reproto_core/
rp_field.rs

1//! Data Models for fields
2
3use errors::Result;
4use {Diagnostics, Flavor, FlavorField, Translate, Translator};
5
6#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
7#[serde(bound = "F::Type: ::serde::Serialize")]
8pub struct RpField<F: 'static>
9where
10    F: Flavor,
11{
12    /// Is the field required.
13    pub required: bool,
14    /// Mangled identifier, taking target-specific keywords into account.
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub safe_ident: Option<String>,
17    /// Original identifier used to specify the field.
18    pub ident: String,
19    /// Field comments.
20    pub comment: Vec<String>,
21    #[serde(rename = "type")]
22    pub ty: F::Type,
23    /// Alias of field in JSON.
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub field_as: Option<String>,
26}
27
28impl<F: 'static> FlavorField for RpField<F>
29where
30    F: Flavor,
31{
32    fn is_discriminating(&self) -> bool {
33        self.required
34    }
35}
36
37impl<F: 'static> RpField<F>
38where
39    F: Flavor,
40{
41    pub fn new<S: AsRef<str>>(ident: S, ty: F::Type) -> Self {
42        RpField {
43            required: true,
44            safe_ident: None,
45            ident: ident.as_ref().to_string(),
46            comment: Vec::new(),
47            ty: ty,
48            field_as: None,
49        }
50    }
51
52    pub fn is_optional(&self) -> bool {
53        !self.required
54    }
55
56    pub fn is_required(&self) -> bool {
57        self.required
58    }
59
60    /// Get the keyword-safe identifier.
61    ///
62    /// This will be the identifier escaped to avoid any target-language keywords.
63    pub fn safe_ident(&self) -> &str {
64        self.safe_ident.as_ref().unwrap_or(&self.ident)
65    }
66
67    /// Change the safe identifier.
68    pub fn with_safe_ident<S: AsRef<str>>(self, safe_ident: S) -> RpField<F> {
69        Self {
70            safe_ident: Some(safe_ident.as_ref().to_string()),
71            ..self
72        }
73    }
74
75    /// Get the original identifier of the field.
76    pub fn ident(&self) -> &str {
77        &self.ident
78    }
79
80    /// Get the JSON name of the field, if it differs from `ident`.
81    ///
82    /// TODO: Return `Option`, currently returns ident. This is a better indication whether
83    /// 'renaming' should occur.
84    pub fn name(&self) -> &str {
85        self.field_as.as_ref().unwrap_or(&self.ident)
86    }
87
88    /// Get the type of the field.
89    pub fn ty(&self) -> &F::Type {
90        &self.ty
91    }
92
93    pub fn display(&self) -> String {
94        self.name().to_owned()
95    }
96}
97
98impl<F: 'static, T> Translate<T> for RpField<F>
99where
100    F: Flavor,
101    T: Translator<Source = F>,
102{
103    type Source = F;
104    type Out = RpField<T::Target>;
105
106    /// Translate into different flavor.
107    fn translate(self, diag: &mut Diagnostics, translator: &T) -> Result<RpField<T::Target>> {
108        Ok(RpField {
109            required: self.required,
110            safe_ident: self.safe_ident,
111            ident: self.ident,
112            comment: self.comment,
113            ty: translator.translate_type(diag, self.ty)?,
114            field_as: self.field_as,
115        })
116    }
117}