• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import sys
2
3from lldb import 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/use/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
39PY3 = sys.version_info[0] == 3
40
41
42class 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
63def 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
72class DefaultSyntheticProvider:
73    def __init__(self, valobj, dict):
74        # type: (SBValue, dict) -> DefaultSyntheticProvider
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
100class 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
128def SizeSummaryProvider(valobj, dict):
129    # type: (SBValue, dict) -> str
130    return 'size=' + str(valobj.GetNumChildren())
131
132
133def 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
139def 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
147def 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
157def 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
176class 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
222class 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
266class 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
319class 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
356class StdVecDequeSyntheticProvider:
357    """Pretty-printer for alloc::collections::vec_deque::VecDeque<T>
358
359    struct VecDeque<T> { head: usize, len: 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 int(index) < self.size:
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.head) % 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.size = self.valobj.GetChildMemberWithName("len").GetValueAsUnsigned()
392        self.buf = self.valobj.GetChildMemberWithName("buf")
393        self.cap = self.buf.GetChildMemberWithName("cap").GetValueAsUnsigned()
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
406class 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
492class 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
575def 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
582class 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
651class 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
684def 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
690class 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
738
739
740def StdNonZeroNumberSummaryProvider(valobj, _dict):
741    # type: (SBValue, dict) -> str
742    objtype = valobj.GetType()
743    field = objtype.GetFieldAtIndex(0)
744    element = valobj.GetChildMemberWithName(field.name)
745    return element.GetValue()
746