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}