@@ -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 = cast_to_internal (node_ptr ).GetChildMemberWithName ("edges" ) if height > 0 else None
1179+
1180+ for i in range (length + 1 ):
1181+ if height > 0 :
1182+ child_ptr = unwrap_item_from_array_of_maybe_uninit (edges , i )
1183+ yield from children_of_node (child_ptr , height - 1 )
1184+ if i < length :
1185+ # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays.
1186+ key_type_size = keys .type .size
1187+ val_type_size = vals .type .size
1188+ key = (
1189+ unwrap_item_from_array_of_maybe_uninit (keys , i )
1190+ if key_type_size > 0
1191+ else node_ptr .EvaluateExpression ("()" )
1192+ )
1193+ val = (
1194+ unwrap_item_from_array_of_maybe_uninit (vals , i )
1195+ if val_type_size > 0
1196+ else node_ptr .EvaluateExpression ("()" )
1197+ )
1198+ yield key , val
1199+
1200+ def strip_till_parentheses (text : str ) -> str :
1201+ start = text .find ('(' )
1202+ end = text .find (')' )
1203+ if start == - 1 or end == - 1 :
1204+ return text
1205+ return text [start : end + 1 ]
1206+
1207+
1208+ class StdBTreeMapSyntheticProvider :
1209+ def __init__ (self , valobj : SBValue , _dict : LLDBOpaque , show_values : bool = True ):
1210+ self .valobj = valobj
1211+ self ._dict = _dict
1212+ self .show_values = True
1213+
1214+ def num_children (self ) -> int :
1215+ return self .size
1216+
1217+ def get_child_index (self , name : str ) -> int :
1218+ index = name .lstrip ("[" ).rstrip ("]" )
1219+ if index .isdigit ():
1220+ return int (index )
1221+ else :
1222+ return - 1
1223+
1224+ def get_child_at_index (self , index : int ) -> SBValue :
1225+ key , value = self .items [index ]
1226+ if self .show_values :
1227+ data = key .GetData ()
1228+ assert data .Append (value .GetData ()), "Failed to create key value pair"
1229+ return self .valobj .CreateValueFromData (
1230+ "[%s]" % index , data , self .pair_type
1231+ )
1232+ return self .valobj .CreateValueFromData (
1233+ "[%s]" % index , key .GetData (), key .type
1234+ )
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_type_name = self .valobj .GetChildMemberWithName ("_marker" ).GetTypeName ()
1247+ pair_type_name = strip_till_parentheses (marker_type_name )
1248+ target = self .valobj .GetTarget ()
1249+ self .pair_type = target .FindFirstType (pair_type_name )
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+ target = self .valobj .GetTarget ()
1258+ type_some = target .FindFirstType (get_template_args (root .GetTypeName ())[0 ])
1259+ root = root .Cast (type_some )
1260+
1261+ height = root .GetChildMemberWithName ("height" )
1262+ node_ptr = root .GetChildMemberWithName ("node" )
1263+
1264+ self .items = [
1265+ (key , value )
1266+ 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