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