tc_transact/public/
value.rs1use safecast::TryCastFrom;
2use std::sync::Arc;
3
4use tc_error::*;
5use tc_value::uuid::Uuid;
6use tc_value::{Number, TCString, Value, ValueType};
7use tcgeneric::{label, Id, Label, Map, PathSegment, Tuple};
8
9use super::helpers::SelfHandler;
10use super::{ClosureInstance, GetHandler, Handler, Route, StateInstance};
11
12pub const PREFIX: Label = label("value");
13
14struct EqHandler<F> {
15 call: F,
16}
17
18impl<'a, State, F> Handler<'a, State> for EqHandler<F>
19where
20 State: StateInstance,
21 F: FnOnce(Value) -> bool + Send + 'a,
22{
23 fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, State::Txn, State>>
24 where
25 'b: 'a,
26 {
27 Some(Box::new(|_txn, key| {
28 Box::pin(async move { Ok(Value::from((self.call)(key)).into()) })
29 }))
30 }
31}
32
33impl<F> From<F> for EqHandler<F> {
34 fn from(call: F) -> Self {
35 Self { call }
36 }
37}
38
39impl<State> Route<State> for Value
40where
41 State: StateInstance + From<Value> + From<Tuple<Value>>,
42 Box<dyn ClosureInstance<State>>: TryCastFrom<State>,
43 Id: TryCastFrom<State>,
44 Map<State>: TryFrom<State, Error = TCError>,
45 Number: TryCastFrom<State>,
46 TCString: TryCastFrom<State>,
47 Tuple<State>: TryCastFrom<State>,
48 Value: TryCastFrom<State>,
49{
50 fn route<'a>(&'a self, path: &'a [PathSegment]) -> Option<Box<dyn Handler<'a, State> + 'a>> {
51 let child_handler = match self {
52 Self::Number(number) => number.route(path),
53 Self::String(s) => s.route(path),
54 Self::Tuple(tuple) => tuple.route(path),
55 _ => None,
56 };
57
58 if child_handler.is_some() {
59 child_handler
60 } else if path.len() == 1 {
61 match path[0].as_str() {
62 "eq" => Some(Box::new(EqHandler::from(move |other| self == &other))),
63 "ne" => Some(Box::new(EqHandler::from(move |other| self != &other))),
64 _ => None,
65 }
66 } else if path.is_empty() {
67 Some(Box::new(SelfHandler::from(self)))
68 } else {
69 None
70 }
71 }
72}
73
74struct UuidHandler<'a> {
75 dtype: &'a str,
76}
77
78impl<'a, State: StateInstance> Handler<'a, State> for UuidHandler<'a> {
79 fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, State::Txn, State>>
80 where
81 'b: 'a,
82 {
83 Some(Box::new(|_txn, key| {
84 Box::pin(async move {
85 let uuid = if key.is_some() {
86 Uuid::try_cast_from(key, |v| TCError::unexpected(v, "a UUID"))?
87 } else {
88 return Err(bad_request!("missing UUID to cast into {}", self.dtype));
89 };
90
91 let value = match self.dtype {
92 "bytes" => Value::Bytes(Arc::new(uuid.into_bytes())),
93 "id" => Value::Id(uuid.into()),
94 "string" => Value::String(uuid.to_string().into()),
95 other => {
96 return Err(TCError::not_found(format!("{} in {}", other, self.dtype)))
97 }
98 };
99
100 Ok(State::from(value))
101 })
102 }))
103 }
104}
105
106struct StaticHandler {
107 class: ValueType,
108}
109
110impl<'a, State: StateInstance> Handler<'a, State> for StaticHandler {
111 fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, State::Txn, State>>
112 where
113 'b: 'a,
114 {
115 Some(Box::new(|_txn, key| {
116 Box::pin(async move { self.class.try_cast(key).map(State::from) })
117 }))
118 }
119}
120
121impl<'a> From<ValueType> for StaticHandler {
122 fn from(class: ValueType) -> Self {
123 Self { class }
124 }
125}
126
127pub struct Static;
128
129impl<State: StateInstance> Route<State> for Static {
130 fn route<'a>(&'a self, path: &'a [PathSegment]) -> Option<Box<dyn Handler<'a, State> + 'a>> {
131 if let Some(class) = ValueType::from_suffix(path) {
132 return Some(Box::new(StaticHandler::from(class)));
133 }
134
135 assert!(
136 !path.is_empty(),
137 "failed to parse ValueType::Value from an empty path"
138 );
139
140 match path[0].as_str() {
141 "bytes" | "id" | "string" if path.len() == 2 => match path[1].as_str() {
142 "uuid" => Some(Box::new(UuidHandler {
143 dtype: path[0].as_str(),
144 })),
145 _ => None,
146 },
147 _ => None,
148 }
149 }
150}