@@ -1151,6 +1151,130 @@ def has_children(self) -> bool:
1151
1151
return True
1152
1152
1153
1153
1154
+ def children_of_node (node_ptr : SBValue , height : int ):
1155
+ def get_edges (node : SBValue ) -> SBValue :
1156
+ # BTreeMap implementation does ad-hoc polymorphism between LeafNode and InternalNode
1157
+ # with raw pointers.
1158
+ # https://github.com/rust-lang/rust/issues/90520#issuecomment-2211103129
1159
+ # Implementing this the same way as the GDB provider with type casting fails
1160
+ # because LLDB does not find the target type for some reason.
1161
+ # Therefore, we manually do the pointer arithmetic to get the edges array
1162
+ # and handle it as raw pointers later instead of MaybeUninit<NonNull<LeafNode<K,V>>>.
1163
+ # We can do that because InternalNode is repr(C).
1164
+ leaf_ptr_type = node .GetType ()
1165
+ # Array has a constant length of 2 * B
1166
+ edges_arr_type = leaf_ptr_type .GetArrayType (12 )
1167
+ node_addr = node .unsigned
1168
+ leaf_size = leaf_ptr_type .GetPointeeType ().size
1169
+ edges_addr = node_addr + leaf_size
1170
+ return node .CreateValueFromAddress ("edges" , edges_addr , edges_arr_type )
1171
+
1172
+ def unwrap_item_from_array_of_maybe_uninit (arr : SBValue , index : int ) -> SBValue :
1173
+ element = arr .GetChildAtIndex (index )
1174
+ return element .GetChildMemberWithName ("value" ).GetChildMemberWithName ("value" )
1175
+
1176
+ if node_ptr .type .name .startswith ("alloc::collections::btree::node::BoxedNode<" ):
1177
+ # BACKCOMPAT: rust 1.49
1178
+ node_ptr = node_ptr .GetChildMemberWithName ("ptr" )
1179
+
1180
+ if not node_ptr .type .IsPointerType ():
1181
+ # After the first recursion, this method is called with a raw pointer type directly
1182
+ # instead of NonNull<T>
1183
+ node_ptr = unwrap_unique_or_non_null (node_ptr )
1184
+
1185
+ leaf = node_ptr .Dereference ()
1186
+ keys = leaf .GetChildMemberWithName ("keys" )
1187
+ vals = leaf .GetChildMemberWithName ("vals" )
1188
+ length = leaf .GetChildMemberWithName ("len" ).unsigned
1189
+ edges = get_edges (node_ptr ) if height > 0 else None
1190
+
1191
+ for i in range (length + 1 ):
1192
+ if height > 0 :
1193
+ child_ptr = edges .GetChildAtIndex (i )
1194
+ yield from children_of_node (child_ptr , height - 1 )
1195
+ if i < length :
1196
+ # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays.
1197
+ key_type_size = keys .type .size
1198
+ val_type_size = vals .type .size
1199
+ key = (
1200
+ unwrap_item_from_array_of_maybe_uninit (keys , i )
1201
+ if key_type_size > 0
1202
+ else node_ptr .EvaluateExpression ("()" )
1203
+ )
1204
+ val = (
1205
+ unwrap_item_from_array_of_maybe_uninit (vals , i )
1206
+ if val_type_size > 0
1207
+ else node_ptr .EvaluateExpression ("()" )
1208
+ )
1209
+ yield key , val
1210
+
1211
+
1212
+ class StdBTreeMapSyntheticProvider :
1213
+ def __init__ (self , valobj : SBValue , _dict : LLDBOpaque , show_values : bool = True ):
1214
+ self .valobj = valobj
1215
+ self ._dict = _dict
1216
+ self .show_values = show_values
1217
+
1218
+ def num_children (self ) -> int :
1219
+ return self .size
1220
+
1221
+ def get_child_index (self , name : str ) -> int :
1222
+ index = name .lstrip ("[" ).rstrip ("]" )
1223
+ if index .isdigit ():
1224
+ return int (index )
1225
+ else :
1226
+ return - 1
1227
+
1228
+ def get_child_at_index (self , index : int ) -> SBValue :
1229
+ key , value = self .items [index ]
1230
+ if self .show_values :
1231
+ data = key .GetData ()
1232
+ assert data .Append (value .GetData ()), "Failed to create key value pair"
1233
+ return self .valobj .CreateValueFromData ("[%s]" % index , data , self .pair_type )
1234
+ return self .valobj .CreateValueFromData ("[%s]" % index , key .GetData (), key .type )
1235
+
1236
+ def update (self ) -> bool :
1237
+ self .size = self .valobj .GetChildMemberWithName ("length" ).unsigned
1238
+ self .items = []
1239
+
1240
+ # Determine the type for the tuple (Key, Value)
1241
+ # - get_template_args helper breaks on console because type is shown as
1242
+ # `core::marker::PhantomData<(&str, &str) *>`
1243
+ # - Type lookup after get_template_args helper fails with codelldb for unclear reasons
1244
+ # - Native `template_args[0]` from LLDB fails with codelldb and just says `T` if printed
1245
+ # on console
1246
+ marker = self .valobj .GetChildMemberWithName ("_marker" )
1247
+ marker_type = marker .GetType ()
1248
+ box = marker_type .GetTemplateArgumentType (0 )
1249
+ self .pair_type = box .GetPointeeType ()
1250
+
1251
+ if self .size == 0 :
1252
+ return
1253
+
1254
+ root = self .valobj .GetChildMemberWithName ("root" )
1255
+
1256
+ if root .type .name .startswith ("core::option::Option<" ):
1257
+ synthetic_children = root .children [0 ]
1258
+ current_variant = synthetic_children .GetChildMemberWithName ("$variant$" )
1259
+ root = current_variant .GetChildMemberWithName (
1260
+ "value"
1261
+ ).GetChildMemberWithName ("__0" )
1262
+
1263
+ height = root .GetChildMemberWithName ("height" )
1264
+ node_ptr = root .GetChildMemberWithName ("node" )
1265
+
1266
+ self .items = [
1267
+ (key , value ) for key , value in children_of_node (node_ptr , height .unsigned )
1268
+ ]
1269
+
1270
+ assert len (self .items ) == self .size
1271
+
1272
+ return False
1273
+
1274
+ def has_children (self ) -> bool :
1275
+ return True
1276
+
1277
+
1154
1278
def StdRcSummaryProvider (valobj : SBValue , _dict : LLDBOpaque ) -> str :
1155
1279
strong = valobj .GetChildMemberWithName ("strong" ).GetValueAsUnsigned ()
1156
1280
weak = valobj .GetChildMemberWithName ("weak" ).GetValueAsUnsigned ()
0 commit comments