@@ -1151,6 +1151,130 @@ def has_children(self) -> bool:
11511151 return True
11521152
11531153
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+
11541278def StdRcSummaryProvider (valobj : SBValue , _dict : LLDBOpaque ) -> str :
11551279 strong = valobj .GetChildMemberWithName ("strong" ).GetValueAsUnsigned ()
11561280 weak = valobj .GetChildMemberWithName ("weak" ).GetValueAsUnsigned ()
0 commit comments