Skip to main content

jeff/reader/
function.rs

1//! Function definition in a jeff program.
2use crate::capnp::jeff_capnp;
3use crate::reader::value::{FunctionIOValue, ValueTable};
4
5use super::metadata::sealed::HasMetadataSealed;
6use super::string_table::StringTable;
7use super::{ReadError, Region};
8
9/// Function index into the module's function table.
10pub type FunctionId = u32;
11
12/// Function in a jeff module.
13#[derive(Clone, Copy, Debug)]
14pub enum Function<'a> {
15    /// Function definition with a body.
16    Definition(FunctionDefinition<'a>),
17    /// Function declaration with only a signature.
18    Declaration(FunctionDeclaration<'a>),
19}
20
21/// Function definition in a jeff module.
22#[derive(Clone, Copy, Debug)]
23pub struct FunctionDefinition<'a> {
24    /// Internal capnproto function definition.
25    function: jeff_capnp::function::Reader<'a>,
26    /// Reader for the function's body.
27    body: jeff_capnp::region::Reader<'a>,
28    /// Function-level register of typed hyperedges.
29    values: ValueTable<'a>,
30    /// Module-level register of reused strings.
31    strings: StringTable<'a>,
32}
33
34/// Function declaration in a jeff module.
35#[derive(Clone, Copy, Debug)]
36pub struct FunctionDeclaration<'a> {
37    /// Internal capnproto function declaration.
38    function: jeff_capnp::function::Reader<'a>,
39    /// Reader for the function's inputs.
40    inputs: capnp::struct_list::Reader<'a, jeff_capnp::value::Owned>,
41    /// Reader for the function's outputs.
42    outputs: capnp::struct_list::Reader<'a, jeff_capnp::value::Owned>,
43    /// Module-level register of reused strings.
44    strings: StringTable<'a>,
45}
46
47impl<'a> Function<'a> {
48    /// Create a new function view from a capnp reader.
49    pub(crate) fn read_capnp(
50        function: jeff_capnp::function::Reader<'a>,
51        strings: StringTable<'a>,
52    ) -> Self {
53        match function.which().expect("Function should be valid") {
54            jeff_capnp::function::Which::Definition(def) => {
55                let body = def.get_body().expect("Body should be present");
56                let values = ValueTable::read_capnp(
57                    def.get_values().expect("Values should be present"),
58                    strings,
59                );
60                let def = FunctionDefinition {
61                    function,
62                    body,
63                    values,
64                    strings,
65                };
66                Self::Definition(def)
67            }
68            jeff_capnp::function::Which::Declaration(decl) => {
69                let inputs = decl.get_inputs().expect("Inputs should be present");
70                let outputs = decl.get_outputs().expect("Outputs should be present");
71                let decl = FunctionDeclaration {
72                    function,
73                    inputs,
74                    outputs,
75                    strings,
76                };
77                Self::Declaration(decl)
78            }
79        }
80    }
81
82    /// Returns the name of this function.
83    ///
84    /// # Panics
85    ///
86    /// Panics if the function name index is out of bounds or not valid utf8.
87    pub fn name(&self) -> &str {
88        match self {
89            Function::Declaration(decl) => decl.name(),
90            Function::Definition(def) => def.name(),
91        }
92    }
93
94    /// Returns the input types of this function.
95    pub fn input_types(&self) -> impl Iterator<Item = Result<FunctionIOValue<'a>, ReadError>> + '_ {
96        match self {
97            Function::Declaration(decl) => itertools::Either::Left(decl.input_types()),
98            Function::Definition(def) => itertools::Either::Right(def.input_types()),
99        }
100    }
101
102    /// Returns the output types of this function.
103    pub fn output_types(
104        &self,
105    ) -> impl Iterator<Item = Result<FunctionIOValue<'a>, ReadError>> + '_ {
106        match self {
107            Function::Declaration(decl) => itertools::Either::Left(decl.output_types()),
108            Function::Definition(def) => itertools::Either::Right(def.output_types()),
109        }
110    }
111}
112
113impl<'a> FunctionDefinition<'a> {
114    /// Returns the name of this function.
115    ///
116    /// # Panics
117    ///
118    /// Panics if the function name index is out of bounds or not valid utf8.
119    pub fn name(&self) -> &str {
120        self.strings
121            .get(self.function.get_name(), "function name")
122            .expect("Invalid function name definition")
123    }
124
125    /// Returns the dataflow region associated with this function.
126    pub fn body(&self) -> Region<'a> {
127        Region::read_capnp(self.body, self.strings, self.values())
128    }
129
130    /// Returns the value table associated with this function.
131    pub fn values(&self) -> ValueTable<'a> {
132        self.values
133    }
134
135    /// Returns the input types of this function.
136    pub fn input_types(&self) -> impl Iterator<Item = Result<FunctionIOValue<'a>, ReadError>> + 'a {
137        self.body().sources().map(|v| Ok(v?.into()))
138    }
139
140    /// Returns the output types of this function.
141    pub fn output_types(
142        &self,
143    ) -> impl Iterator<Item = Result<FunctionIOValue<'a>, ReadError>> + 'a {
144        self.body().targets().map(|v| Ok(v?.into()))
145    }
146}
147
148impl<'a> FunctionDeclaration<'a> {
149    /// Returns the name of this function.
150    ///
151    /// # Panics
152    ///
153    /// Panics if the function name index is out of bounds or not valid utf8.
154    pub fn name(&self) -> &str {
155        self.strings
156            .get(self.function.get_name(), "function name")
157            .expect("Invalid function name definition")
158    }
159
160    /// Returns the input types of this function.
161    pub fn input_types(&self) -> impl Iterator<Item = Result<FunctionIOValue<'a>, ReadError>> + '_ {
162        self.inputs
163            .iter()
164            .map(move |value| Ok(FunctionIOValue::read_capnp(value, self.strings)))
165    }
166
167    /// Returns the output types of this function.
168    pub fn output_types(
169        &self,
170    ) -> impl Iterator<Item = Result<FunctionIOValue<'a>, ReadError>> + '_ {
171        self.outputs
172            .iter()
173            .map(move |value| Ok(FunctionIOValue::read_capnp(value, self.strings)))
174    }
175}
176
177impl<'a> HasMetadataSealed for Function<'a> {
178    fn strings(&self) -> StringTable<'a> {
179        match self {
180            Function::Declaration(decl) => decl.strings,
181            Function::Definition(def) => def.strings,
182        }
183    }
184
185    fn metadata_reader(&self) -> capnp::struct_list::Reader<'_, jeff_capnp::meta::Owned> {
186        match self {
187            Function::Declaration(decl) => decl.metadata_reader(),
188            Function::Definition(def) => def.metadata_reader(),
189        }
190    }
191}
192
193impl<'a> HasMetadataSealed for FunctionDeclaration<'a> {
194    fn strings(&self) -> StringTable<'a> {
195        self.strings
196    }
197
198    fn metadata_reader(&self) -> capnp::struct_list::Reader<'_, jeff_capnp::meta::Owned> {
199        self.function
200            .get_metadata()
201            .expect("Metadata should be present")
202    }
203}
204
205impl<'a> HasMetadataSealed for FunctionDefinition<'a> {
206    fn strings(&self) -> StringTable<'a> {
207        self.strings
208    }
209
210    fn metadata_reader(&self) -> capnp::struct_list::Reader<'_, jeff_capnp::meta::Owned> {
211        self.function
212            .get_metadata()
213            .expect("Metadata should be present")
214    }
215}