Skip to main content

capnp/
dynamic_value.rs

1//! Dynamically typed values.
2
3use crate::introspect::{self, TypeVariant};
4use crate::schema_capnp::value;
5use crate::Result;
6use crate::{dynamic_list, dynamic_struct};
7
8/// A dynamically-typed read-only value.
9#[derive(Clone, Copy)]
10pub enum Reader<'a> {
11    Void,
12    Bool(bool),
13    Int8(i8),
14    Int16(i16),
15    Int32(i32),
16    Int64(i64),
17    UInt8(u8),
18    UInt16(u16),
19    UInt32(u32),
20    UInt64(u64),
21    Float32(f32),
22    Float64(f64),
23    Enum(Enum),
24    Text(crate::text::Reader<'a>),
25    Data(crate::data::Reader<'a>),
26    Struct(dynamic_struct::Reader<'a>),
27    List(dynamic_list::Reader<'a>),
28    AnyPointer(crate::any_pointer::Reader<'a>),
29    Capability(Capability),
30}
31
32impl<'a> Reader<'a> {
33    pub fn new(value: value::Reader<'a>, ty: introspect::Type) -> Result<Self> {
34        match (value.which()?, ty.which()) {
35            (value::Void(()), _) => Ok(Reader::Void),
36            (value::Bool(b), _) => Ok(Reader::Bool(b)),
37            (value::Int8(x), _) => Ok(Reader::Int8(x)),
38            (value::Int16(x), _) => Ok(Reader::Int16(x)),
39            (value::Int32(x), _) => Ok(Reader::Int32(x)),
40            (value::Int64(x), _) => Ok(Reader::Int64(x)),
41            (value::Uint8(x), _) => Ok(Reader::UInt8(x)),
42            (value::Uint16(x), _) => Ok(Reader::UInt16(x)),
43            (value::Uint32(x), _) => Ok(Reader::UInt32(x)),
44            (value::Uint64(x), _) => Ok(Reader::UInt64(x)),
45            (value::Float32(x), _) => Ok(Reader::Float32(x)),
46            (value::Float64(x), _) => Ok(Reader::Float64(x)),
47            (value::Enum(d), TypeVariant::Enum(e)) => Ok(Reader::Enum(Enum::new(d, e.into()))),
48            (value::Text(t), _) => Ok(Reader::Text(t?)),
49            (value::Data(d), _) => Ok(Reader::Data(d?)),
50            (value::Struct(d), TypeVariant::Struct(schema)) => Ok(Reader::Struct(
51                dynamic_struct::Reader::new(d.reader.get_struct(None)?, schema.into()),
52            )),
53            (value::List(l), TypeVariant::List(element_type)) => {
54                Ok(Reader::List(dynamic_list::Reader::new(
55                    l.reader
56                        .get_list(element_type.expected_element_size(), None)?,
57                    element_type,
58                )))
59            }
60            (value::Interface(()), TypeVariant::Capability) => Ok(Capability.into()),
61            (value::AnyPointer(a), TypeVariant::AnyPointer) => Ok(a.into()),
62            _ => Err(crate::Error::from_kind(crate::ErrorKind::TypeMismatch)),
63        }
64    }
65
66    /// Downcasts the `Reader` into a more specific type. Panics if the
67    /// expected type does not match the value.
68    pub fn downcast<T: DowncastReader<'a>>(self) -> T {
69        T::downcast_reader(self)
70    }
71
72    /// Downcasts the `Reader` into a specific struct type. Panics if the
73    /// expected type does not match the value.
74    ///
75    /// Design note: instead of this method, it would be better to add a blanket impl
76    /// of the `DowncastBuilder` trait that covered every struct type. Unfortunately,
77    /// the current way the `Introspect` and `OwnedStruct` traits are set up does not
78    /// seem to allow this.
79    pub fn downcast_struct<T: crate::traits::OwnedStruct>(self) -> T::Reader<'a> {
80        let sr: dynamic_struct::Reader = self.downcast();
81        sr.downcast::<T>()
82    }
83}
84
85impl<'a> From<()> for Reader<'a> {
86    fn from((): ()) -> Reader<'a> {
87        Reader::Void
88    }
89}
90
91macro_rules! primitive_dynamic_value(
92    ($t:ty, $v:ident) => (
93        impl <'a> From<$t> for Reader<'a> {
94            fn from(x: $t) -> Reader<'a> { Reader::$v(x) }
95        }
96    )
97);
98
99primitive_dynamic_value!(bool, Bool);
100primitive_dynamic_value!(i8, Int8);
101primitive_dynamic_value!(i16, Int16);
102primitive_dynamic_value!(i32, Int32);
103primitive_dynamic_value!(i64, Int64);
104primitive_dynamic_value!(u8, UInt8);
105primitive_dynamic_value!(u16, UInt16);
106primitive_dynamic_value!(u32, UInt32);
107primitive_dynamic_value!(u64, UInt64);
108primitive_dynamic_value!(f32, Float32);
109primitive_dynamic_value!(f64, Float64);
110
111/// Helper trait for the `dynamic_value::Reader::downcast()` method.
112pub trait DowncastReader<'a> {
113    fn downcast_reader(v: Reader<'a>) -> Self;
114}
115
116impl<'a> DowncastReader<'a> for () {
117    fn downcast_reader(value: Reader<'a>) {
118        let Reader::Void = value else {
119            panic!("error downcasting to void")
120        };
121    }
122}
123
124macro_rules! downcast_reader_impl(
125    ($t:ty, $v:ident, $s:expr) => (
126        impl <'a> DowncastReader<'a> for $t {
127            fn downcast_reader(value: Reader<'a>) -> Self {
128                let Reader::$v(x) = value else { panic!("error downcasting to {}", $s) };
129                x
130            }
131        }
132    )
133);
134
135downcast_reader_impl!(bool, Bool, "bool");
136downcast_reader_impl!(i8, Int8, "i8");
137downcast_reader_impl!(i16, Int16, "i16");
138downcast_reader_impl!(i32, Int32, "i32");
139downcast_reader_impl!(i64, Int64, "i64");
140downcast_reader_impl!(u8, UInt8, "u8");
141downcast_reader_impl!(u16, UInt16, "u16");
142downcast_reader_impl!(u32, UInt32, "u32");
143downcast_reader_impl!(u64, UInt64, "u64");
144downcast_reader_impl!(f32, Float32, "f32");
145downcast_reader_impl!(f64, Float64, "f64");
146downcast_reader_impl!(Enum, Enum, "enum");
147downcast_reader_impl!(crate::text::Reader<'a>, Text, "text");
148downcast_reader_impl!(crate::data::Reader<'a>, Data, "data");
149downcast_reader_impl!(dynamic_list::Reader<'a>, List, "list");
150downcast_reader_impl!(dynamic_struct::Reader<'a>, Struct, "struct");
151downcast_reader_impl!(crate::any_pointer::Reader<'a>, AnyPointer, "anypointer");
152
153/// A dynamically-typed value with mutable interior.
154pub enum Builder<'a> {
155    Void,
156    Bool(bool),
157    Int8(i8),
158    Int16(i16),
159    Int32(i32),
160    Int64(i64),
161    UInt8(u8),
162    UInt16(u16),
163    UInt32(u32),
164    UInt64(u64),
165    Float32(f32),
166    Float64(f64),
167    Enum(Enum),
168    Text(crate::text::Builder<'a>),
169    Data(crate::data::Builder<'a>),
170    Struct(dynamic_struct::Builder<'a>),
171    List(dynamic_list::Builder<'a>),
172    AnyPointer(crate::any_pointer::Builder<'a>),
173    Capability(Capability),
174}
175
176impl<'a> Builder<'a> {
177    pub fn reborrow(&mut self) -> Builder<'_> {
178        match self {
179            Builder::Void => Builder::Void,
180            Builder::Bool(b) => Builder::Bool(*b),
181            Builder::Int8(x) => Builder::Int8(*x),
182            Builder::Int16(x) => Builder::Int16(*x),
183            Builder::Int32(x) => Builder::Int32(*x),
184            Builder::Int64(x) => Builder::Int64(*x),
185            Builder::UInt8(x) => Builder::UInt8(*x),
186            Builder::UInt16(x) => Builder::UInt16(*x),
187            Builder::UInt32(x) => Builder::UInt32(*x),
188            Builder::UInt64(x) => Builder::UInt64(*x),
189            Builder::Float32(x) => Builder::Float32(*x),
190            Builder::Float64(x) => Builder::Float64(*x),
191            Builder::Enum(e) => Builder::Enum(*e),
192            Builder::Text(t) => Builder::Text(t.reborrow()),
193            Builder::Data(d) => Builder::Data(d),
194            Builder::Struct(ref mut s) => Builder::Struct(s.reborrow()),
195            Builder::List(ref mut l) => Builder::List(l.reborrow()),
196            Builder::AnyPointer(ref mut a) => Builder::AnyPointer(a.reborrow()),
197            Builder::Capability(c) => Builder::Capability(*c),
198        }
199    }
200
201    pub fn into_reader(self) -> Reader<'a> {
202        match self {
203            Builder::Void => Reader::Void,
204            Builder::Bool(b) => Reader::Bool(b),
205            Builder::Int8(x) => Reader::Int8(x),
206            Builder::Int16(x) => Reader::Int16(x),
207            Builder::Int32(x) => Reader::Int32(x),
208            Builder::Int64(x) => Reader::Int64(x),
209            Builder::UInt8(x) => Reader::UInt8(x),
210            Builder::UInt16(x) => Reader::UInt16(x),
211            Builder::UInt32(x) => Reader::UInt32(x),
212            Builder::UInt64(x) => Reader::UInt64(x),
213            Builder::Float32(x) => Reader::Float32(x),
214            Builder::Float64(x) => Reader::Float64(x),
215            Builder::Enum(e) => Reader::Enum(e),
216            Builder::Text(t) => Reader::Text(t.into_reader()),
217            Builder::Data(d) => Reader::Data(d),
218            Builder::Struct(s) => Reader::Struct(s.into_reader()),
219            Builder::List(l) => Reader::List(l.into_reader()),
220            Builder::AnyPointer(a) => Reader::AnyPointer(a.into_reader()),
221            Builder::Capability(c) => Reader::Capability(c),
222        }
223    }
224
225    /// Downcasts the `Builder` into a more specific type. Panics if the
226    /// expected type does not match the value.
227    pub fn downcast<T: DowncastBuilder<'a>>(self) -> T {
228        T::downcast_builder(self)
229    }
230
231    /// Downcasts the `Builder` into a specific struct type. Panics if the
232    /// expected type does not match the value.
233    ///
234    /// Design note: instead of this method, it would be better to add a blanket impl
235    /// of the `DowncastBuilder` trait that covered every struct type. Unfortunately,
236    /// the current way the `Introspect` and `OwnedStruct` traits are set up does not
237    /// seem to allow this.
238    pub fn downcast_struct<T: crate::traits::OwnedStruct>(self) -> T::Builder<'a> {
239        let sb: dynamic_struct::Builder = self.downcast();
240        sb.downcast::<T>()
241    }
242}
243
244/// Helper trait for the `dynamic_value::Builder::downcast()` method.
245pub trait DowncastBuilder<'a> {
246    fn downcast_builder(v: Builder<'a>) -> Self;
247}
248
249impl<'a> DowncastBuilder<'a> for () {
250    fn downcast_builder(value: Builder<'a>) {
251        let Builder::Void = value else {
252            panic!("error downcasting to void")
253        };
254    }
255}
256
257macro_rules! downcast_builder_impl(
258    ($t:ty, $v:ident, $s:expr) => (
259        impl <'a> DowncastBuilder<'a> for $t {
260            fn downcast_builder(value: Builder<'a>) -> Self {
261                let Builder::$v(x) = value else { panic!("error downcasting to {}", $s) };
262                x
263            }
264        }
265    )
266);
267
268downcast_builder_impl!(bool, Bool, "bool");
269downcast_builder_impl!(i8, Int8, "i8");
270downcast_builder_impl!(i16, Int16, "i16");
271downcast_builder_impl!(i32, Int32, "i32");
272downcast_builder_impl!(i64, Int64, "i64");
273downcast_builder_impl!(u8, UInt8, "u8");
274downcast_builder_impl!(u16, UInt16, "u16");
275downcast_builder_impl!(u32, UInt32, "u32");
276downcast_builder_impl!(u64, UInt64, "u64");
277downcast_builder_impl!(f32, Float32, "f32");
278downcast_builder_impl!(f64, Float64, "f64");
279downcast_builder_impl!(Enum, Enum, "enum");
280downcast_builder_impl!(crate::text::Builder<'a>, Text, "text");
281downcast_builder_impl!(crate::data::Builder<'a>, Data, "data");
282downcast_builder_impl!(dynamic_list::Builder<'a>, List, "list");
283downcast_builder_impl!(dynamic_struct::Builder<'a>, Struct, "struct");
284downcast_builder_impl!(crate::any_pointer::Builder<'a>, AnyPointer, "anypointer");
285
286/// A dynamically-typed enum value.
287#[derive(Clone, Copy)]
288pub struct Enum {
289    value: u16,
290    schema: crate::schema::EnumSchema,
291}
292
293impl Enum {
294    pub fn new(value: u16, schema: crate::schema::EnumSchema) -> Self {
295        Self { value, schema }
296    }
297
298    /// Gets the u16 representation of this value.
299    pub fn get_value(&self) -> u16 {
300        self.value
301    }
302
303    /// Gets the schema of this enumerant.
304    pub fn get_enumerant(self) -> crate::Result<Option<crate::schema::Enumerant>> {
305        let enumerants = self.schema.get_enumerants()?;
306        if (self.value) < enumerants.len() {
307            Ok(Some(enumerants.get(self.value)))
308        } else {
309            Ok(None)
310        }
311    }
312}
313
314impl<'a> From<Enum> for Reader<'a> {
315    fn from(e: Enum) -> Reader<'a> {
316        Reader::Enum(e)
317    }
318}
319
320impl<'a> From<Enum> for Builder<'a> {
321    fn from(e: Enum) -> Builder<'a> {
322        Builder::Enum(e)
323    }
324}
325
326/// A dynamic capability. Currently, this is just a stub and does not support calling
327/// of methods.
328#[derive(Clone, Copy)]
329pub struct Capability;
330
331impl<'a> From<Capability> for Reader<'a> {
332    fn from(c: Capability) -> Reader<'a> {
333        Reader::Capability(c)
334    }
335}
336
337impl<'a> From<Capability> for Builder<'a> {
338    fn from(c: Capability) -> Builder<'a> {
339        Builder::Capability(c)
340    }
341}