rune/runtime/
dynamic.rs

1use core::borrow::Borrow;
2use core::hash::Hash;
3use core::ops::Deref;
4
5use crate::alloc::{Box, Vec};
6
7use super::{FromValue, Repr, Rtti, RttiKind, RuntimeError, Tuple, TypeInfo, Value};
8
9use rust_alloc::sync::Arc;
10
11/// A reference to a dynamically defined empty type.
12pub struct DynamicEmpty {
13    rtti: Arc<Rtti>,
14}
15
16impl FromValue for DynamicEmpty {
17    #[inline]
18    fn from_value(value: Value) -> Result<Self, RuntimeError> {
19        match value.take_repr() {
20            Repr::Dynamic(value) if matches!(value.rtti().kind, RttiKind::Empty) => Ok(Self {
21                rtti: value.rtti().clone(),
22            }),
23            value => Err(RuntimeError::expected_empty(value.type_info())),
24        }
25    }
26}
27
28impl DynamicEmpty {
29    /// Get human readable type information for the dynamic tuple.
30    pub fn type_info(&self) -> TypeInfo {
31        self.rtti.clone().type_info()
32    }
33}
34
35/// A reference to a dynamically defined tuple.
36///
37/// This derefs into a [`Tuple`], which can be used to access the individual
38/// fields.
39pub struct DynamicTuple {
40    rtti: Arc<Rtti>,
41    values: Vec<Value>,
42}
43
44impl FromValue for DynamicTuple {
45    #[inline]
46    fn from_value(value: Value) -> Result<Self, RuntimeError> {
47        match value.take_repr() {
48            Repr::Dynamic(value) if matches!(value.rtti().kind, RttiKind::Tuple) => {
49                let mut values = Vec::try_with_capacity(value.len())?;
50
51                for value in value.borrow_ref()?.iter() {
52                    values.try_push(value.clone())?;
53                }
54
55                Ok(Self {
56                    rtti: value.rtti().clone(),
57                    values,
58                })
59            }
60            value => Err(RuntimeError::expected_tuple(value.type_info())),
61        }
62    }
63}
64
65impl DynamicTuple {
66    /// Get human readable type information for the dynamic tuple.
67    pub fn type_info(&self) -> TypeInfo {
68        self.rtti.clone().type_info()
69    }
70}
71
72impl Deref for DynamicTuple {
73    type Target = Tuple;
74
75    #[inline]
76    fn deref(&self) -> &Self::Target {
77        Tuple::new(&self.values)
78    }
79}
80
81/// A reference to a dynamically defined struct.
82pub struct DynamicStruct {
83    rtti: Arc<Rtti>,
84    values: Vec<Value>,
85}
86
87impl FromValue for DynamicStruct {
88    #[inline]
89    fn from_value(value: Value) -> Result<Self, RuntimeError> {
90        match value.take_repr() {
91            Repr::Dynamic(value) if matches!(value.rtti().kind, RttiKind::Struct) => {
92                let mut values = Vec::try_with_capacity(value.len())?;
93
94                for value in value.borrow_ref()?.iter() {
95                    values.try_push(value.clone())?;
96                }
97
98                Ok(Self {
99                    rtti: value.rtti().clone(),
100                    values,
101                })
102            }
103            value => Err(RuntimeError::expected_struct(value.type_info())),
104        }
105    }
106}
107
108impl DynamicStruct {
109    /// Get a value from the dynamic struct.
110    pub fn get<Q>(&self, key: &Q) -> Option<&Value>
111    where
112        Box<str>: Borrow<Q>,
113        Q: Hash + Eq + ?Sized,
114    {
115        let index = *self.rtti.fields.get(key)?;
116        self.values.get(index)
117    }
118
119    /// Get human readable type information for the dynamic struct.
120    pub fn type_info(&self) -> TypeInfo {
121        self.rtti.clone().type_info()
122    }
123}