Skip to main content

jeff/reader/
region.rs

1//! Dataflow region definition in a jeff program.
2use crate::capnp::jeff_capnp;
3use crate::reader::value::{ValueTable, WireValue};
4use crate::Direction;
5
6use super::metadata::sealed::HasMetadataSealed;
7use super::op::Operation;
8use super::string_table::StringTable;
9use super::value::ValueId;
10use super::ReadError;
11
12/// Dataflow region defined in a jeff module.
13#[derive(Clone, Copy, Debug)]
14pub struct Region<'a> {
15    /// Internal capnproto region definition.
16    region: jeff_capnp::region::Reader<'a>,
17    /// Module-level register of reused strings.
18    strings: StringTable<'a>,
19    /// Function-level register of typed hyperedges.
20    values: ValueTable<'a>,
21}
22
23impl<'a> Region<'a> {
24    /// Create a new dataflow region reader from a capnp reader.
25    pub(crate) fn read_capnp(
26        region: jeff_capnp::region::Reader<'a>,
27        strings: StringTable<'a>,
28        values: ValueTable<'a>,
29    ) -> Self {
30        Self {
31            region,
32            strings,
33            values,
34        }
35    }
36
37    /// Returns an iterator over the sources or target values of this region.
38    ///
39    /// # Errors
40    ///
41    /// - [`ReadError::ValueOutOfBounds`] if an encoded value references an invalid index in the value table.
42    pub fn boundary(
43        &self,
44        direction: Direction,
45    ) -> impl Iterator<Item = Result<WireValue<'a>, ReadError>> {
46        let value_table = self.values;
47        let values = match direction {
48            Direction::Incoming => self.region.get_sources(),
49            Direction::Outgoing => self.region.get_targets(),
50        }
51        .expect("Boundary should be present");
52        values.iter().map(move |idx| value_table.get(idx))
53    }
54
55    /// Return an iterator over the source values of this region.
56    ///
57    /// # Errors
58    ///
59    /// - [`ReadError::ValueOutOfBounds`] if an encoded value references an invalid index in the value table.
60    pub fn sources(&self) -> impl Iterator<Item = Result<WireValue<'a>, ReadError>> {
61        self.boundary(Direction::Incoming)
62    }
63
64    /// Return an iterator over the target values of this region.
65    ///
66    /// # Errors
67    ///
68    /// - [`ReadError::ValueOutOfBounds`] if an encoded value references an invalid index in the value table.
69    pub fn targets(&self) -> impl Iterator<Item = Result<WireValue<'a>, ReadError>> {
70        self.boundary(Direction::Outgoing)
71    }
72
73    /// Returns the number of sources or target values in this region.
74    pub fn boundary_count(&self, direction: Direction) -> usize {
75        match direction {
76            Direction::Incoming => self.region.get_sources(),
77            Direction::Outgoing => self.region.get_targets(),
78        }
79        .expect("Boundary should be present")
80        .len() as usize
81    }
82
83    /// Returns the number of source values in this region.
84    pub fn source_count(&self) -> usize {
85        self.boundary_count(Direction::Incoming)
86    }
87
88    /// Returns the number of target values in this region.
89    pub fn target_count(&self) -> usize {
90        self.boundary_count(Direction::Outgoing)
91    }
92
93    /// Returns the boundary value at the given index, or `None` if the index is
94    /// out of bounds.
95    ///
96    /// # Errors
97    ///
98    /// - [`ReadError::ValueOutOfBounds`] if the encoded value references an invalid index in the value table.
99    pub fn boundary_value(
100        &self,
101        direction: Direction,
102        idx: usize,
103    ) -> Option<Result<WireValue<'a>, ReadError>> {
104        let values = match direction {
105            Direction::Incoming => self.region.get_sources(),
106            Direction::Outgoing => self.region.get_targets(),
107        }
108        .expect("Boundary should be present");
109        if idx >= values.len() as usize {
110            return None;
111        }
112        Some(self.values.get(values.get(idx as ValueId)))
113    }
114
115    /// Returns the source value at the given index, or `None` if the index is
116    /// out of bounds.
117    ///
118    /// # Errors
119    ///
120    /// - [`ReadError::ValueOutOfBounds`] if the encoded value references an invalid index in the value table.
121    pub fn source(&self, idx: usize) -> Option<Result<WireValue<'a>, ReadError>> {
122        self.boundary_value(Direction::Incoming, idx)
123    }
124
125    /// Returns the target value at the given index, or `None` if the index is
126    /// out of bounds.
127    ///
128    /// # Errors
129    ///
130    /// - [`ReadError::ValueOutOfBounds`] if the encoded value references an invalid index in the value table.
131    pub fn target(&self, idx: usize) -> Option<Result<WireValue<'a>, ReadError>> {
132        self.boundary_value(Direction::Outgoing, idx)
133    }
134
135    /// Returns an iterator over the operations in this region.
136    pub fn operations(&self) -> impl Iterator<Item = Operation<'a>> {
137        let strings_table = self.strings;
138        let value_table = self.values;
139        self.region
140            .get_operations()
141            .expect("Ops should be present")
142            .iter()
143            .map(move |op| Operation::read_capnp(op, strings_table, value_table))
144    }
145
146    /// Returns the number of operations in this region.
147    pub fn operation_count(&self) -> usize {
148        self.region
149            .get_operations()
150            .expect("Ops should be present")
151            .len() as usize
152    }
153
154    /// Returns the `n`-th operation in this region.
155    ///
156    /// # Panics
157    ///
158    /// Panics if `n` is equal or greater than [`Region::operation_count`].
159    pub fn operation(&self, n: usize) -> Operation<'a> {
160        Operation::read_capnp(
161            self.region
162                .get_operations()
163                .expect("Ops should be present")
164                .get(n as u32),
165            self.strings,
166            self.values,
167        )
168    }
169}
170
171impl<'a> HasMetadataSealed for Region<'a> {
172    fn strings(&self) -> StringTable<'a> {
173        self.strings
174    }
175
176    fn metadata_reader(&self) -> capnp::struct_list::Reader<'a, jeff_capnp::meta::Owned> {
177        self.region
178            .get_metadata()
179            .expect("Metadata should be present")
180    }
181}