jeff/reader/
function.rs

1//! Function definition in a jeff program.
2use crate::capnp::jeff_capnp;
3use crate::reader::Value;
4
5use super::metadata::sealed::HasMetadataSealed;
6use super::string_table::StringTable;
7use super::{ReadError, Region, ValueTable};
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<Value<'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(&self) -> impl Iterator<Item = Result<Value<'a>, ReadError>> + '_ {
104        match self {
105            Function::Declaration(decl) => itertools::Either::Left(decl.output_types()),
106            Function::Definition(def) => itertools::Either::Right(def.output_types()),
107        }
108    }
109}
110
111impl<'a> FunctionDefinition<'a> {
112    /// Returns the name of this function.
113    ///
114    /// # Panics
115    ///
116    /// Panics if the function name index is out of bounds or not valid utf8.
117    pub fn name(&self) -> &str {
118        self.strings
119            .get(self.function.get_name(), "function name")
120            .expect("Invalid function name definition")
121    }
122
123    /// Returns the dataflow region associated with this function.
124    pub fn body(&self) -> Region<'a> {
125        Region::read_capnp(self.body, self.strings, self.values())
126    }
127
128    /// Returns the value table associated with this function.
129    pub fn values(&self) -> ValueTable<'a> {
130        self.values
131    }
132
133    /// Returns the input types of this function.
134    pub fn input_types(&self) -> impl Iterator<Item = Result<Value<'a>, ReadError>> + 'a {
135        self.body().sources()
136    }
137
138    /// Returns the output types of this function.
139    pub fn output_types(&self) -> impl Iterator<Item = Result<Value<'a>, ReadError>> + 'a {
140        self.body().targets()
141    }
142}
143
144impl<'a> FunctionDeclaration<'a> {
145    /// Returns the name of this function.
146    ///
147    /// # Panics
148    ///
149    /// Panics if the function name index is out of bounds or not valid utf8.
150    pub fn name(&self) -> &str {
151        self.strings
152            .get(self.function.get_name(), "function name")
153            .expect("Invalid function name definition")
154    }
155
156    /// Returns the input types of this function.
157    pub fn input_types(&self) -> impl Iterator<Item = Result<Value<'a>, ReadError>> + '_ {
158        self.inputs
159            .iter()
160            .map(move |value| Ok(Value::read_capnp(None, value, self.strings)))
161    }
162
163    /// Returns the output types of this function.
164    pub fn output_types(&self) -> impl Iterator<Item = Result<Value<'a>, ReadError>> + '_ {
165        self.outputs
166            .iter()
167            .map(move |value| Ok(Value::read_capnp(None, value, self.strings)))
168    }
169}
170
171impl<'a> HasMetadataSealed for Function<'a> {
172    fn strings(&self) -> StringTable<'a> {
173        match self {
174            Function::Declaration(decl) => decl.strings,
175            Function::Definition(def) => def.strings,
176        }
177    }
178
179    fn metadata_reader(&self) -> capnp::struct_list::Reader<'_, jeff_capnp::meta::Owned> {
180        match self {
181            Function::Declaration(decl) => decl.metadata_reader(),
182            Function::Definition(def) => def.metadata_reader(),
183        }
184    }
185}
186
187impl<'a> HasMetadataSealed for FunctionDeclaration<'a> {
188    fn strings(&self) -> StringTable<'a> {
189        self.strings
190    }
191
192    fn metadata_reader(&self) -> capnp::struct_list::Reader<'_, jeff_capnp::meta::Owned> {
193        self.function
194            .get_metadata()
195            .expect("Metadata should be present")
196    }
197}
198
199impl<'a> HasMetadataSealed for FunctionDefinition<'a> {
200    fn strings(&self) -> StringTable<'a> {
201        self.strings
202    }
203
204    fn metadata_reader(&self) -> capnp::struct_list::Reader<'_, jeff_capnp::meta::Owned> {
205        self.function
206            .get_metadata()
207            .expect("Metadata should be present")
208    }
209}