1use std::fmt;
4use std::ops::Deref;
5
6use async_trait::async_trait;
7use destream::{de, en};
8use get_size::GetSize;
9use get_size_derive::*;
10use safecast::*;
11
12use tc_scalar::*;
13use tc_transact::hash::{Digest, Hash, Output};
14use tc_value::{Link, Value};
15use tcgeneric::{path_label, Map, NativeClass, PathLabel};
16
17use crate::{State, StateType};
18
19use super::ObjectType;
20
21const PATH: PathLabel = path_label(&["state", "class"]);
22
23#[derive(Clone, Default, Eq, PartialEq, GetSize)]
25pub struct InstanceClass {
26 extends: Link,
27 proto: Map<Scalar>,
28}
29
30impl InstanceClass {
31 pub fn new(proto: Map<Scalar>) -> Self {
33 Self {
34 extends: PATH.into(),
35 proto,
36 }
37 }
38
39 pub fn extend<L: Into<Link>>(extends: L, proto: Map<Scalar>) -> Self {
41 Self {
42 extends: extends.into(),
43 proto,
44 }
45 }
46
47 pub fn extends(&self) -> &Link {
49 &self.extends
50 }
51
52 pub fn into_inner(self) -> (Link, Map<Scalar>) {
54 (self.extends, self.proto)
55 }
56
57 pub fn proto(&'_ self) -> &'_ Map<Scalar> {
59 &self.proto
60 }
61}
62
63impl<D: Digest> Hash<D> for InstanceClass {
64 fn hash(self) -> Output<D> {
65 Hash::<D>::hash(&self)
66 }
67}
68
69impl<'a, D: Digest> Hash<D> for &'a InstanceClass {
70 fn hash(self) -> Output<D> {
71 if self.extends == Link::from(PATH) {
72 Hash::<D>::hash(self.proto.deref())
73 } else {
74 Hash::<D>::hash((&self.extends, self.proto.deref()))
75 }
76 }
77}
78
79impl tcgeneric::Class for InstanceClass {}
80
81impl tcgeneric::Instance for InstanceClass {
82 type Class = ObjectType;
83
84 fn class(&self) -> ObjectType {
85 ObjectType::Class
86 }
87}
88
89impl From<StateType> for InstanceClass {
90 fn from(st: StateType) -> Self {
91 Self::extend(st.path(), Map::default())
92 }
93}
94
95impl From<(Link, Map<Scalar>)> for InstanceClass {
96 fn from(class: (Link, Map<Scalar>)) -> Self {
97 let (extends, proto) = class;
98 Self { extends, proto }
99 }
100}
101
102impl CastFrom<Link> for InstanceClass {
103 fn cast_from(extends: Link) -> Self {
104 Self {
105 extends,
106 proto: Map::new(),
107 }
108 }
109}
110
111impl TryCastFrom<PostRef> for InstanceClass {
112 fn can_cast_from(value: &PostRef) -> bool {
113 match value {
114 (Subject::Link(_), _) => true,
115 _ => false,
116 }
117 }
118
119 fn opt_cast_from(value: PostRef) -> Option<Self> {
120 match value {
121 (Subject::Link(extends), proto) => Some(Self { extends, proto }),
122 _ => None,
123 }
124 }
125}
126
127impl TryCastFrom<OpRef> for InstanceClass {
128 fn can_cast_from(op_ref: &OpRef) -> bool {
129 match op_ref {
130 OpRef::Post(op_ref) => Self::can_cast_from(op_ref),
131 _ => false,
132 }
133 }
134
135 fn opt_cast_from(op_ref: OpRef) -> Option<Self> {
136 match op_ref {
137 OpRef::Post(op_ref) => Self::opt_cast_from(op_ref),
138 _ => None,
139 }
140 }
141}
142
143impl TryCastFrom<TCRef> for InstanceClass {
144 fn can_cast_from(tc_ref: &TCRef) -> bool {
145 match tc_ref {
146 TCRef::Op(op_ref) => Self::can_cast_from(op_ref),
147 _ => false,
148 }
149 }
150
151 fn opt_cast_from(tc_ref: TCRef) -> Option<Self> {
152 match tc_ref {
153 TCRef::Op(op_ref) => Self::opt_cast_from(op_ref),
154 _ => None,
155 }
156 }
157}
158
159impl TryCastFrom<Scalar> for InstanceClass {
160 fn can_cast_from(scalar: &Scalar) -> bool {
161 match scalar {
162 Scalar::Ref(tc_ref) => Self::can_cast_from(&**tc_ref),
163 Scalar::Tuple(tuple) => tuple.matches::<(Link, Map<Scalar>)>(),
164 Scalar::Value(value) => Self::can_cast_from(value),
165 _ => false,
166 }
167 }
168
169 fn opt_cast_from(scalar: Scalar) -> Option<Self> {
170 match scalar {
171 Scalar::Ref(tc_ref) => Self::opt_cast_from(*tc_ref),
172 Scalar::Tuple(tuple) => {
173 let (extends, proto) = tuple.opt_cast_into()?;
174 Some(Self::cast_from((extends, proto)))
175 }
176 Scalar::Value(value) => Self::opt_cast_from(value),
177 _ => None,
178 }
179 }
180}
181
182impl CastFrom<InstanceClass> for Scalar {
183 fn cast_from(class: InstanceClass) -> Self {
184 if class.proto.is_empty() {
185 Self::Value(class.extends.into())
186 } else {
187 Self::Ref(Box::new(TCRef::Op(OpRef::Post((
188 class.extends.into(),
189 class.proto,
190 )))))
191 }
192 }
193}
194
195impl<Txn> CastFrom<InstanceClass> for (Link, Map<State<Txn>>) {
196 fn cast_from(class: InstanceClass) -> Self {
197 let proto = class
198 .proto
199 .into_iter()
200 .map(|(key, scalar)| (key, State::Scalar(scalar)))
201 .collect();
202
203 (class.extends, proto)
204 }
205}
206
207impl TryCastFrom<Value> for InstanceClass {
208 fn can_cast_from(value: &Value) -> bool {
209 match value {
210 Value::Link(link) => Self::can_cast_from(link),
211 _ => false,
212 }
213 }
214
215 fn opt_cast_from(value: Value) -> Option<Self> {
216 match value {
217 Value::Link(link) => Self::opt_cast_from(link),
218 _ => None,
219 }
220 }
221}
222
223impl TryCastFrom<InstanceClass> for StateType {
224 fn can_cast_from(class: &InstanceClass) -> bool {
225 if class.proto.is_empty() {
226 if class.extends.host().is_none() {
227 return StateType::from_path(class.extends.path()).is_some();
228 }
229 }
230
231 false
232 }
233
234 fn opt_cast_from(class: InstanceClass) -> Option<Self> {
235 if class.proto.is_empty() {
236 if class.extends.host().is_none() {
237 return StateType::from_path(class.extends.path());
238 }
239 }
240
241 None
242 }
243}
244
245impl TryCastFrom<InstanceClass> for Link {
246 fn can_cast_from(class: &InstanceClass) -> bool {
247 class.proto.is_empty()
248 }
249
250 fn opt_cast_from(class: InstanceClass) -> Option<Self> {
251 if class.proto.is_empty() {
252 Some(class.extends.into())
253 } else {
254 None
255 }
256 }
257}
258
259impl TryCastFrom<InstanceClass> for Value {
260 fn can_cast_from(class: &InstanceClass) -> bool {
261 Link::can_cast_from(class)
262 }
263
264 fn opt_cast_from(class: InstanceClass) -> Option<Self> {
265 Link::opt_cast_from(class).map(Self::Link)
266 }
267}
268
269#[async_trait]
270impl de::FromStream for InstanceClass {
271 type Context = ();
272
273 async fn from_stream<D: de::Decoder>(_: (), decoder: &mut D) -> Result<Self, D::Error> {
274 decoder.decode_map(InstanceClassVisitor).await
275 }
276}
277
278impl<'en> en::ToStream<'en> for InstanceClass {
279 fn to_stream<E: en::Encoder<'en>>(&'en self, encoder: E) -> Result<E::Ok, E::Error> {
280 use en::EncodeMap;
281
282 let mut map = encoder.encode_map(Some(1))?;
283 map.encode_entry(&self.extends, &self.proto)?;
284 map.end()
285 }
286}
287
288impl<'en> en::IntoStream<'en> for InstanceClass {
289 fn into_stream<E: en::Encoder<'en>>(self, encoder: E) -> Result<E::Ok, E::Error> {
290 use en::EncodeMap;
291
292 let mut map = encoder.encode_map(Some(1))?;
293 map.encode_entry(self.extends, self.proto)?;
294 map.end()
295 }
296}
297
298impl fmt::Debug for InstanceClass {
299 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
300 write!(
301 f,
302 "Class which extends {} with prototype {:?}",
303 self.extends, self.proto
304 )
305 }
306}
307
308struct InstanceClassVisitor;
309
310#[async_trait]
311impl de::Visitor for InstanceClassVisitor {
312 type Value = InstanceClass;
313
314 fn expecting() -> &'static str {
315 "a user-defined Class"
316 }
317
318 async fn visit_map<A: de::MapAccess>(self, mut access: A) -> Result<InstanceClass, A::Error> {
319 if let Some(extends) = access.next_key::<Link>(()).await? {
320 log::debug!("Class extends {}", extends);
321 let proto = access.next_value(()).await?;
322 log::debug!("prototype is {:?}", proto);
323 return Ok(InstanceClass::extend(extends, proto));
324 } else {
325 Err(de::Error::invalid_length(0, 1))
326 }
327 }
328}