tc_state/object/
instance.rs

1//! User-defined instance implementation.
2
3use std::convert::{TryFrom, TryInto};
4use std::fmt;
5use std::marker::PhantomData;
6use std::ops::Deref;
7
8use log::debug;
9use safecast::TryCastFrom;
10
11use tc_scalar::Scalar;
12use tc_transact::public::ToState;
13use tc_transact::{Gateway, Transaction};
14use tc_value::Value;
15use tcgeneric::Map;
16
17use crate::{CacheBlock, State};
18
19use super::{InstanceClass, Object};
20
21/// A user-defined instance, subclassing `T`.
22pub struct InstanceExt<Txn, T> {
23    parent: Box<T>,
24    class: InstanceClass,
25    members: Map<State<Txn>>,
26    txn: PhantomData<Txn>, // needed to compile when the collection feature flag is off
27}
28
29impl<Txn, T> Clone for InstanceExt<Txn, T>
30where
31    T: Clone,
32{
33    fn clone(&self) -> Self {
34        Self {
35            parent: self.parent.clone(),
36            class: self.class.clone(),
37            members: self.members.clone(),
38            txn: self.txn,
39        }
40    }
41}
42
43impl<Txn, T> InstanceExt<Txn, T>
44where
45    T: tcgeneric::Instance,
46{
47    /// Construct a new instance of the given user-defined [`InstanceClass`].
48    pub fn new(parent: T, class: InstanceClass) -> Self {
49        InstanceExt {
50            parent: Box::new(parent),
51            class,
52            members: Map::default(),
53            txn: PhantomData,
54        }
55    }
56
57    /// Construct a new instance of an anonymous class.
58    pub fn anonymous(parent: T, class: InstanceClass, members: Map<State<Txn>>) -> Self {
59        InstanceExt {
60            parent: Box::new(parent),
61            class,
62            members,
63            txn: PhantomData,
64        }
65    }
66
67    /// Borrow the members of this instance.
68    pub fn members(&self) -> &Map<State<Txn>> {
69        &self.members
70    }
71
72    /// Borrow the parent of this instance.
73    pub fn parent(&self) -> &T {
74        &self.parent
75    }
76
77    /// Borrow the class prototype of this instance.
78    pub fn proto(&self) -> &Map<Scalar> {
79        self.class.proto()
80    }
81
82    /// Convert the native type of this instance, if possible.
83    pub fn try_into<E, O: tcgeneric::Instance + TryFrom<T, Error = E>>(
84        self,
85    ) -> Result<InstanceExt<Txn, O>, E> {
86        let class = self.class;
87        let parent = (*self.parent).try_into()?;
88
89        Ok(InstanceExt {
90            parent: Box::new(parent),
91            class,
92            members: self.members,
93            txn: self.txn,
94        })
95    }
96}
97
98impl<Txn, T> tcgeneric::Instance for InstanceExt<Txn, T>
99where
100    Txn: Send + Sync,
101    T: tcgeneric::Instance,
102{
103    type Class = InstanceClass;
104
105    fn class(&self) -> Self::Class {
106        self.class.clone()
107    }
108}
109
110impl<Txn, T> Deref for InstanceExt<Txn, T>
111where
112    T: tcgeneric::Instance,
113{
114    type Target = T;
115
116    fn deref(&self) -> &Self::Target {
117        &self.parent
118    }
119}
120
121impl<Txn, T> TryCastFrom<InstanceExt<Txn, T>> for Scalar
122where
123    T: fmt::Debug,
124    Scalar: TryCastFrom<T>,
125{
126    fn can_cast_from(instance: &InstanceExt<Txn, T>) -> bool {
127        debug!("Scalar::can_cast_from {:?}?", instance);
128        Self::can_cast_from(&(*instance).parent)
129    }
130
131    fn opt_cast_from(instance: InstanceExt<Txn, T>) -> Option<Self> {
132        Self::opt_cast_from(*instance.parent)
133    }
134}
135
136impl<Txn, T> TryCastFrom<InstanceExt<Txn, T>> for Value
137where
138    T: fmt::Debug,
139    Value: TryCastFrom<T>,
140{
141    fn can_cast_from(instance: &InstanceExt<Txn, T>) -> bool {
142        debug!("Value::can_cast_from {:?}?", instance);
143        Self::can_cast_from(&(*instance).parent)
144    }
145
146    fn opt_cast_from(instance: InstanceExt<Txn, T>) -> Option<Self> {
147        Self::opt_cast_from(*instance.parent)
148    }
149}
150
151impl<Txn, T> ToState<State<Txn>> for InstanceExt<Txn, T>
152where
153    Txn: Transaction<CacheBlock> + Gateway<State<Txn>>,
154    T: tcgeneric::Instance + ToState<State<Txn>>,
155{
156    fn to_state(&self) -> State<Txn> {
157        let instance = InstanceExt {
158            parent: Box::new(self.parent.to_state()),
159            class: self.class.clone(),
160            members: self.members.clone(),
161            txn: self.txn,
162        };
163
164        State::Object(Object::Instance(instance))
165    }
166}
167
168impl<Txn, T> fmt::Debug for InstanceExt<Txn, T> {
169    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
170        write!(f, "instance of {}", std::any::type_name::<T>())
171    }
172}