hugr_llvm/emit/func/
mailbox.rs1use std::{borrow::Cow, rc::Rc};
2
3use anyhow::{bail, Result};
4use delegate::delegate;
5use inkwell::{
6 builder::Builder,
7 types::{BasicType, BasicTypeEnum},
8 values::{BasicValue, BasicValueEnum, PointerValue},
9};
10use itertools::{zip_eq, Itertools as _};
11
12#[derive(Eq, PartialEq, Clone)]
13pub struct ValueMailBox<'c> {
14 typ: BasicTypeEnum<'c>,
15 ptr: PointerValue<'c>,
16 name: Cow<'static, str>,
17}
18
19fn join_names<'a>(names: impl IntoIterator<Item = &'a str>) -> String {
20 names
21 .into_iter()
22 .filter(|x| !x.is_empty())
23 .join("_")
24 .to_string()
25}
26
27impl<'c> ValueMailBox<'c> {
28 pub(super) fn new(
29 typ: impl BasicType<'c>,
30 ptr: PointerValue<'c>,
31 name: Option<String>,
32 ) -> Self {
33 Self {
34 typ: typ.as_basic_type_enum(),
35 ptr,
36 name: name.map_or(Cow::Borrowed(""), Cow::Owned),
37 }
38 }
39 pub fn get_type(&self) -> BasicTypeEnum<'c> {
40 self.typ
41 }
42
43 pub fn name(&self) -> &str {
44 self.name.as_ref()
45 }
46
47 pub fn promise(&self) -> ValuePromise<'c> {
48 ValuePromise(self.clone())
49 }
50
51 pub fn read<'a>(
52 &'a self,
53 builder: &Builder<'c>,
54 labels: impl IntoIterator<Item = &'a str>,
55 ) -> Result<BasicValueEnum<'c>> {
56 let r = builder.build_load(
57 self.ptr,
58 &join_names(
59 labels
60 .into_iter()
61 .chain(std::iter::once(self.name.as_ref())),
62 ),
63 )?;
64 debug_assert_eq!(r.get_type(), self.get_type());
65 Ok(r)
66 }
67
68 fn write(&self, builder: &Builder<'c>, v: impl BasicValue<'c>) -> Result<()> {
69 builder.build_store(self.ptr, v)?;
70 Ok(())
71 }
72}
73
74#[must_use]
75pub struct ValuePromise<'c>(ValueMailBox<'c>);
76
77impl<'c> ValuePromise<'c> {
78 pub fn finish(self, builder: &Builder<'c>, v: impl BasicValue<'c>) -> Result<()> {
79 self.0.write(builder, v)
80 }
81
82 delegate! {
83 to self.0 {
84 pub fn get_type(&self) -> BasicTypeEnum<'c>;
85 }
86 }
87}
88
89#[derive(Eq, PartialEq, Clone)]
92#[allow(clippy::len_without_is_empty)]
93pub struct RowMailBox<'c>(Rc<Vec<ValueMailBox<'c>>>, Cow<'static, str>);
94
95impl<'c> RowMailBox<'c> {
96 pub fn new_empty() -> Self {
97 Self::new(std::iter::empty(), None)
98 }
99
100 pub(super) fn new(
101 mbs: impl IntoIterator<Item = ValueMailBox<'c>>,
102 name: Option<String>,
103 ) -> Self {
104 Self(
105 Rc::new(mbs.into_iter().collect_vec()),
106 name.map_or(Cow::Borrowed(""), Cow::Owned),
107 )
108 }
109
110 pub fn promise(&self) -> RowPromise<'c> {
112 RowPromise(self.clone())
113 }
114
115 pub fn get_types(&'_ self) -> impl Iterator<Item = BasicTypeEnum<'c>> + '_ {
117 self.0.iter().map(ValueMailBox::get_type)
118 }
119
120 pub fn len(&self) -> usize {
122 self.0.len()
123 }
124
125 pub fn read_vec<'a>(
127 &'a self,
128 builder: &Builder<'c>,
129 labels: impl IntoIterator<Item = &'a str>,
130 ) -> Result<Vec<BasicValueEnum<'c>>> {
131 self.read(builder, labels)
132 }
133
134 pub fn read<'a, R: FromIterator<BasicValueEnum<'c>>>(
136 &'a self,
137 builder: &Builder<'c>,
138 labels: impl IntoIterator<Item = &'a str>,
139 ) -> Result<R> {
140 let labels = labels.into_iter().collect_vec();
141 self.mailboxes()
142 .map(|mb| mb.read(builder, labels.clone()))
143 .collect::<Result<_>>()
144 }
145
146 pub(crate) fn write(
147 &self,
148 builder: &Builder<'c>,
149 vs: impl IntoIterator<Item = BasicValueEnum<'c>>,
150 ) -> Result<()> {
151 let vs = vs.into_iter().collect_vec();
152 #[cfg(debug_assertions)]
153 {
154 let actual_types = vs.clone().into_iter().map(|x| x.get_type()).collect_vec();
155 let expected_types = self.get_types().collect_vec();
156 if actual_types != expected_types {
157 bail!(
158 "RowMailbox::write: Expected types {:?}, got {:?}",
159 expected_types,
160 actual_types
161 );
162 }
163 }
164 zip_eq(self.0.iter(), vs).try_for_each(|(mb, v)| mb.write(builder, v))
165 }
166
167 fn mailboxes(&'_ self) -> impl Iterator<Item = ValueMailBox<'c>> + '_ {
168 self.0.iter().cloned()
169 }
170}
171
172impl<'c> FromIterator<ValueMailBox<'c>> for RowMailBox<'c> {
173 fn from_iter<T: IntoIterator<Item = ValueMailBox<'c>>>(iter: T) -> Self {
174 Self::new(iter, None)
175 }
176}
177
178#[must_use]
180#[allow(clippy::len_without_is_empty)]
181pub struct RowPromise<'c>(RowMailBox<'c>);
182
183impl<'c> RowPromise<'c> {
184 pub fn finish(
186 self,
187 builder: &Builder<'c>,
188 vs: impl IntoIterator<Item = BasicValueEnum<'c>>,
189 ) -> Result<()> {
190 self.0.write(builder, vs)
191 }
192
193 delegate! {
194 to self.0 {
195 pub fn get_types(&'_ self) -> impl Iterator<Item=BasicTypeEnum<'c>> + '_;
197 pub fn len(&self) -> usize;
199 }
200 }
201}