]> git.lizzy.rs Git - rust.git/blob - src/etc/lldb_providers.py
Rollup merge of #98441 - calebzulawski:simd_as, r=oli-obk
[rust.git] / src / etc / lldb_providers.py
1 import sys
2
3 from lldb import SBValue, SBData, SBError, eBasicTypeLong, eBasicTypeUnsignedLong, \
4     eBasicTypeUnsignedChar
5
6 # from lldb.formatters import Logger
7
8 ####################################################################################################
9 # This file contains two kinds of pretty-printers: summary and synthetic.
10 #
11 # Important classes from LLDB module:
12 #   SBValue: the value of a variable, a register, or an expression
13 #   SBType:  the data type; each SBValue has a corresponding SBType
14 #
15 # Summary provider is a function with the type `(SBValue, dict) -> str`.
16 #   The first parameter is the object encapsulating the actual variable being displayed;
17 #   The second parameter is an internal support parameter used by LLDB, and you should not touch it.
18 #
19 # Synthetic children is the way to provide a children-based representation of the object's value.
20 # Synthetic provider is a class that implements the following interface:
21 #
22 #     class SyntheticChildrenProvider:
23 #         def __init__(self, SBValue, dict)
24 #         def num_children(self)
25 #         def get_child_index(self, str)
26 #         def get_child_at_index(self, int)
27 #         def update(self)
28 #         def has_children(self)
29 #         def get_value(self)
30 #
31 #
32 # You can find more information and examples here:
33 #   1. https://lldb.llvm.org/varformats.html
34 #   2. https://lldb.llvm.org/python-reference.html
35 #   3. https://lldb.llvm.org/python_reference/lldb.formatters.cpp.libcxx-pysrc.html
36 #   4. https://github.com/llvm-mirror/lldb/tree/master/examples/summaries/cocoa
37 ####################################################################################################
38
39 PY3 = sys.version_info[0] == 3
40
41
42 class ValueBuilder:
43     def __init__(self, valobj):
44         # type: (SBValue) -> ValueBuilder
45         self.valobj = valobj
46         process = valobj.GetProcess()
47         self.endianness = process.GetByteOrder()
48         self.pointer_size = process.GetAddressByteSize()
49
50     def from_int(self, name, value):
51         # type: (str, int) -> SBValue
52         type = self.valobj.GetType().GetBasicType(eBasicTypeLong)
53         data = SBData.CreateDataFromSInt64Array(self.endianness, self.pointer_size, [value])
54         return self.valobj.CreateValueFromData(name, data, type)
55
56     def from_uint(self, name, value):
57         # type: (str, int) -> SBValue
58         type = self.valobj.GetType().GetBasicType(eBasicTypeUnsignedLong)
59         data = SBData.CreateDataFromUInt64Array(self.endianness, self.pointer_size, [value])
60         return self.valobj.CreateValueFromData(name, data, type)
61
62
63 def unwrap_unique_or_non_null(unique_or_nonnull):
64     # BACKCOMPAT: rust 1.32
65     # https://github.com/rust-lang/rust/commit/7a0911528058e87d22ea305695f4047572c5e067
66     # BACKCOMPAT: rust 1.60
67     # https://github.com/rust-lang/rust/commit/2a91eeac1a2d27dd3de1bf55515d765da20fd86f
68     ptr = unique_or_nonnull.GetChildMemberWithName("pointer")
69     return ptr if ptr.TypeIsPointerType() else ptr.GetChildAtIndex(0)
70
71
72 class DefaultSynthteticProvider:
73     def __init__(self, valobj, dict):
74         # type: (SBValue, dict) -> DefaultSynthteticProvider
75         # logger = Logger.Logger()
76         # logger >> "Default synthetic provider for " + str(valobj.GetName())
77         self.valobj = valobj
78
79     def num_children(self):
80         # type: () -> int
81         return self.valobj.GetNumChildren()
82
83     def get_child_index(self, name):
84         # type: (str) -> int
85         return self.valobj.GetIndexOfChildWithName(name)
86
87     def get_child_at_index(self, index):
88         # type: (int) -> SBValue
89         return self.valobj.GetChildAtIndex(index)
90
91     def update(self):
92         # type: () -> None
93         pass
94
95     def has_children(self):
96         # type: () -> bool
97         return self.valobj.MightHaveChildren()
98
99
100 class EmptySyntheticProvider:
101     def __init__(self, valobj, dict):
102         # type: (SBValue, dict) -> EmptySyntheticProvider
103         # logger = Logger.Logger()
104         # logger >> "[EmptySyntheticProvider] for " + str(valobj.GetName())
105         self.valobj = valobj
106
107     def num_children(self):
108         # type: () -> int
109         return 0
110
111     def get_child_index(self, name):
112         # type: (str) -> int
113         return None
114
115     def get_child_at_index(self, index):
116         # type: (int) -> SBValue
117         return None
118
119     def update(self):
120         # type: () -> None
121         pass
122
123     def has_children(self):
124         # type: () -> bool
125         return False
126
127
128 def SizeSummaryProvider(valobj, dict):
129     # type: (SBValue, dict) -> str
130     return 'size=' + str(valobj.GetNumChildren())
131
132
133 def vec_to_string(vec):
134     length = vec.GetNumChildren()
135     chars = [vec.GetChildAtIndex(i).GetValueAsUnsigned() for i in range(length)]
136     return bytes(chars).decode(errors='replace') if PY3 else "".join(chr(char) for char in chars)
137
138
139 def StdStringSummaryProvider(valobj, dict):
140     # type: (SBValue, dict) -> str
141     # logger = Logger.Logger()
142     # logger >> "[StdStringSummaryProvider] for " + str(valobj.GetName())
143     vec = valobj.GetChildAtIndex(0)
144     return '"%s"' % vec_to_string(vec)
145
146
147 def StdOsStringSummaryProvider(valobj, dict):
148     # type: (SBValue, dict) -> str
149     # logger = Logger.Logger()
150     # logger >> "[StdOsStringSummaryProvider] for " + str(valobj.GetName())
151     buf = valobj.GetChildAtIndex(0).GetChildAtIndex(0)
152     is_windows = "Wtf8Buf" in buf.type.name
153     vec = buf.GetChildAtIndex(0) if is_windows else buf
154     return '"%s"' % vec_to_string(vec)
155
156
157 def StdStrSummaryProvider(valobj, dict):
158     # type: (SBValue, dict) -> str
159     # logger = Logger.Logger()
160     # logger >> "[StdStrSummaryProvider] for " + str(valobj.GetName())
161
162     length = valobj.GetChildMemberWithName("length").GetValueAsUnsigned()
163     if length == 0:
164         return '""'
165
166     data_ptr = valobj.GetChildMemberWithName("data_ptr")
167
168     start = data_ptr.GetValueAsUnsigned()
169     error = SBError()
170     process = data_ptr.GetProcess()
171     data = process.ReadMemory(start, length, error)
172     data = data.decode(encoding='UTF-8') if PY3 else data
173     return '"%s"' % data
174
175
176 class StructSyntheticProvider:
177     """Pretty-printer for structs and struct enum variants"""
178
179     def __init__(self, valobj, dict, is_variant=False):
180         # type: (SBValue, dict, bool) -> StructSyntheticProvider
181         # logger = Logger.Logger()
182         self.valobj = valobj
183         self.is_variant = is_variant
184         self.type = valobj.GetType()
185         self.fields = {}
186
187         if is_variant:
188             self.fields_count = self.type.GetNumberOfFields() - 1
189             real_fields = self.type.fields[1:]
190         else:
191             self.fields_count = self.type.GetNumberOfFields()
192             real_fields = self.type.fields
193
194         for number, field in enumerate(real_fields):
195             self.fields[field.name] = number
196
197     def num_children(self):
198         # type: () -> int
199         return self.fields_count
200
201     def get_child_index(self, name):
202         # type: (str) -> int
203         return self.fields.get(name, -1)
204
205     def get_child_at_index(self, index):
206         # type: (int) -> SBValue
207         if self.is_variant:
208             field = self.type.GetFieldAtIndex(index + 1)
209         else:
210             field = self.type.GetFieldAtIndex(index)
211         return self.valobj.GetChildMemberWithName(field.name)
212
213     def update(self):
214         # type: () -> None
215         pass
216
217     def has_children(self):
218         # type: () -> bool
219         return True
220
221
222 class TupleSyntheticProvider:
223     """Pretty-printer for tuples and tuple enum variants"""
224
225     def __init__(self, valobj, dict, is_variant=False):
226         # type: (SBValue, dict, bool) -> TupleSyntheticProvider
227         # logger = Logger.Logger()
228         self.valobj = valobj
229         self.is_variant = is_variant
230         self.type = valobj.GetType()
231
232         if is_variant:
233             self.size = self.type.GetNumberOfFields() - 1
234         else:
235             self.size = self.type.GetNumberOfFields()
236
237     def num_children(self):
238         # type: () -> int
239         return self.size
240
241     def get_child_index(self, name):
242         # type: (str) -> int
243         if name.isdigit():
244             return int(name)
245         else:
246             return -1
247
248     def get_child_at_index(self, index):
249         # type: (int) -> SBValue
250         if self.is_variant:
251             field = self.type.GetFieldAtIndex(index + 1)
252         else:
253             field = self.type.GetFieldAtIndex(index)
254         element = self.valobj.GetChildMemberWithName(field.name)
255         return self.valobj.CreateValueFromData(str(index), element.GetData(), element.GetType())
256
257     def update(self):
258         # type: () -> None
259         pass
260
261     def has_children(self):
262         # type: () -> bool
263         return True
264
265
266 class StdVecSyntheticProvider:
267     """Pretty-printer for alloc::vec::Vec<T>
268
269     struct Vec<T> { buf: RawVec<T>, len: usize }
270     struct RawVec<T> { ptr: Unique<T>, cap: usize, ... }
271     rust 1.31.1: struct Unique<T: ?Sized> { pointer: NonZero<*const T>, ... }
272     rust 1.33.0: struct Unique<T: ?Sized> { pointer: *const T, ... }
273     rust 1.62.0: struct Unique<T: ?Sized> { pointer: NonNull<T>, ... }
274     struct NonZero<T>(T)
275     struct NonNull<T> { pointer: *const T }
276     """
277
278     def __init__(self, valobj, dict):
279         # type: (SBValue, dict) -> StdVecSyntheticProvider
280         # logger = Logger.Logger()
281         # logger >> "[StdVecSyntheticProvider] for " + str(valobj.GetName())
282         self.valobj = valobj
283         self.update()
284
285     def num_children(self):
286         # type: () -> int
287         return self.length
288
289     def get_child_index(self, name):
290         # type: (str) -> int
291         index = name.lstrip('[').rstrip(']')
292         if index.isdigit():
293             return int(index)
294         else:
295             return -1
296
297     def get_child_at_index(self, index):
298         # type: (int) -> SBValue
299         start = self.data_ptr.GetValueAsUnsigned()
300         address = start + index * self.element_type_size
301         element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.element_type)
302         return element
303
304     def update(self):
305         # type: () -> None
306         self.length = self.valobj.GetChildMemberWithName("len").GetValueAsUnsigned()
307         self.buf = self.valobj.GetChildMemberWithName("buf")
308
309         self.data_ptr = unwrap_unique_or_non_null(self.buf.GetChildMemberWithName("ptr"))
310
311         self.element_type = self.data_ptr.GetType().GetPointeeType()
312         self.element_type_size = self.element_type.GetByteSize()
313
314     def has_children(self):
315         # type: () -> bool
316         return True
317
318
319 class StdSliceSyntheticProvider:
320     def __init__(self, valobj, dict):
321         self.valobj = valobj
322         self.update()
323
324     def num_children(self):
325         # type: () -> int
326         return self.length
327
328     def get_child_index(self, name):
329         # type: (str) -> int
330         index = name.lstrip('[').rstrip(']')
331         if index.isdigit():
332             return int(index)
333         else:
334             return -1
335
336     def get_child_at_index(self, index):
337         # type: (int) -> SBValue
338         start = self.data_ptr.GetValueAsUnsigned()
339         address = start + index * self.element_type_size
340         element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.element_type)
341         return element
342
343     def update(self):
344         # type: () -> None
345         self.length = self.valobj.GetChildMemberWithName("length").GetValueAsUnsigned()
346         self.data_ptr = self.valobj.GetChildMemberWithName("data_ptr")
347
348         self.element_type = self.data_ptr.GetType().GetPointeeType()
349         self.element_type_size = self.element_type.GetByteSize()
350
351     def has_children(self):
352         # type: () -> bool
353         return True
354
355
356 class StdVecDequeSyntheticProvider:
357     """Pretty-printer for alloc::collections::vec_deque::VecDeque<T>
358
359     struct VecDeque<T> { tail: usize, head: usize, buf: RawVec<T> }
360     """
361
362     def __init__(self, valobj, dict):
363         # type: (SBValue, dict) -> StdVecDequeSyntheticProvider
364         # logger = Logger.Logger()
365         # logger >> "[StdVecDequeSyntheticProvider] for " + str(valobj.GetName())
366         self.valobj = valobj
367         self.update()
368
369     def num_children(self):
370         # type: () -> int
371         return self.size
372
373     def get_child_index(self, name):
374         # type: (str) -> int
375         index = name.lstrip('[').rstrip(']')
376         if index.isdigit() and self.tail <= index and (self.tail + index) % self.cap < self.head:
377             return int(index)
378         else:
379             return -1
380
381     def get_child_at_index(self, index):
382         # type: (int) -> SBValue
383         start = self.data_ptr.GetValueAsUnsigned()
384         address = start + ((index + self.tail) % self.cap) * self.element_type_size
385         element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.element_type)
386         return element
387
388     def update(self):
389         # type: () -> None
390         self.head = self.valobj.GetChildMemberWithName("head").GetValueAsUnsigned()
391         self.tail = self.valobj.GetChildMemberWithName("tail").GetValueAsUnsigned()
392         self.buf = self.valobj.GetChildMemberWithName("buf")
393         self.cap = self.buf.GetChildMemberWithName("cap").GetValueAsUnsigned()
394         if self.head >= self.tail:
395             self.size = self.head - self.tail
396         else:
397             self.size = self.cap + self.head - self.tail
398
399         self.data_ptr = unwrap_unique_or_non_null(self.buf.GetChildMemberWithName("ptr"))
400
401         self.element_type = self.data_ptr.GetType().GetPointeeType()
402         self.element_type_size = self.element_type.GetByteSize()
403
404     def has_children(self):
405         # type: () -> bool
406         return True
407
408
409 # BACKCOMPAT: rust 1.35
410 class StdOldHashMapSyntheticProvider:
411     """Pretty-printer for std::collections::hash::map::HashMap<K, V, S>
412
413     struct HashMap<K, V, S> {..., table: RawTable<K, V>, ... }
414     struct RawTable<K, V> { capacity_mask: usize, size: usize, hashes: TaggedHashUintPtr, ... }
415     """
416
417     def __init__(self, valobj, dict, show_values=True):
418         # type: (SBValue, dict, bool) -> StdOldHashMapSyntheticProvider
419         self.valobj = valobj
420         self.show_values = show_values
421         self.update()
422
423     def num_children(self):
424         # type: () -> int
425         return self.size
426
427     def get_child_index(self, name):
428         # type: (str) -> int
429         index = name.lstrip('[').rstrip(']')
430         if index.isdigit():
431             return int(index)
432         else:
433             return -1
434
435     def get_child_at_index(self, index):
436         # type: (int) -> SBValue
437         # logger = Logger.Logger()
438         start = self.data_ptr.GetValueAsUnsigned() & ~1
439
440         # See `libstd/collections/hash/table.rs:raw_bucket_at
441         hashes = self.hash_uint_size * self.capacity
442         align = self.pair_type_size
443         # See `libcore/alloc.rs:padding_needed_for`
444         len_rounded_up = (((((hashes + align) % self.modulo - 1) % self.modulo) & ~(
445                 (align - 1) % self.modulo)) % self.modulo - hashes) % self.modulo
446         # len_rounded_up = ((hashes + align - 1) & ~(align - 1)) - hashes
447
448         pairs_offset = hashes + len_rounded_up
449         pairs_start = start + pairs_offset
450
451         table_index = self.valid_indices[index]
452         idx = table_index & self.capacity_mask
453         address = pairs_start + idx * self.pair_type_size
454         element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.pair_type)
455         if self.show_values:
456             return element
457         else:
458             key = element.GetChildAtIndex(0)
459             return self.valobj.CreateValueFromData("[%s]" % index, key.GetData(), key.GetType())
460
461     def update(self):
462         # type: () -> None
463         # logger = Logger.Logger()
464
465         self.table = self.valobj.GetChildMemberWithName("table")  # type: SBValue
466         self.size = self.table.GetChildMemberWithName("size").GetValueAsUnsigned()
467         self.hashes = self.table.GetChildMemberWithName("hashes")
468         self.hash_uint_type = self.hashes.GetType()
469         self.hash_uint_size = self.hashes.GetType().GetByteSize()
470         self.modulo = 2 ** self.hash_uint_size
471         self.data_ptr = self.hashes.GetChildAtIndex(0).GetChildAtIndex(0)
472
473         self.capacity_mask = self.table.GetChildMemberWithName("capacity_mask").GetValueAsUnsigned()
474         self.capacity = (self.capacity_mask + 1) % self.modulo
475
476         marker = self.table.GetChildMemberWithName("marker").GetType()  # type: SBType
477         self.pair_type = marker.template_args[0]
478         self.pair_type_size = self.pair_type.GetByteSize()
479
480         self.valid_indices = []
481         for idx in range(self.capacity):
482             address = self.data_ptr.GetValueAsUnsigned() + idx * self.hash_uint_size
483             hash_uint = self.data_ptr.CreateValueFromAddress("[%s]" % idx, address,
484                                                              self.hash_uint_type)
485             hash_ptr = hash_uint.GetChildAtIndex(0).GetChildAtIndex(0)
486             if hash_ptr.GetValueAsUnsigned() != 0:
487                 self.valid_indices.append(idx)
488
489         # logger >> "Valid indices: {}".format(str(self.valid_indices))
490
491     def has_children(self):
492         # type: () -> bool
493         return True
494
495
496 class StdHashMapSyntheticProvider:
497     """Pretty-printer for hashbrown's HashMap"""
498
499     def __init__(self, valobj, dict, show_values=True):
500         # type: (SBValue, dict, bool) -> StdHashMapSyntheticProvider
501         self.valobj = valobj
502         self.show_values = show_values
503         self.update()
504
505     def num_children(self):
506         # type: () -> int
507         return self.size
508
509     def get_child_index(self, name):
510         # type: (str) -> int
511         index = name.lstrip('[').rstrip(']')
512         if index.isdigit():
513             return int(index)
514         else:
515             return -1
516
517     def get_child_at_index(self, index):
518         # type: (int) -> SBValue
519         pairs_start = self.data_ptr.GetValueAsUnsigned()
520         idx = self.valid_indices[index]
521         if self.new_layout:
522             idx = -(idx + 1)
523         address = pairs_start + idx * self.pair_type_size
524         element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.pair_type)
525         if self.show_values:
526             return element
527         else:
528             key = element.GetChildAtIndex(0)
529             return self.valobj.CreateValueFromData("[%s]" % index, key.GetData(), key.GetType())
530
531     def update(self):
532         # type: () -> None
533         table = self.table()
534         inner_table = table.GetChildMemberWithName("table")
535
536         capacity = inner_table.GetChildMemberWithName("bucket_mask").GetValueAsUnsigned() + 1
537         ctrl = inner_table.GetChildMemberWithName("ctrl").GetChildAtIndex(0)
538
539         self.size = inner_table.GetChildMemberWithName("items").GetValueAsUnsigned()
540         self.pair_type = table.type.template_args[0]
541         if self.pair_type.IsTypedefType():
542             self.pair_type = self.pair_type.GetTypedefedType()
543         self.pair_type_size = self.pair_type.GetByteSize()
544
545         self.new_layout = not inner_table.GetChildMemberWithName("data").IsValid()
546         if self.new_layout:
547             self.data_ptr = ctrl.Cast(self.pair_type.GetPointerType())
548         else:
549             self.data_ptr = inner_table.GetChildMemberWithName("data").GetChildAtIndex(0)
550
551         u8_type = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar)
552         u8_type_size = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar).GetByteSize()
553
554         self.valid_indices = []
555         for idx in range(capacity):
556             address = ctrl.GetValueAsUnsigned() + idx * u8_type_size
557             value = ctrl.CreateValueFromAddress("ctrl[%s]" % idx, address,
558                                                 u8_type).GetValueAsUnsigned()
559             is_present = value & 128 == 0
560             if is_present:
561                 self.valid_indices.append(idx)
562
563     def table(self):
564         # type: () -> SBValue
565         if self.show_values:
566             hashbrown_hashmap = self.valobj.GetChildMemberWithName("base")
567         else:
568             # BACKCOMPAT: rust 1.47
569             # HashSet wraps either std HashMap or hashbrown::HashSet, which both
570             # wrap hashbrown::HashMap, so either way we "unwrap" twice.
571             hashbrown_hashmap = self.valobj.GetChildAtIndex(0).GetChildAtIndex(0)
572         return hashbrown_hashmap.GetChildMemberWithName("table")
573
574     def has_children(self):
575         # type: () -> bool
576         return True
577
578
579 def StdRcSummaryProvider(valobj, dict):
580     # type: (SBValue, dict) -> str
581     strong = valobj.GetChildMemberWithName("strong").GetValueAsUnsigned()
582     weak = valobj.GetChildMemberWithName("weak").GetValueAsUnsigned()
583     return "strong={}, weak={}".format(strong, weak)
584
585
586 class StdRcSyntheticProvider:
587     """Pretty-printer for alloc::rc::Rc<T> and alloc::sync::Arc<T>
588
589     struct Rc<T> { ptr: NonNull<RcBox<T>>, ... }
590     rust 1.31.1: struct NonNull<T> { pointer: NonZero<*const T> }
591     rust 1.33.0: struct NonNull<T> { pointer: *const T }
592     struct NonZero<T>(T)
593     struct RcBox<T> { strong: Cell<usize>, weak: Cell<usize>, value: T }
594     struct Cell<T> { value: UnsafeCell<T> }
595     struct UnsafeCell<T> { value: T }
596
597     struct Arc<T> { ptr: NonNull<ArcInner<T>>, ... }
598     struct ArcInner<T> { strong: atomic::AtomicUsize, weak: atomic::AtomicUsize, data: T }
599     struct AtomicUsize { v: UnsafeCell<usize> }
600     """
601
602     def __init__(self, valobj, dict, is_atomic=False):
603         # type: (SBValue, dict, bool) -> StdRcSyntheticProvider
604         self.valobj = valobj
605
606         self.ptr = unwrap_unique_or_non_null(self.valobj.GetChildMemberWithName("ptr"))
607
608         self.value = self.ptr.GetChildMemberWithName("data" if is_atomic else "value")
609
610         self.strong = self.ptr.GetChildMemberWithName("strong").GetChildAtIndex(
611             0).GetChildMemberWithName("value")
612         self.weak = self.ptr.GetChildMemberWithName("weak").GetChildAtIndex(
613             0).GetChildMemberWithName("value")
614
615         self.value_builder = ValueBuilder(valobj)
616
617         self.update()
618
619     def num_children(self):
620         # type: () -> int
621         # Actually there are 3 children, but only the `value` should be shown as a child
622         return 1
623
624     def get_child_index(self, name):
625         # type: (str) -> int
626         if name == "value":
627             return 0
628         if name == "strong":
629             return 1
630         if name == "weak":
631             return 2
632         return -1
633
634     def get_child_at_index(self, index):
635         # type: (int) -> SBValue
636         if index == 0:
637             return self.value
638         if index == 1:
639             return self.value_builder.from_uint("strong", self.strong_count)
640         if index == 2:
641             return self.value_builder.from_uint("weak", self.weak_count)
642
643         return None
644
645     def update(self):
646         # type: () -> None
647         self.strong_count = self.strong.GetValueAsUnsigned()
648         self.weak_count = self.weak.GetValueAsUnsigned() - 1
649
650     def has_children(self):
651         # type: () -> bool
652         return True
653
654
655 class StdCellSyntheticProvider:
656     """Pretty-printer for std::cell::Cell"""
657
658     def __init__(self, valobj, dict):
659         # type: (SBValue, dict) -> StdCellSyntheticProvider
660         self.valobj = valobj
661         self.value = valobj.GetChildMemberWithName("value").GetChildAtIndex(0)
662
663     def num_children(self):
664         # type: () -> int
665         return 1
666
667     def get_child_index(self, name):
668         # type: (str) -> int
669         if name == "value":
670             return 0
671         return -1
672
673     def get_child_at_index(self, index):
674         # type: (int) -> SBValue
675         if index == 0:
676             return self.value
677         return None
678
679     def update(self):
680         # type: () -> None
681         pass
682
683     def has_children(self):
684         # type: () -> bool
685         return True
686
687
688 def StdRefSummaryProvider(valobj, dict):
689     # type: (SBValue, dict) -> str
690     borrow = valobj.GetChildMemberWithName("borrow").GetValueAsSigned()
691     return "borrow={}".format(borrow) if borrow >= 0 else "borrow_mut={}".format(-borrow)
692
693
694 class StdRefSyntheticProvider:
695     """Pretty-printer for std::cell::Ref, std::cell::RefMut, and std::cell::RefCell"""
696
697     def __init__(self, valobj, dict, is_cell=False):
698         # type: (SBValue, dict, bool) -> StdRefSyntheticProvider
699         self.valobj = valobj
700
701         borrow = valobj.GetChildMemberWithName("borrow")
702         value = valobj.GetChildMemberWithName("value")
703         if is_cell:
704             self.borrow = borrow.GetChildMemberWithName("value").GetChildMemberWithName("value")
705             self.value = value.GetChildMemberWithName("value")
706         else:
707             self.borrow = borrow.GetChildMemberWithName("borrow").GetChildMemberWithName(
708                 "value").GetChildMemberWithName("value")
709             self.value = value.Dereference()
710
711         self.value_builder = ValueBuilder(valobj)
712
713         self.update()
714
715     def num_children(self):
716         # type: () -> int
717         # Actually there are 2 children, but only the `value` should be shown as a child
718         return 1
719
720     def get_child_index(self, name):
721         if name == "value":
722             return 0
723         if name == "borrow":
724             return 1
725         return -1
726
727     def get_child_at_index(self, index):
728         # type: (int) -> SBValue
729         if index == 0:
730             return self.value
731         if index == 1:
732             return self.value_builder.from_int("borrow", self.borrow_count)
733         return None
734
735     def update(self):
736         # type: () -> None
737         self.borrow_count = self.borrow.GetValueAsSigned()
738
739     def has_children(self):
740         # type: () -> bool
741         return True
742
743
744 def StdNonZeroNumberSummaryProvider(valobj, _dict):
745     # type: (SBValue, dict) -> str
746     objtype = valobj.GetType()
747     field = objtype.GetFieldAtIndex(0)
748     element = valobj.GetChildMemberWithName(field.name)
749     return element.GetValue()