@@ -1151,6 +1151,129 @@ def has_children(self) -> bool:
11511151 return True
11521152
11531153
1154+ def children_of_node (node_ptr : SBValue , height : int ):
1155+ def cast_to_internal (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+ internal_type_name = node .type .GetPointeeType ().name .replace (
1160+ "LeafNode" , "InternalNode" , 1
1161+ )
1162+ target = node .GetTarget ()
1163+ internal_type = target .FindFirstType (internal_type_name )
1164+ return node .Cast (internal_type .GetPointerType ())
1165+
1166+ def unwrap_item_from_array_of_maybe_uninit (arr : SBValue , index : int ) -> SBValue :
1167+ element = arr .GetChildAtIndex (index )
1168+ return element .GetChildMemberWithName ("value" ).GetChildMemberWithName ("value" )
1169+
1170+ if node_ptr .type .name .startswith ("alloc::collections::btree::node::BoxedNode<" ):
1171+ # BACKCOMPAT: rust 1.49
1172+ node_ptr = node_ptr .GetChildMemberWithName ("ptr" )
1173+ node_ptr = unwrap_unique_or_non_null (node_ptr )
1174+ leaf = node_ptr .Dereference ()
1175+ keys = leaf .GetChildMemberWithName ("keys" )
1176+ vals = leaf .GetChildMemberWithName ("vals" )
1177+ length = leaf .GetChildMemberWithName ("len" ).unsigned
1178+ edges = (
1179+ cast_to_internal (node_ptr ).GetChildMemberWithName ("edges" )
1180+ if height > 0
1181+ else None
1182+ )
1183+
1184+ for i in range (length + 1 ):
1185+ if height > 0 :
1186+ child_ptr = unwrap_item_from_array_of_maybe_uninit (edges , i )
1187+ yield from children_of_node (child_ptr , height - 1 )
1188+ if i < length :
1189+ # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays.
1190+ key_type_size = keys .type .size
1191+ val_type_size = vals .type .size
1192+ key = (
1193+ unwrap_item_from_array_of_maybe_uninit (keys , i )
1194+ if key_type_size > 0
1195+ else node_ptr .EvaluateExpression ("()" )
1196+ )
1197+ val = (
1198+ unwrap_item_from_array_of_maybe_uninit (vals , i )
1199+ if val_type_size > 0
1200+ else node_ptr .EvaluateExpression ("()" )
1201+ )
1202+ yield key , val
1203+
1204+
1205+ def strip_till_parentheses (text : str ) -> str :
1206+ start = text .find ("(" )
1207+ end = text .find (")" )
1208+ if start == - 1 or end == - 1 :
1209+ return text
1210+ return text [start : end + 1 ]
1211+
1212+
1213+ class StdBTreeMapSyntheticProvider :
1214+ def __init__ (self , valobj : SBValue , _dict : LLDBOpaque , show_values : bool = True ):
1215+ self .valobj = valobj
1216+ self ._dict = _dict
1217+ self .show_values = True
1218+
1219+ def num_children (self ) -> int :
1220+ return self .size
1221+
1222+ def get_child_index (self , name : str ) -> int :
1223+ index = name .lstrip ("[" ).rstrip ("]" )
1224+ if index .isdigit ():
1225+ return int (index )
1226+ else :
1227+ return - 1
1228+
1229+ def get_child_at_index (self , index : int ) -> SBValue :
1230+ key , value = self .items [index ]
1231+ if self .show_values :
1232+ data = key .GetData ()
1233+ assert data .Append (value .GetData ()), "Failed to create key value pair"
1234+ return self .valobj .CreateValueFromData ("[%s]" % index , data , self .pair_type )
1235+ return self .valobj .CreateValueFromData ("[%s]" % index , key .GetData (), key .type )
1236+
1237+ def update (self ) -> bool :
1238+ self .size = self .valobj .GetChildMemberWithName ("length" ).unsigned
1239+ self .items = []
1240+
1241+ # Determine the type for the tuple (Key, Value)
1242+ # - get_template_args helper breaks on console because type is shown as
1243+ # `core::marker::PhantomData<(&str, &str) *>`
1244+ # - Type lookup after get_template_args helper fails with codelldb for unclear reasons
1245+ # - Native `template_args[0]` from LLDB fails with codelldb and just says `T` if printed
1246+ # on console
1247+ marker_type_name = self .valobj .GetChildMemberWithName ("_marker" ).GetTypeName ()
1248+ pair_type_name = strip_till_parentheses (marker_type_name )
1249+ target = self .valobj .GetTarget ()
1250+ self .pair_type = target .FindFirstType (pair_type_name )
1251+
1252+ if self .size == 0 :
1253+ return
1254+
1255+ root = self .valobj .GetChildMemberWithName ("root" )
1256+
1257+ if root .type .name .startswith ("core::option::Option<" ):
1258+ target = self .valobj .GetTarget ()
1259+ type_some = target .FindFirstType (get_template_args (root .GetTypeName ())[0 ])
1260+ root = root .Cast (type_some )
1261+
1262+ height = root .GetChildMemberWithName ("height" )
1263+ node_ptr = root .GetChildMemberWithName ("node" )
1264+
1265+ self .items = [
1266+ (key , value ) for key , value in children_of_node (node_ptr , height .unsigned )
1267+ ]
1268+
1269+ assert len (self .items ) == self .size
1270+
1271+ return False
1272+
1273+ def has_children (self ) -> bool :
1274+ return True
1275+
1276+
11541277def StdRcSummaryProvider (valobj : SBValue , _dict : LLDBOpaque ) -> str :
11551278 strong = valobj .GetChildMemberWithName ("strong" ).GetValueAsUnsigned ()
11561279 weak = valobj .GetChildMemberWithName ("weak" ).GetValueAsUnsigned ()
0 commit comments