Skip to main content

zlink_core/idl/
field.rs

1//! Custom type, field and parameter definitions for Varlink IDL.
2
3use core::fmt;
4
5use super::{Comment, List, Type, TypeRef};
6
7/// A field in a custom type or method parameter.
8#[derive(Debug, Clone, Eq)]
9pub struct Field<'a> {
10    /// The name of the field.
11    name: &'a str,
12    /// The type of the field.
13    ty: TypeRef<'a>,
14    /// Comments associated with this field.
15    comments: List<'a, Comment<'a>>,
16}
17
18/// Type alias for method parameters, which have the same structure as fields.
19pub type Parameter<'a> = Field<'a>;
20
21impl<'a> Field<'a> {
22    /// Creates a new field with the given name, borrowed type, and comments.
23    pub const fn new(name: &'a str, ty: &'a Type<'a>, comments: &'a [&'a Comment<'a>]) -> Self {
24        Self {
25            name,
26            ty: TypeRef::new(ty),
27            comments: List::Borrowed(comments),
28        }
29    }
30
31    /// Same as `new` but takes `ty` by value.
32    /// Creates a new field with the given name, owned type, and comments.
33    pub fn new_owned(name: &'a str, ty: Type<'a>, comments: alloc::vec::Vec<Comment<'a>>) -> Self {
34        Self {
35            name,
36            ty: TypeRef::new_owned(ty),
37            comments: List::from(comments),
38        }
39    }
40
41    /// Returns the name of the field.
42    pub fn name(&self) -> &'a str {
43        self.name
44    }
45
46    /// Returns the type of the field.
47    pub fn ty(&self) -> &Type<'a> {
48        self.ty.inner()
49    }
50
51    /// Returns the comments associated with this field.
52    pub fn comments(&self) -> impl Iterator<Item = &Comment<'a>> {
53        self.comments.iter()
54    }
55}
56
57impl<'a> fmt::Display for Field<'a> {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        // Comments first
60        for comment in self.comments.iter() {
61            writeln!(f, "{comment}")?;
62        }
63        write!(f, "{}: {}", self.name, self.ty)
64    }
65}
66
67impl<'a> PartialEq for Field<'a> {
68    fn eq(&self, other: &Self) -> bool {
69        self.name == other.name && self.ty == other.ty
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use crate::idl::Type;
77
78    #[test]
79    fn field_creation() {
80        let field = Field::new("age", &Type::Int, &[]);
81        assert_eq!(field.name(), "age");
82        assert_eq!(field.ty(), &Type::Int);
83    }
84
85    #[test]
86    fn parameter_alias() {
87        let param: Parameter<'_> = Field::new("input", &Type::String, &[]);
88        assert_eq!(param.name(), "input");
89        assert_eq!(param.ty(), &Type::String);
90    }
91
92    #[test]
93    fn display_with_comments() {
94        use crate::idl::Comment;
95        use core::fmt::Write;
96
97        let comment1 = Comment::new("User's email address");
98        let comment2 = Comment::new("Must be valid format");
99        let comments = [&comment1, &comment2];
100
101        let field = Field::new("email", &Type::String, &comments);
102        let mut displayed = String::new();
103        write!(&mut displayed, "{}", field).unwrap();
104        assert_eq!(
105            displayed,
106            "# User's email address\n# Must be valid format\nemail: string"
107        );
108    }
109}