tblgen/
record.rs

1// Original work Copyright 2016 Alexander Stocko <as@coder.gg>.
2// Modified work Copyright 2023 Daan Vanoverloop
3// See the COPYRIGHT file at the top-level directory of this distribution.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11use paste::paste;
12use std::{ffi::c_void, marker::PhantomData};
13
14use crate::raw::{
15    TableGenRecTyKind::TableGenInvalidRecTyKind as RawInvalidRecTyKind, TableGenRecordRef,
16    TableGenRecordValRef, tableGenIntArrayFree, tableGenRecordDump, tableGenRecordGetDefInit,
17    tableGenRecordGetFieldType, tableGenRecordGetFirstValue, tableGenRecordGetID,
18    tableGenRecordGetLoc, tableGenRecordGetName, tableGenRecordGetNameInit,
19    tableGenRecordGetNumSuperClasses, tableGenRecordGetNumTemplateArgs,
20    tableGenRecordGetSuperClass, tableGenRecordGetTemplateArgName, tableGenRecordGetValue,
21    tableGenRecordGetValueAsBit, tableGenRecordGetValueAsBitsInit, tableGenRecordGetValueAsDag,
22    tableGenRecordGetValueAsDef, tableGenRecordGetValueAsInt, tableGenRecordGetValueAsListInit,
23    tableGenRecordGetValueAsListOfDefs, tableGenRecordGetValueAsListOfInts,
24    tableGenRecordGetValueAsListOfStrings, tableGenRecordGetValueAsOptionalDef,
25    tableGenRecordGetValueAsOptionalString, tableGenRecordGetValueAsString,
26    tableGenRecordHasDirectSuperClass, tableGenRecordIsAnonymous, tableGenRecordIsClass,
27    tableGenRecordIsSubclassOf, tableGenRecordIsValueUnset, tableGenRecordPrint,
28    tableGenRecordRecTyGetClass, tableGenRecordRecTyGetNumClasses, tableGenRecordRecTyIsSubClassOf,
29    tableGenRecordValDump, tableGenRecordValGetBitsWidth, tableGenRecordValGetListElementType,
30    tableGenRecordValGetLoc, tableGenRecordValGetNameInit, tableGenRecordValGetValue,
31    tableGenRecordValIsNonconcreteOK, tableGenRecordValIsTemplateArg, tableGenRecordValNext,
32    tableGenRecordValPrint, tableGenStringRefArrayFree,
33};
34
35use crate::{
36    error::{Error, SourceLoc, SourceLocation, TableGenError, WithLocation},
37    init::{BitInit, BitsInit, DagInit, DefInit, ListInit, StringInit, TypedInit},
38    string_ref::StringRef,
39    util::print_callback,
40};
41use std::fmt::{self, Debug, Display, Formatter};
42
43/// An immutable reference to a TableGen record.
44///
45/// This reference cannot outlive the
46/// [`RecordKeeper`](crate::record_keeper::RecordKeeper) from which it is
47/// borrowed.
48#[derive(Clone, Copy, PartialEq, Eq)]
49pub struct Record<'a> {
50    raw: TableGenRecordRef,
51    _reference: PhantomData<&'a TableGenRecordRef>,
52}
53
54impl Display for Record<'_> {
55    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
56        let mut data = (formatter, Ok(()));
57
58        unsafe {
59            tableGenRecordPrint(
60                self.raw,
61                Some(print_callback),
62                &mut data as *mut _ as *mut c_void,
63            );
64        }
65
66        data.1
67    }
68}
69
70impl Debug for Record<'_> {
71    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
72        writeln!(formatter, "Record(")?;
73        Display::fmt(self, formatter)?;
74        write!(formatter, ")")
75    }
76}
77
78impl std::hash::Hash for Record<'_> {
79    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
80        self.raw.hash(state);
81    }
82}
83
84macro_rules! record_value {
85    ($(#[$attr:meta])* $name:ident, $type:ty) => {
86        paste! {
87            $(#[$attr])*
88            pub fn [<$name _value>](self, name: &str) -> Result<$type, Error> {
89                self.value(name)?.try_into()
90            }
91        }
92    };
93}
94
95impl<'a> Record<'a> {
96    /// Creates a record from a raw object.
97    ///
98    /// # Safety
99    ///
100    /// The raw object must be valid.
101    pub unsafe fn from_raw(ptr: TableGenRecordRef) -> Record<'a> {
102        Record {
103            raw: ptr,
104            _reference: PhantomData,
105        }
106    }
107
108    /// Returns the name of the record.
109    ///
110    /// # Errors
111    ///
112    /// Returns an error if the name is not a valid UTF-8 string.
113    pub fn name(self) -> Result<&'a str, Error> {
114        unsafe { StringRef::from_raw(tableGenRecordGetName(self.raw)) }
115            .try_into()
116            .map_err(TableGenError::from)
117            .map_err(|e| e.with_location(self))
118    }
119
120    record_value!(
121        /// Returns the field with the given name converted to a [`Vec<bool>`]
122        /// if this field is of type [`BitsInit`](crate::init::BitsInit).
123        bits,
124        Vec<bool>
125    );
126    record_value!(
127        /// Returns the field with the given name converted to a [`String`]
128        /// if this field is of type [`StringInit`](crate::init::StringInit).
129        ///
130        /// Note that this copies the string into a new string.
131        code,
132        String
133    );
134    record_value!(
135        /// Returns the field with the given name converted to a [`&str`]
136        /// if this field is of type [`StringInit`](crate::init::StringInit).
137        code_str,
138        &'a str
139    );
140    record_value!(
141        /// Returns the field with the given name converted to a [`String`]
142        /// if this field is of type [`StringInit`](crate::init::StringInit).
143        ///
144        /// Note that this copies the string into a new string.
145        string,
146        String
147    );
148
149    /// Returns a [`RecordValue`] for the field with the given name.
150    pub fn value<'n>(self, name: &'n str) -> Result<RecordValue<'a>, Error> {
151        let value = unsafe { tableGenRecordGetValue(self.raw, StringRef::from(name).to_raw()) };
152        if !value.is_null() {
153            Ok(unsafe { RecordValue::from_raw(value) })
154        } else {
155            Err(TableGenError::MissingValue(String::from(name)).with_location(self))
156        }
157    }
158
159    /// Returns true if the record is anonymous.
160    pub fn anonymous(self) -> bool {
161        unsafe { tableGenRecordIsAnonymous(self.raw) > 0 }
162    }
163
164    /// Returns true if the record is a subclass of the class with the given
165    /// name.
166    pub fn subclass_of(self, class: &str) -> bool {
167        unsafe { tableGenRecordIsSubclassOf(self.raw, StringRef::from(class).to_raw()) > 0 }
168    }
169
170    /// Returns an iterator over the fields of the record.
171    ///
172    /// The iterator yields [`RecordValue`] structs
173    pub fn values(self) -> RecordValueIter<'a> {
174        RecordValueIter::new(self)
175    }
176
177    /// Returns `true` if the record has a field with the given name.
178    pub fn has_field(self, name: &str) -> bool {
179        let v = unsafe { tableGenRecordGetValue(self.raw, StringRef::from(name).to_raw()) };
180        !v.is_null()
181    }
182
183    /// Returns the [`TableGenRecTyKind`](crate::raw::TableGenRecTyKind) of the
184    /// field with the given name, or `None` if the field does not exist.
185    pub fn field_type(self, name: &str) -> Option<crate::raw::TableGenRecTyKind::Type> {
186        use crate::raw::TableGenRecTyKind::TableGenInvalidRecTyKind;
187        let kind = unsafe { tableGenRecordGetFieldType(self.raw, StringRef::from(name).to_raw()) };
188        if kind == TableGenInvalidRecTyKind {
189            None
190        } else {
191            Some(kind)
192        }
193    }
194
195    /// Dumps the record to stderr (for debugging).
196    pub fn dump(self) {
197        unsafe { tableGenRecordDump(self.raw) }
198    }
199
200    /// Returns the number of template arguments.
201    pub fn num_template_args(self) -> usize {
202        unsafe { tableGenRecordGetNumTemplateArgs(self.raw) }
203    }
204
205    /// Returns the template argument name at the given index.
206    pub fn template_arg_name(self, index: usize) -> Option<&'a str> {
207        unsafe { StringRef::from_option_raw(tableGenRecordGetTemplateArgName(self.raw, index)) }
208            .and_then(|s| s.try_into().ok())
209    }
210
211    /// Returns an iterator over the template argument names.
212    pub fn template_args(self) -> TemplateArgIter<'a> {
213        let back = self.num_template_args();
214        TemplateArgIter {
215            record: self,
216            index: 0,
217            back,
218        }
219    }
220
221    /// Returns the number of direct super classes.
222    pub fn num_super_classes(self) -> usize {
223        unsafe { tableGenRecordGetNumSuperClasses(self.raw) }
224    }
225
226    /// Returns the super class at the given index.
227    pub fn super_class(self, index: usize) -> Option<Record<'a>> {
228        let ptr = unsafe { tableGenRecordGetSuperClass(self.raw, index) };
229        if ptr.is_null() {
230            None
231        } else {
232            Some(unsafe { Record::from_raw(ptr) })
233        }
234    }
235
236    /// Returns an iterator over the direct super classes.
237    pub fn direct_super_classes(self) -> SuperClassIter<'a> {
238        let back = self.num_super_classes();
239        SuperClassIter {
240            record: self,
241            index: 0,
242            back,
243        }
244    }
245
246    /// Returns the integer value of the field with the given name.
247    pub fn int_value(self, name: &str) -> Result<i64, Error> {
248        let mut out: i64 = 0;
249        let ok = unsafe {
250            tableGenRecordGetValueAsInt(self.raw, StringRef::from(name).to_raw(), &mut out)
251        };
252        if ok > 0 {
253            Ok(out)
254        } else {
255            Err(TableGenError::MissingValue(name.into()).with_location(self))
256        }
257    }
258
259    /// Returns the string value of the field with the given name as a `&str`.
260    pub fn str_value(self, name: &str) -> Result<&'a str, Error> {
261        let raw =
262            unsafe { tableGenRecordGetValueAsString(self.raw, StringRef::from(name).to_raw()) };
263        if raw.data.is_null() {
264            Err(TableGenError::MissingValue(name.into()).with_location(self))
265        } else {
266            unsafe { StringRef::from_raw(raw) }
267                .try_into()
268                .map_err(TableGenError::from)
269                .map_err(|e| e.with_location(self))
270        }
271    }
272
273    /// Returns the bit (boolean) value of the field with the given name.
274    pub fn bit_value(self, name: &str) -> Result<bool, Error> {
275        let mut out: i8 = 0;
276        let ok = unsafe {
277            tableGenRecordGetValueAsBit(self.raw, StringRef::from(name).to_raw(), &mut out)
278        };
279        if ok > 0 {
280            Ok(out != 0)
281        } else {
282            Err(TableGenError::MissingValue(name.into()).with_location(self))
283        }
284    }
285
286    /// Returns the def value of the field with the given name as a [`Record`].
287    pub fn def_value(self, name: &str) -> Result<Record<'a>, Error> {
288        let ptr = unsafe { tableGenRecordGetValueAsDef(self.raw, StringRef::from(name).to_raw()) };
289        if ptr.is_null() {
290            Err(TableGenError::MissingValue(name.into()).with_location(self))
291        } else {
292            Ok(unsafe { Record::from_raw(ptr) })
293        }
294    }
295
296    /// Returns the dag value of the field with the given name.
297    pub fn dag_value(self, name: &str) -> Result<DagInit<'a>, Error> {
298        let ptr = unsafe { tableGenRecordGetValueAsDag(self.raw, StringRef::from(name).to_raw()) };
299        if ptr.is_null() {
300            Err(TableGenError::MissingValue(name.into()).with_location(self))
301        } else {
302            Ok(unsafe { DagInit::from_raw(ptr) })
303        }
304    }
305
306    /// Returns the bits init of the field with the given name.
307    pub fn bits_init_value(self, name: &str) -> Result<BitsInit<'a>, Error> {
308        let ptr =
309            unsafe { tableGenRecordGetValueAsBitsInit(self.raw, StringRef::from(name).to_raw()) };
310        if ptr.is_null() {
311            Err(TableGenError::MissingValue(name.into()).with_location(self))
312        } else {
313            Ok(unsafe { BitsInit::from_raw(ptr) })
314        }
315    }
316
317    /// Returns the list init of the field with the given name.
318    pub fn list_init_value(self, name: &str) -> Result<ListInit<'a>, Error> {
319        let ptr =
320            unsafe { tableGenRecordGetValueAsListInit(self.raw, StringRef::from(name).to_raw()) };
321        if ptr.is_null() {
322            Err(TableGenError::MissingValue(name.into()).with_location(self))
323        } else {
324            Ok(unsafe { ListInit::from_raw(ptr) })
325        }
326    }
327
328    /// Returns the list-of-defs value of the field with the given name.
329    pub fn list_of_defs_value(self, name: &str) -> Result<Vec<Record<'a>>, Error> {
330        let ptr =
331            unsafe { tableGenRecordGetValueAsListOfDefs(self.raw, StringRef::from(name).to_raw()) };
332        if ptr.is_null() {
333            return Err(TableGenError::MissingValue(name.into()).with_location(self));
334        }
335        let len = unsafe { crate::raw::tableGenRecordVectorSize(ptr) };
336        let mut result = Vec::with_capacity(len);
337        for i in 0..len {
338            let rec = unsafe { crate::raw::tableGenRecordVectorGet(ptr, i) };
339            result.push(unsafe { Record::from_raw(rec) });
340        }
341        unsafe { crate::raw::tableGenRecordVectorFree(ptr) };
342        Ok(result)
343    }
344
345    /// Returns the list-of-ints value of the field with the given name.
346    pub fn list_of_ints_value(self, name: &str) -> Result<Vec<i64>, Error> {
347        let mut arr = std::ptr::null_mut();
348        let mut len: usize = 0;
349        let ok = unsafe {
350            tableGenRecordGetValueAsListOfInts(
351                self.raw,
352                StringRef::from(name).to_raw(),
353                &mut arr,
354                &mut len,
355            )
356        };
357        if ok == 0 {
358            return Err(TableGenError::MissingValue(name.into()).with_location(self));
359        }
360        let result = unsafe { std::slice::from_raw_parts(arr, len) }.to_vec();
361        unsafe { tableGenIntArrayFree(arr) };
362        Ok(result)
363    }
364
365    /// Returns the list-of-strings value of the field with the given name.
366    pub fn list_of_strings_value(self, name: &str) -> Result<Vec<&'a str>, Error> {
367        let mut arr = std::ptr::null_mut();
368        let mut len: usize = 0;
369        let ok = unsafe {
370            tableGenRecordGetValueAsListOfStrings(
371                self.raw,
372                StringRef::from(name).to_raw(),
373                &mut arr,
374                &mut len,
375            )
376        };
377        if ok == 0 {
378            return Err(TableGenError::MissingValue(name.into()).with_location(self));
379        }
380        let raw_refs = unsafe { std::slice::from_raw_parts(arr, len) };
381        let mut result = Vec::with_capacity(len);
382        for raw_ref in raw_refs {
383            let s: &'a str = unsafe { StringRef::from_raw(*raw_ref) }
384                .try_into()
385                .map_err(TableGenError::from)
386                .map_err(|e| e.with_location(self))?;
387            result.push(s);
388        }
389        unsafe { tableGenStringRefArrayFree(arr) };
390        Ok(result)
391    }
392
393    /// Returns the optional string value of the field, or `None` if unset.
394    ///
395    /// Returns `Err` if the field does not exist or is not a string/unset.
396    pub fn optional_str_value(self, name: &str) -> Result<Option<&'a str>, Error> {
397        let mut out = crate::raw::TableGenStringRef {
398            data: std::ptr::null(),
399            len: 0,
400        };
401        let ok = unsafe {
402            tableGenRecordGetValueAsOptionalString(
403                self.raw,
404                StringRef::from(name).to_raw(),
405                &mut out,
406            )
407        };
408        if ok == 0 {
409            return Err(TableGenError::MissingValue(name.into()).with_location(self));
410        }
411        if out.data.is_null() {
412            Ok(None)
413        } else {
414            let s: &'a str = unsafe { StringRef::from_raw(out) }
415                .try_into()
416                .map_err(TableGenError::from)
417                .map_err(|e| e.with_location(self))?;
418            Ok(Some(s))
419        }
420    }
421
422    /// Returns the optional def value of the field, or `None` if unset.
423    pub fn optional_def_value(self, name: &str) -> Option<Record<'a>> {
424        let ptr = unsafe {
425            tableGenRecordGetValueAsOptionalDef(self.raw, StringRef::from(name).to_raw())
426        };
427        if ptr.is_null() {
428            None
429        } else {
430            Some(unsafe { Record::from_raw(ptr) })
431        }
432    }
433
434    /// Returns true if the named field exists and has an unset value (`?`).
435    pub fn is_value_unset(self, name: &str) -> bool {
436        unsafe { tableGenRecordIsValueUnset(self.raw, StringRef::from(name).to_raw()) > 0 }
437    }
438
439    /// Returns true if this record is a class definition (not a def).
440    pub fn is_class(self) -> bool {
441        unsafe { tableGenRecordIsClass(self.raw) > 0 }
442    }
443
444    /// Returns the [`DefInit`] for this record.
445    pub fn def_init(self) -> DefInit<'a> {
446        unsafe { DefInit::from_raw(tableGenRecordGetDefInit(self.raw)) }
447    }
448
449    /// Returns the unique numeric ID of this record.
450    pub fn id(self) -> u32 {
451        unsafe { tableGenRecordGetID(self.raw) }
452    }
453
454    /// Returns the name as a raw [`TypedInit`].
455    pub fn name_init(self) -> TypedInit<'a> {
456        unsafe { TypedInit::from_raw(tableGenRecordGetNameInit(self.raw)) }
457    }
458
459    /// Returns true if the given record is a direct superclass of this record.
460    pub fn has_direct_super_class(self, super_class: Record<'a>) -> bool {
461        unsafe { tableGenRecordHasDirectSuperClass(self.raw, super_class.raw) > 0 }
462    }
463
464    /// Returns the number of classes in this record's type.
465    pub fn num_type_classes(self) -> usize {
466        unsafe { tableGenRecordRecTyGetNumClasses(self.raw) }
467    }
468
469    /// Returns the class at the given index in this record's type.
470    pub fn type_class(self, index: usize) -> Option<Record<'a>> {
471        let ptr = unsafe { tableGenRecordRecTyGetClass(self.raw, index) };
472        if ptr.is_null() {
473            None
474        } else {
475            Some(unsafe { Record::from_raw(ptr) })
476        }
477    }
478
479    /// Returns true if this record's type is a subclass of the given class.
480    pub fn type_is_subclass_of(self, class: Record<'a>) -> bool {
481        unsafe { tableGenRecordRecTyIsSubClassOf(self.raw, class.raw) > 0 }
482    }
483}
484
485impl SourceLoc for Record<'_> {
486    fn source_location(self) -> SourceLocation {
487        unsafe { SourceLocation::from_raw(tableGenRecordGetLoc(self.raw)) }
488    }
489}
490
491macro_rules! try_into {
492    ($type:ty) => {
493        impl<'a> TryFrom<RecordValue<'a>> for $type {
494            type Error = Error;
495
496            fn try_from(record_value: RecordValue<'a>) -> Result<Self, Self::Error> {
497                Self::try_from(record_value.init).map_err(|e| e.set_location(record_value))
498            }
499        }
500    };
501}
502
503try_into!(bool);
504try_into!(Vec<bool>);
505try_into!(Vec<BitInit<'a>>);
506try_into!(i64);
507try_into!(ListInit<'a>);
508try_into!(DagInit<'a>);
509try_into!(Record<'a>);
510try_into!(String);
511try_into!(&'a str);
512
513impl<'a> From<RecordValue<'a>> for TypedInit<'a> {
514    fn from(value: RecordValue<'a>) -> Self {
515        value.init
516    }
517}
518
519/// Struct that represents a field of a [`Record`].
520///
521/// Can be converted into a Rust type using the [`TryInto`] trait.
522#[derive(Debug, Clone, Copy, PartialEq, Eq)]
523pub struct RecordValue<'a> {
524    raw: TableGenRecordValRef,
525    pub name: StringInit<'a>,
526    pub init: TypedInit<'a>,
527    _reference: PhantomData<&'a TableGenRecordRef>,
528}
529
530impl Display for RecordValue<'_> {
531    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
532        let mut data = (formatter, Ok(()));
533
534        unsafe {
535            tableGenRecordValPrint(
536                self.raw,
537                Some(print_callback),
538                &mut data as *mut _ as *mut c_void,
539            );
540        }
541
542        data.1
543    }
544}
545
546impl std::hash::Hash for RecordValue<'_> {
547    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
548        self.raw.hash(state);
549    }
550}
551
552impl RecordValue<'_> {
553    /// Creates a record from a raw object.
554    ///
555    /// # Safety
556    ///
557    /// The raw object must be valid.
558    pub unsafe fn from_raw(ptr: TableGenRecordValRef) -> Self {
559        let name = unsafe { StringInit::from_raw(tableGenRecordValGetNameInit(ptr)) };
560        let value = unsafe { TypedInit::from_raw(tableGenRecordValGetValue(ptr)) };
561        Self {
562            name,
563            init: value,
564            raw: ptr,
565            _reference: PhantomData,
566        }
567    }
568
569    /// Dumps this record value to stderr (for debugging).
570    pub fn dump(self) {
571        unsafe { tableGenRecordValDump(self.raw) }
572    }
573
574    /// Returns true if this field is a template argument.
575    pub fn is_template_arg(self) -> bool {
576        unsafe { tableGenRecordValIsTemplateArg(self.raw) > 0 }
577    }
578
579    /// Returns true if nonconcrete values are allowed for this field.
580    pub fn is_nonconcrete_ok(self) -> bool {
581        unsafe { tableGenRecordValIsNonconcreteOK(self.raw) > 0 }
582    }
583
584    /// If this field is bits-typed, returns the bit width.
585    pub fn bits_width(self) -> Option<usize> {
586        let w = unsafe { tableGenRecordValGetBitsWidth(self.raw) };
587        if w == 0 { None } else { Some(w) }
588    }
589
590    /// If this field is list-typed, returns the element type kind.
591    pub fn list_element_type(self) -> Option<crate::raw::TableGenRecTyKind::Type> {
592        let k = unsafe { tableGenRecordValGetListElementType(self.raw) };
593        if k == RawInvalidRecTyKind {
594            None
595        } else {
596            Some(k)
597        }
598    }
599}
600
601impl SourceLoc for RecordValue<'_> {
602    fn source_location(self) -> SourceLocation {
603        unsafe { SourceLocation::from_raw(tableGenRecordValGetLoc(self.raw)) }
604    }
605}
606
607/// Iterator over the fields of a [`Record`].
608#[derive(Debug, Clone)]
609pub struct RecordValueIter<'a> {
610    record: TableGenRecordRef,
611    current: TableGenRecordValRef,
612    _reference: PhantomData<&'a TableGenRecordRef>,
613}
614
615impl<'a> RecordValueIter<'a> {
616    fn new(record: Record<'a>) -> RecordValueIter<'a> {
617        unsafe {
618            RecordValueIter {
619                record: record.raw,
620                current: tableGenRecordGetFirstValue(record.raw),
621                _reference: PhantomData,
622            }
623        }
624    }
625}
626
627impl<'a> Iterator for RecordValueIter<'a> {
628    type Item = RecordValue<'a>;
629
630    fn next(&mut self) -> Option<RecordValue<'a>> {
631        if self.current.is_null() {
632            return None;
633        }
634        let res = unsafe { RecordValue::from_raw(self.current) };
635        self.current = unsafe { tableGenRecordValNext(self.record, self.current) };
636        Some(res)
637    }
638}
639
640impl std::iter::FusedIterator for RecordValueIter<'_> {}
641
642/// Iterator over the template argument names of a [`Record`].
643#[derive(Debug, Clone)]
644pub struct TemplateArgIter<'a> {
645    record: Record<'a>,
646    index: usize,
647    back: usize,
648}
649
650impl<'a> Iterator for TemplateArgIter<'a> {
651    type Item = &'a str;
652
653    fn next(&mut self) -> Option<Self::Item> {
654        if self.index >= self.back {
655            return None;
656        }
657        let name = self.record.template_arg_name(self.index);
658        self.index += 1;
659        name
660    }
661
662    fn size_hint(&self) -> (usize, Option<usize>) {
663        let remaining = self.back.saturating_sub(self.index);
664        (remaining, Some(remaining))
665    }
666}
667
668impl<'a> DoubleEndedIterator for TemplateArgIter<'a> {
669    fn next_back(&mut self) -> Option<Self::Item> {
670        if self.index >= self.back {
671            return None;
672        }
673        self.back -= 1;
674        match self.record.template_arg_name(self.back) {
675            Some(name) => Some(name),
676            None => {
677                self.back += 1;
678                None
679            }
680        }
681    }
682}
683
684impl ExactSizeIterator for TemplateArgIter<'_> {}
685
686impl std::iter::FusedIterator for TemplateArgIter<'_> {}
687
688/// Iterator over the direct super classes of a [`Record`].
689#[derive(Debug, Clone)]
690pub struct SuperClassIter<'a> {
691    record: Record<'a>,
692    index: usize,
693    back: usize,
694}
695
696impl<'a> Iterator for SuperClassIter<'a> {
697    type Item = Record<'a>;
698
699    fn next(&mut self) -> Option<Self::Item> {
700        if self.index >= self.back {
701            return None;
702        }
703        let class = self.record.super_class(self.index);
704        self.index += 1;
705        class
706    }
707
708    fn size_hint(&self) -> (usize, Option<usize>) {
709        let remaining = self.back.saturating_sub(self.index);
710        (remaining, Some(remaining))
711    }
712}
713
714impl<'a> DoubleEndedIterator for SuperClassIter<'a> {
715    fn next_back(&mut self) -> Option<Self::Item> {
716        if self.index >= self.back {
717            return None;
718        }
719        self.back -= 1;
720        match self.record.super_class(self.back) {
721            Some(class) => Some(class),
722            None => {
723                self.back += 1;
724                None
725            }
726        }
727    }
728}
729
730impl ExactSizeIterator for SuperClassIter<'_> {}
731
732impl std::iter::FusedIterator for SuperClassIter<'_> {}
733
734#[cfg(test)]
735mod tests {
736    use super::*;
737    use crate::TableGenParser;
738
739    #[test]
740    fn record() {
741        let rk = TableGenParser::new()
742            .add_source(
743                r#"
744                class A;
745                class B;
746                class C;
747
748                def D1: A;
749                def D2: A, B;
750                def : B, C;
751                "#,
752            )
753            .unwrap()
754            .parse()
755            .expect("valid tablegen");
756        let d2 = rk.def("D2").expect("D2 exists");
757        assert!(d2.subclass_of("A"));
758        assert!(d2.subclass_of("B"));
759        assert!(!d2.subclass_of("C"));
760        assert!(!d2.subclass_of("D"));
761        let anon = rk
762            .defs()
763            .map(|(_name, def)| def)
764            .find(|d| d.anonymous())
765            .expect("anonymous class exists");
766        assert!(!anon.subclass_of("A"));
767        assert!(anon.subclass_of("B"));
768        assert!(anon.subclass_of("C"));
769    }
770
771    #[test]
772    fn single_value() {
773        let rk = TableGenParser::new()
774            .add_source(
775                r#"
776                def A {
777                    int size = 42;
778                }
779                "#,
780            )
781            .unwrap()
782            .parse()
783            .expect("valid tablegen");
784        let a = rk.def("A").expect("def A exists");
785        assert_eq!(a.name(), Ok("A"));
786        assert_eq!(a.int_value("size"), Ok(42));
787        assert_eq!(
788            a.value("size")
789                .and_then(|v| {
790                    assert!(v.name.to_str() == Ok("size"));
791                    v.init.as_int().map_err(|e| e.set_location(v))
792                })
793                .and_then(|i| {
794                    i64::try_from(i)
795                        .map_err(|e| e.with_location(crate::error::SourceLocation::none()))
796                }),
797            Ok(42)
798        );
799    }
800
801    #[test]
802    fn values() {
803        let rk = TableGenParser::new()
804            .add_source(
805                r#"
806                def A {
807                    int a = 5;
808                    string n = "hello";
809                }
810                "#,
811            )
812            .unwrap()
813            .parse()
814            .expect("valid tablegen");
815        let a = rk.def("A").expect("def A exists");
816        let values = a.values();
817        assert_eq!(values.clone().count(), 2);
818        for v in values {
819            match v.init {
820                TypedInit::Int(i) => {
821                    assert_eq!(v.name.to_str(), Ok("a"));
822                    assert_eq!(i64::try_from(i).unwrap(), 5);
823                }
824                TypedInit::String(i) => {
825                    assert_eq!(v.name.to_str(), Ok("n"));
826                    assert_eq!(i.to_str(), Ok("hello"));
827                }
828                _ => panic!("unexpected type"),
829            }
830        }
831    }
832
833    #[test]
834    fn empty_record_values() {
835        let rk = TableGenParser::new()
836            .add_source("def Empty;")
837            .unwrap()
838            .parse()
839            .expect("valid tablegen");
840        let r = rk.def("Empty").expect("def Empty exists");
841        assert_eq!(r.values().count(), 0);
842        // Calling next() on an already-exhausted iterator must not invoke UB.
843        let mut iter = r.values();
844        assert!(iter.next().is_none());
845        assert!(iter.next().is_none());
846    }
847
848    #[test]
849    fn print_error() {
850        let rk = TableGenParser::new()
851            .add_source(
852                r#"
853                class C<int test> {
854                    int a = test;
855                }
856                def A : C<4>;
857                "#,
858            )
859            .unwrap()
860            .parse()
861            .expect("valid tablegen");
862        let a = rk.def("A").expect("def A exists");
863        if let Err(e) = a.string_value("a") {
864            // With source info
865            let msg = format!("{}", e.clone().add_source_info(rk.source_info()));
866            let msg = msg.trim();
867            // LLVM 22+ changed PrintMessage formatting for in-memory buffers.
868            #[cfg(any(
869                feature = "llvm16-0",
870                feature = "llvm17-0",
871                feature = "llvm18-0",
872                feature = "llvm19-0",
873                feature = "llvm20-0",
874                feature = "llvm21-0"
875            ))]
876            assert_eq!(
877                msg,
878                r#"
879                  error: invalid conversion from Int to alloc::string::String
880                    int a = test;
881                        ^
882                "#
883                .trim()
884            );
885            #[cfg(feature = "llvm22-0")]
886            assert!(
887                msg.contains("error: invalid conversion from Int to alloc::string::String"),
888                "unexpected error message: {msg}"
889            );
890
891            // Without source info
892            drop(rk);
893            assert_eq!(
894                format!("{}", e).trim(),
895                r#"
896                  invalid conversion from Int to alloc::string::String
897                "#
898                .trim()
899            );
900
901            // With incorrect source info
902            let rk = TableGenParser::new()
903                .add_source("def A;")
904                .unwrap()
905                .parse()
906                .expect("valid tablegen");
907            assert_eq!(
908                format!("{}", e.add_source_info(rk.source_info())).trim(),
909                "invalid conversion from Int to alloc::string::String\nfailed to print source information: invalid source location"
910                .trim()
911            );
912        } else {
913            panic!("expected error")
914        }
915    }
916
917    #[test]
918    fn has_field() {
919        let rk = TableGenParser::new()
920            .add_source("def A { int x = 1; }")
921            .unwrap()
922            .parse()
923            .expect("valid tablegen");
924        let a = rk.def("A").expect("def A exists");
925        assert!(a.has_field("x"));
926        assert!(!a.has_field("y"));
927    }
928
929    #[test]
930    fn field_type() {
931        use crate::raw::TableGenRecTyKind::{
932            TableGenBitRecTyKind, TableGenIntRecTyKind, TableGenStringRecTyKind,
933        };
934        let rk = TableGenParser::new()
935            .add_source("def A { int i = 1; string s = \"hi\"; bit b = 1; }")
936            .unwrap()
937            .parse()
938            .expect("valid tablegen");
939        let a = rk.def("A").expect("def A exists");
940        assert_eq!(a.field_type("i"), Some(TableGenIntRecTyKind));
941        assert_eq!(a.field_type("s"), Some(TableGenStringRecTyKind));
942        assert_eq!(a.field_type("b"), Some(TableGenBitRecTyKind));
943        assert_eq!(a.field_type("nonexistent"), None);
944    }
945
946    #[test]
947    fn template_args() {
948        let rk = TableGenParser::new()
949            .add_source("class Foo<int x, string y>;")
950            .unwrap()
951            .parse()
952            .expect("valid tablegen");
953        let foo = rk.class("Foo").expect("class Foo exists");
954        assert_eq!(foo.num_template_args(), 2);
955        assert_eq!(foo.template_arg_name(0), Some("Foo:x"));
956        assert_eq!(foo.template_arg_name(1), Some("Foo:y"));
957        assert_eq!(foo.template_arg_name(2), None);
958        let names: Vec<_> = foo.template_args().collect();
959        assert_eq!(names, vec!["Foo:x", "Foo:y"]);
960        // Double-ended
961        let mut iter = foo.template_args();
962        assert_eq!(iter.next_back(), Some("Foo:y"));
963        assert_eq!(iter.next(), Some("Foo:x"));
964        assert!(iter.next().is_none());
965    }
966
967    #[test]
968    fn template_args_on_def() {
969        let rk = TableGenParser::new()
970            .add_source("class A; def D: A;")
971            .unwrap()
972            .parse()
973            .expect("valid tablegen");
974        let d = rk.def("D").expect("def D exists");
975        assert_eq!(d.num_template_args(), 0);
976        assert_eq!(d.template_arg_name(0), None);
977        assert_eq!(d.template_args().count(), 0);
978    }
979
980    #[test]
981    fn template_args_no_params() {
982        let rk = TableGenParser::new()
983            .add_source("class Foo;")
984            .unwrap()
985            .parse()
986            .expect("valid tablegen");
987        let foo = rk.class("Foo").expect("class Foo exists");
988        assert_eq!(foo.num_template_args(), 0);
989        assert_eq!(foo.template_args().count(), 0);
990        let mut iter = foo.template_args();
991        assert!(iter.next().is_none());
992        assert!(iter.next_back().is_none());
993    }
994
995    #[test]
996    fn template_args_len_tracks() {
997        let rk = TableGenParser::new()
998            .add_source("class Foo<int a, int b, int c>;")
999            .unwrap()
1000            .parse()
1001            .expect("valid tablegen");
1002        let foo = rk.class("Foo").expect("class Foo exists");
1003        let mut iter = foo.template_args();
1004        assert_eq!(iter.len(), 3);
1005        iter.next();
1006        assert_eq!(iter.len(), 2);
1007        iter.next_back();
1008        assert_eq!(iter.len(), 1);
1009        iter.next();
1010        assert_eq!(iter.len(), 0);
1011        assert!(iter.next().is_none());
1012        assert!(iter.next_back().is_none());
1013    }
1014
1015    #[test]
1016    fn super_classes() {
1017        let rk = TableGenParser::new()
1018            .add_source(
1019                r#"
1020                class A;
1021                class B;
1022                class C;
1023                def D: A, B, C;
1024                "#,
1025            )
1026            .unwrap()
1027            .parse()
1028            .expect("valid tablegen");
1029        let d = rk.def("D").expect("def D exists");
1030        assert_eq!(d.num_super_classes(), 3);
1031        assert_eq!(d.super_class(0).unwrap().name().unwrap(), "A");
1032        assert_eq!(d.super_class(1).unwrap().name().unwrap(), "B");
1033        assert_eq!(d.super_class(2).unwrap().name().unwrap(), "C");
1034        assert!(d.super_class(3).is_none());
1035        let names: Vec<_> = d
1036            .direct_super_classes()
1037            .map(|r| r.name().unwrap().to_string())
1038            .collect();
1039        assert_eq!(names, vec!["A", "B", "C"]);
1040        // Double-ended
1041        let mut iter = d.direct_super_classes();
1042        assert_eq!(iter.next_back().unwrap().name().unwrap(), "C");
1043        assert_eq!(iter.next().unwrap().name().unwrap(), "A");
1044        assert_eq!(iter.next().unwrap().name().unwrap(), "B");
1045        assert!(iter.next().is_none());
1046    }
1047
1048    #[test]
1049    fn super_classes_on_class() {
1050        let rk = TableGenParser::new()
1051            .add_source("class A; class B: A; class C: A, B;")
1052            .unwrap()
1053            .parse()
1054            .expect("valid tablegen");
1055        let b = rk.class("B").expect("class B exists");
1056        assert_eq!(b.num_super_classes(), 1);
1057        assert_eq!(b.super_class(0).unwrap().name().unwrap(), "A");
1058        let c = rk.class("C").expect("class C exists");
1059        assert_eq!(c.num_super_classes(), 2);
1060        let names: Vec<_> = c
1061            .direct_super_classes()
1062            .map(|r| r.name().unwrap().to_string())
1063            .collect();
1064        assert_eq!(names, vec!["A", "B"]);
1065    }
1066
1067    #[test]
1068    fn super_classes_empty() {
1069        let rk = TableGenParser::new()
1070            .add_source("def D;")
1071            .unwrap()
1072            .parse()
1073            .expect("valid tablegen");
1074        let d = rk.def("D").expect("def D exists");
1075        assert_eq!(d.num_super_classes(), 0);
1076        assert!(d.super_class(0).is_none());
1077        assert_eq!(d.direct_super_classes().count(), 0);
1078        let mut iter = d.direct_super_classes();
1079        assert!(iter.next().is_none());
1080        assert!(iter.next_back().is_none());
1081    }
1082
1083    #[test]
1084    fn super_classes_len_tracks() {
1085        let rk = TableGenParser::new()
1086            .add_source("class A; class B; class C; def D: A, B, C;")
1087            .unwrap()
1088            .parse()
1089            .expect("valid tablegen");
1090        let d = rk.def("D").expect("def D exists");
1091        let mut iter = d.direct_super_classes();
1092        assert_eq!(iter.len(), 3);
1093        iter.next();
1094        assert_eq!(iter.len(), 2);
1095        iter.next_back();
1096        assert_eq!(iter.len(), 1);
1097        iter.next();
1098        assert_eq!(iter.len(), 0);
1099        assert!(iter.next().is_none());
1100        assert!(iter.next_back().is_none());
1101    }
1102}