Skip to main content

jeff/reader/
metadata.rs

1//! Metadata associated with jeff elements.
2
3use crate::capnp::jeff_capnp;
4
5use super::string_table::StringTable;
6use super::ReadError;
7
8/// A metadata entry, consisting of a name and a value.
9#[derive(Clone, Copy)]
10pub struct Metadata<'a> {
11    /// Internal capnproto function definition.
12    name: &'a str,
13    /// Value of the metadata entry.
14    value: capnp::any_pointer::Reader<'a>,
15}
16
17impl<'a> Metadata<'a> {
18    /// Create a new function view from a capnp reader.
19    ///
20    /// # Panics
21    ///
22    /// Panics if the metadata key string index is out of bounds or not valid utf8.
23    pub(crate) fn read_capnp(meta: jeff_capnp::meta::Reader<'a>, strings: StringTable<'a>) -> Self {
24        Self::try_read_capnp(meta, strings).unwrap_or_else(|e| panic!("{}", e))
25    }
26
27    /// Create a new function view from a capnp reader.
28    ///
29    /// # Errors
30    ///
31    /// - [`ReadError::StringOutOfBounds`] if the metadata key string index is out of bounds.
32    /// - [`ReadError::StringNotUtf8`] if the metadata key string is not valid utf8.
33    pub(crate) fn try_read_capnp(
34        meta: jeff_capnp::meta::Reader<'a>,
35        strings: StringTable<'a>,
36    ) -> Result<Self, ReadError> {
37        let name = strings.get(meta.get_name(), "metadata name")?;
38        let value = meta.get_value();
39
40        Ok(Self { name, value })
41    }
42
43    /// Returns the name of this metadata entry.
44    pub fn name(&self) -> &str {
45        self.name
46    }
47
48    /// Returns the value of this metadata entry, as a capnproto any pointer.
49    //
50    // TODO: Add `try_value_*` getters that try to cast into str / int / float / etc.
51    pub fn value_any_pointer(&self) -> capnp::any_pointer::Reader<'a> {
52        self.value
53    }
54
55    /// Returns the value as a string.
56    ///
57    /// Returns `None` if the value cannot be converted to a string.
58    pub fn value_str(&self) -> Option<&str> {
59        let reader = self.value.get_as::<capnp::text::Reader>().ok()?;
60        reader.to_str().ok()
61    }
62}
63
64impl std::fmt::Debug for Metadata<'_> {
65    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66        f.debug_struct("Metadata")
67            .field("name", &self.name)
68            .field("value", &"...")
69            .finish()
70    }
71}
72
73/// Trait for types that have metadata entries.
74pub trait HasMetadata: sealed::HasMetadataSealed {
75    /// Returns an iterator over the metadata entries for this module.
76    fn metadata_entries(&self) -> impl Iterator<Item = Metadata<'_>> {
77        self.metadata_reader()
78            .iter()
79            .map(|m| Metadata::read_capnp(m, self.strings()))
80    }
81
82    /// Returns the number of metadata entries in this module.
83    fn metadata_count(&self) -> usize {
84        self.metadata_reader().len() as usize
85    }
86
87    /// Returns the `n`-th metadata entry in this module.
88    ///
89    /// # Panics
90    ///
91    /// Panics if `n` is equal or greater than [`HasMetadata::metadata_count`].
92    fn metadata(&self, n: usize) -> Metadata<'_> {
93        Metadata::read_capnp(self.metadata_reader().get(n as u32), self.strings())
94    }
95
96    /// Returns the `n`-th metadata entry in this module.
97    ///
98    /// Returns `None` if `n` is equal or greater than [`HasMetadata::metadata_count`].
99    fn try_metadata(&self, n: usize) -> Option<Metadata<'_>> {
100        let m = self.metadata_reader().try_get(n as u32)?;
101        Some(Metadata::read_capnp(m, self.strings()))
102    }
103}
104
105pub(crate) mod sealed {
106    use crate::capnp::jeff_capnp;
107    use crate::reader::string_table::StringTable;
108
109    pub trait HasMetadataSealed {
110        /// Returns the internal storage of strings.
111        ///
112        /// This is a list of strings that are reused across the different jeff definitions,
113        /// and encoded as an index into this list.
114        fn strings(&self) -> StringTable<'_>;
115
116        /// Returns the capnproto reader over the element's metadata.
117        fn metadata_reader(&self) -> capnp::struct_list::Reader<'_, jeff_capnp::meta::Owned>;
118    }
119}