1use crate::reader::value::{ValueTable, WireValue};
4use crate::types::Type;
5use crate::{jeff_capnp, Direction};
6
7use super::metadata::sealed::HasMetadataSealed;
8use super::optype::OpType;
9use super::string_table::StringTable;
10use super::value::ValueId;
11use super::ReadError;
12
13#[derive(Clone, Copy, Debug)]
15pub struct Operation<'a> {
16 op: jeff_capnp::op::Reader<'a>,
18 strings: StringTable<'a>,
20 values: ValueTable<'a>,
22}
23
24impl<'a> Operation<'a> {
25 pub(crate) fn read_capnp(
27 operation: jeff_capnp::op::Reader<'a>,
28 strings: StringTable<'a>,
29 values: ValueTable<'a>,
30 ) -> Self {
31 Self {
32 op: operation,
33 strings,
34 values,
35 }
36 }
37
38 pub fn op_type(&self) -> OpType<'a> {
40 OpType::read_capnp(self.op.get_instruction(), self.strings, self.values)
41 }
42
43 pub fn boundary(
49 &self,
50 direction: Direction,
51 ) -> impl Iterator<Item = Result<WireValue<'a>, ReadError>> {
52 let value_table = self.values;
53 let values = match direction {
54 Direction::Incoming => self.op.get_inputs(),
55 Direction::Outgoing => self.op.get_outputs(),
56 }
57 .expect("Boundary should be present");
58 values.iter().map(move |idx| value_table.get(idx))
59 }
60
61 pub fn inputs(&self) -> impl Iterator<Item = Result<WireValue<'a>, ReadError>> {
67 self.boundary(Direction::Incoming)
68 }
69
70 pub fn outputs(&self) -> impl Iterator<Item = Result<WireValue<'a>, ReadError>> {
76 self.boundary(Direction::Outgoing)
77 }
78
79 pub fn boundary_count(&self, direction: Direction) -> usize {
81 match direction {
82 Direction::Incoming => self.op.get_inputs(),
83 Direction::Outgoing => self.op.get_outputs(),
84 }
85 .expect("Boundary should be present")
86 .len() as usize
87 }
88
89 pub fn input_count(&self) -> usize {
91 self.boundary_count(Direction::Incoming)
92 }
93
94 pub fn output_count(&self) -> usize {
96 self.boundary_count(Direction::Outgoing)
97 }
98
99 pub fn boundary_value(
106 &self,
107 direction: Direction,
108 idx: usize,
109 ) -> Option<Result<WireValue<'a>, ReadError>> {
110 let values = match direction {
111 Direction::Incoming => self.op.get_inputs(),
112 Direction::Outgoing => self.op.get_outputs(),
113 }
114 .expect("Boundary should be present");
115 if idx >= values.len() as usize {
116 return None;
117 }
118 let value_id: ValueId = values.get(idx as u32);
119 Some(self.values.get(value_id))
120 }
121
122 pub fn input(&self, idx: usize) -> Option<Result<WireValue<'a>, ReadError>> {
129 self.boundary_value(Direction::Incoming, idx)
130 }
131
132 pub fn output(&self, idx: usize) -> Option<Result<WireValue<'a>, ReadError>> {
139 self.boundary_value(Direction::Outgoing, idx)
140 }
141
142 pub fn input_types(&self) -> impl Iterator<Item = Result<Type, ReadError>> + 'a {
144 self.inputs().map(move |res| res.map(|t| t.ty()))
145 }
146
147 pub fn output_types(&self) -> impl Iterator<Item = Result<Type, ReadError>> + 'a {
149 self.outputs().map(move |res| res.map(|t| t.ty()))
150 }
151}
152
153impl<'a> HasMetadataSealed for Operation<'a> {
154 fn strings(&self) -> StringTable<'a> {
155 self.strings
156 }
157
158 fn metadata_reader(&self) -> capnp::struct_list::Reader<'a, jeff_capnp::meta::Owned> {
159 self.op.get_metadata().expect("Metadata should be present")
160 }
161}