Skip to main content

cynic_parser/executable/
ids.rs

1use std::num::NonZeroU32;
2
3use super::{ExecutableDocument, storage::*, types::TypeRecord};
4use crate::{AstLookup, common::IdRange};
5
6pub use crate::values::ids::{ConstValueId, ValueId};
7
8macro_rules! make_id {
9    ($name:ident, $output:ident, $field:ident) => {
10        #[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
11        pub struct $name(NonZeroU32);
12
13        impl $name {
14            pub(super) fn new(index: usize) -> Self {
15                Self(
16                    NonZeroU32::new(u32::try_from(index + 1).expect("too many indices"))
17                        .expect("also too many indices"),
18                )
19            }
20        }
21
22        impl AstLookup<$name> for ExecutableDocument {
23            type Output = $output;
24
25            fn lookup(&self, index: $name) -> &Self::Output {
26                &self.$field[(index.0.get() - 1) as usize]
27            }
28        }
29    };
30}
31
32macro_rules! impl_id_range_ops {
33    ($name: ident) => {
34        impl crate::common::IdOperations for $name {
35            fn empty_range() -> IdRange<Self> {
36                IdRange::new(Self::new(0), Self::new(0))
37            }
38            fn forward(self) -> Option<Self> {
39                Some(Self(NonZeroU32::new(self.0.get() + 1)?))
40            }
41            fn back(self) -> Option<Self> {
42                Some(Self(NonZeroU32::new(self.0.get() - 1)?))
43            }
44            fn cmp(self, other: Self) -> std::cmp::Ordering {
45                self.0.get().cmp(&other.0.get())
46            }
47            fn distance(lhs: Self, rhs: Self) -> usize {
48                rhs.0.get().saturating_sub(lhs.0.get()) as usize
49            }
50        }
51    };
52}
53
54make_id!(
55    ExecutableDefinitionId,
56    ExecutableDefinitionRecord,
57    definitions
58);
59impl_id_range_ops!(ExecutableDefinitionId);
60
61make_id!(OperationDefinitionId, OperationDefinitionRecord, operations);
62
63make_id!(FragmentDefinitionId, FragmentDefinitionRecord, fragments);
64
65make_id!(DescriptionId, DescriptionRecord, descriptions);
66
67make_id!(SelectionId, SelectionRecord, selections);
68impl_id_range_ops!(SelectionId);
69
70make_id!(FieldSelectionId, FieldSelectionRecord, field_selections);
71make_id!(InlineFragmentId, InlineFragmentRecord, inline_fragments);
72make_id!(FragmentSpreadId, FragmentSpreadRecord, fragment_spreads);
73
74make_id!(DirectiveId, DirectiveRecord, directives);
75
76make_id!(ArgumentId, ArgumentRecord, arguments);
77
78impl_id_range_ops!(DirectiveId);
79impl_id_range_ops!(ArgumentId);
80
81make_id!(TypeId, TypeRecord, types);
82
83make_id!(VariableDefinitionId, VariableDefinitionRecord, variables);
84impl_id_range_ops!(VariableDefinitionId);
85
86make_id!(BlockStringLiteralId, str, block_strings);
87
88#[derive(Clone, Copy)]
89pub struct StringId(NonZeroU32);
90
91impl StringId {
92    pub(super) fn new(index: usize) -> Self {
93        Self(
94            NonZeroU32::new(u32::try_from(index + 1).expect("too many indices"))
95                .expect("also too many indices"),
96        )
97    }
98
99    pub(crate) fn get(&self) -> usize {
100        (self.0.get() - 1) as usize
101    }
102}
103
104impl AstLookup<StringId> for ExecutableDocument {
105    type Output = str;
106
107    fn lookup(&self, index: StringId) -> &Self::Output {
108        &self.strings[(index.0.get() - 1) as usize]
109    }
110}
111
112#[derive(Clone, Copy)]
113pub enum StringLiteralId {
114    String(StringId),
115    Block(BlockStringLiteralId),
116}