reproto_core/
rp_interface.rs

1//! Model for tuples.
2
3use errors::Result;
4use serde::Serialize;
5use std::slice;
6use std::vec;
7use translator;
8use {Diagnostics, Flavor, FlavorField, Loc, RpCode, RpDecl, RpReg, Translate, Translator};
9
10/// Default key to use for tagged sub type strategy.
11pub const DEFAULT_TAG: &str = "type";
12
13#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
14#[serde(tag = "type", rename_all = "snake_case")]
15pub enum RpSubTypeStrategy {
16    /// An object, with a single tag key indicating which sub-type to use.
17    Tagged { tag: String },
18    /// An sub-type is distinguished by its set of unique fields.
19    /// This requires a sub-type to actually _have_ a unique set of fields, which is validates
20    /// during translation.
21    Untagged,
22}
23
24impl Default for RpSubTypeStrategy {
25    fn default() -> Self {
26        RpSubTypeStrategy::Tagged {
27            tag: DEFAULT_TAG.to_string(),
28        }
29    }
30}
31
32decl_body!(pub struct RpInterfaceBody<F> {
33    pub fields: Vec<Loc<F::Field>>,
34    pub codes: Vec<Loc<RpCode>>,
35    pub sub_types: Vec<Loc<RpSubType<F>>>,
36    pub sub_type_strategy: RpSubTypeStrategy,
37});
38
39/// Iterator over fields.
40pub struct Fields<'a, F: 'static>
41where
42    F: Flavor,
43{
44    iter: slice::Iter<'a, Loc<F::Field>>,
45}
46
47impl<'a, F: 'static> Iterator for Fields<'a, F>
48where
49    F: Flavor,
50{
51    type Item = &'a Loc<F::Field>;
52
53    fn next(&mut self) -> Option<Self::Item> {
54        self.iter.next()
55    }
56}
57
58/// Iterator over discriminating sub-type fields.
59///
60/// Discriminating fields are ones which makes this sub-type unique, and are used to distinguish
61/// between different untagged sub-types.
62pub struct DiscriminatingFields<'a, F: 'static>
63where
64    F: Flavor,
65{
66    iter: vec::IntoIter<&'a Loc<F::Field>>,
67}
68
69impl<'a, F: 'static> Iterator for DiscriminatingFields<'a, F>
70where
71    F: Flavor,
72{
73    type Item = &'a Loc<F::Field>;
74
75    fn next(&mut self) -> Option<Self::Item> {
76        self.iter.next()
77    }
78}
79
80impl<F: 'static> RpInterfaceBody<F>
81where
82    F: Flavor,
83{
84    pub fn fields(&self) -> Fields<F> {
85        Fields {
86            iter: self.fields.iter(),
87        }
88    }
89}
90
91impl<F: 'static, T> Translate<T> for RpInterfaceBody<F>
92where
93    F: Flavor,
94    T: Translator<Source = F>,
95{
96    type Source = F;
97    type Out = RpInterfaceBody<T::Target>;
98
99    /// Translate into different flavor.
100    fn translate(
101        self,
102        diag: &mut Diagnostics,
103        translator: &T,
104    ) -> Result<RpInterfaceBody<T::Target>> {
105        translator.visit(diag, &self.name)?;
106
107        let name = translator.translate_local_name(diag, RpReg::Interface, self.name)?;
108
109        Ok(RpInterfaceBody {
110            name: name,
111            ident: self.ident,
112            comment: self.comment,
113            decls: self.decls.translate(diag, translator)?,
114            fields: translator::Fields(self.fields).translate(diag, translator)?,
115            codes: self.codes,
116            sub_types: self.sub_types.translate(diag, translator)?,
117            sub_type_strategy: self.sub_type_strategy,
118        })
119    }
120}
121
122#[derive(Debug, Clone, Serialize)]
123#[serde(bound = "F: Serialize, F::Field: Serialize, F::Endpoint: Serialize, F::Package: \
124                 Serialize, F::Name: Serialize, F::EnumType: Serialize")]
125pub struct RpSubType<F: 'static>
126where
127    F: Flavor,
128{
129    pub name: F::Name,
130    pub ident: String,
131    pub comment: Vec<String>,
132    /// Inner declarations.
133    pub decls: Vec<RpDecl<F>>,
134    pub fields: Vec<Loc<F::Field>>,
135    pub codes: Vec<Loc<RpCode>>,
136    #[serde(skip_serializing_if = "Option::is_none")]
137    pub sub_type_name: Option<Loc<String>>,
138}
139
140impl<F: 'static> RpSubType<F>
141where
142    F: Flavor,
143{
144    pub fn name(&self) -> &str {
145        self.sub_type_name
146            .as_ref()
147            .map(|t| t.as_str())
148            .unwrap_or(&self.ident)
149    }
150
151    /// Access the set of fields which are used to make this sub-type unique.
152    pub fn discriminating_fields(&self) -> DiscriminatingFields<F> {
153        let fields = self.fields
154            .iter()
155            .filter(|f| f.is_discriminating())
156            .collect::<Vec<_>>();
157
158        DiscriminatingFields {
159            iter: fields.into_iter(),
160        }
161    }
162}
163
164impl<F: 'static, T> Translate<T> for RpSubType<F>
165where
166    F: Flavor,
167    T: Translator<Source = F>,
168{
169    type Source = F;
170    type Out = RpSubType<T::Target>;
171
172    /// Translate into different flavor.
173    fn translate(self, diag: &mut Diagnostics, translator: &T) -> Result<RpSubType<T::Target>> {
174        translator.visit(diag, &self.name)?;
175
176        let name = translator.translate_local_name(diag, RpReg::SubType, self.name)?;
177
178        Ok(RpSubType {
179            name: name,
180            ident: self.ident,
181            comment: self.comment,
182            decls: self.decls.translate(diag, translator)?,
183            fields: translator::Fields(self.fields).translate(diag, translator)?,
184            codes: self.codes,
185            sub_type_name: self.sub_type_name,
186        })
187    }
188}