Skip to main content

zlink_core/idl/
custom_object.rs

1//! Object type definition for Varlink IDL.
2
3use core::fmt;
4
5use alloc::vec::Vec;
6
7use super::{Field, List};
8
9/// An object type definition in Varlink IDL (struct-like with named fields).
10#[derive(Debug, Clone, Eq)]
11pub struct CustomObject<'a> {
12    /// The name of the object type.
13    name: &'a str,
14    /// The fields of the object type.
15    fields: List<'a, Field<'a>>,
16    /// The comments associated with this object type.
17    comments: List<'a, super::Comment<'a>>,
18}
19
20impl<'a> CustomObject<'a> {
21    /// Creates a new object type with the given name, borrowed fields, and comments.
22    pub const fn new(
23        name: &'a str,
24        fields: &'a [&'a Field<'a>],
25        comments: &'a [&'a super::Comment<'a>],
26    ) -> Self {
27        Self {
28            name,
29            fields: List::Borrowed(fields),
30            comments: List::Borrowed(comments),
31        }
32    }
33
34    /// Creates a new object type with the given name, owned fields, and comments.
35    pub fn new_owned(
36        name: &'a str,
37        fields: Vec<Field<'a>>,
38        comments: Vec<super::Comment<'a>>,
39    ) -> Self {
40        Self {
41            name,
42            fields: List::from(fields),
43            comments: List::from(comments),
44        }
45    }
46
47    /// Returns the name of the object type.
48    pub fn name(&self) -> &'a str {
49        self.name
50    }
51
52    /// Returns an iterator over the fields of the object type.
53    pub fn fields(&self) -> impl Iterator<Item = &Field<'a>> {
54        self.fields.iter()
55    }
56
57    /// The fields as a slice.
58    pub const fn fields_as_slice(&self) -> Option<&[&Field<'a>]> {
59        self.fields.as_borrowed()
60    }
61
62    /// Returns an iterator over the comments associated with this object type.
63    pub fn comments(&self) -> impl Iterator<Item = &super::Comment<'a>> {
64        self.comments.iter()
65    }
66}
67
68impl<'a> fmt::Display for CustomObject<'a> {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        // Comments first
71        for comment in self.comments.iter() {
72            writeln!(f, "{comment}")?;
73        }
74        write!(f, "type {} (", self.name)?;
75        let mut first = true;
76        for field in self.fields.iter() {
77            if !first {
78                write!(f, ", ")?;
79            }
80            first = false;
81            write!(f, "{field}")?;
82        }
83        write!(f, ")")
84    }
85}
86
87impl<'a> PartialEq for CustomObject<'a> {
88    fn eq(&self, other: &Self) -> bool {
89        self.name == other.name && self.fields == other.fields
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96    use crate::idl::{Comment, Field, Type};
97    use core::fmt::Write;
98
99    #[test]
100    fn display_with_comments() {
101        let comment1 = Comment::new("User data structure");
102        let comment2 = Comment::new("Contains basic user information");
103        let comments = [&comment1, &comment2];
104
105        let name_field = Field::new("name", &Type::String, &[]);
106        let age_field = Field::new("age", &Type::Int, &[]);
107        let fields = [&name_field, &age_field];
108
109        let custom_object = CustomObject::new("User", &fields, &comments);
110        let mut displayed = String::new();
111        write!(&mut displayed, "{}", custom_object).unwrap();
112        assert_eq!(
113            displayed,
114            "# User data structure\n# Contains basic user information\ntype User (name: string, age: int)"
115        );
116    }
117}