1use std::any::{Any, TypeId};
6use std::cell::RefCell;
7use std::collections::HashMap;
8use std::fmt;
9use std::rc::Rc;
10
11use crate::value::{FromLive, Host, IntoLive, Value};
12
13pub type HostFn = Rc<dyn Fn(Vec<Value>) -> Result<Value, String>>;
16
17type Convert = Rc<dyn Fn(Box<dyn Any>) -> Box<dyn Any>>;
18
19type Method = (Option<TypeId>, HostFn);
21
22pub type FieldGet = Rc<dyn Fn(&Value) -> Result<Value, String>>;
24
25pub type FieldSet = Rc<dyn Fn(&Value, Value) -> Result<(), String>>;
27
28pub type RecordFn = Rc<dyn Fn(Vec<(String, Value)>, Option<Value>) -> Result<Value, String>>;
30
31#[derive(Default)]
33pub struct Registry {
34 functions: HashMap<(String, String), HostFn>,
35 methods: HashMap<(String, String), Vec<Method>>,
36 constants: HashMap<(String, String), Rc<dyn Fn() -> Value>>,
37 free: HashMap<String, HostFn>,
38 conversions: HashMap<(TypeId, TypeId), Convert>,
39 aliases: HashMap<String, String>,
40 names: HashMap<TypeId, &'static str>,
41 fields: HashMap<(String, String), (Option<FieldGet>, Option<FieldSet>)>,
42 records: HashMap<String, RecordFn>,
43}
44
45impl fmt::Debug for Registry {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 f.debug_struct("Registry")
48 .field("functions", &self.functions.len())
49 .field("methods", &self.methods.len())
50 .field("constants", &self.constants.len())
51 .finish_non_exhaustive()
52 }
53}
54
55impl Registry {
56 pub fn new() -> Self {
58 Self::default()
59 }
60
61 pub fn function(
63 &mut self,
64 ty: &str,
65 name: &str,
66 f: impl Fn(Vec<Value>) -> Result<Value, String> + 'static,
67 ) {
68 self.functions.insert((ty.to_owned(), name.to_owned()), Rc::new(f));
69 }
70
71 pub fn method(
73 &mut self,
74 ty: &str,
75 name: &str,
76 f: impl Fn(Vec<Value>) -> Result<Value, String> + 'static,
77 ) {
78 self.methods.entry((ty.to_owned(), name.to_owned())).or_default().push((None, Rc::new(f)));
79 }
80
81 pub fn method_for<T: 'static>(
84 &mut self,
85 ty: &str,
86 name: &str,
87 f: impl Fn(Vec<Value>) -> Result<Value, String> + 'static,
88 ) {
89 let list = self.methods.entry((ty.to_owned(), name.to_owned())).or_default();
90 list.retain(|(id, _)| *id != Some(TypeId::of::<T>()));
91 list.push((Some(TypeId::of::<T>()), Rc::new(f)));
92 }
93
94 pub fn constant(&mut self, ty: &str, name: &str, make: impl Fn() -> Value + 'static) {
96 self.constants.insert((ty.to_owned(), name.to_owned()), Rc::new(make));
97 }
98
99 pub fn free_function(&mut self, name: &str, f: impl Fn(Vec<Value>) -> Result<Value, String> + 'static) {
101 self.free.insert(name.to_owned(), Rc::new(f));
102 }
103
104 pub fn field(&mut self, ty: &str, name: &str, get: impl Fn(&Value) -> Result<Value, String> + 'static) {
106 self.fields.entry((ty.to_owned(), name.to_owned())).or_default().0 = Some(Rc::new(get));
107 }
108
109 pub fn set_field(
111 &mut self,
112 ty: &str,
113 name: &str,
114 set: impl Fn(&Value, Value) -> Result<(), String> + 'static,
115 ) {
116 self.fields.entry((ty.to_owned(), name.to_owned())).or_default().1 = Some(Rc::new(set));
117 }
118
119 pub fn record(
121 &mut self,
122 ty: &str,
123 build: impl Fn(Vec<(String, Value)>, Option<Value>) -> Result<Value, String> + 'static,
124 ) {
125 self.records.insert(ty.to_owned(), Rc::new(build));
126 }
127
128 pub(crate) fn find_field(&self, ty: &str, name: &str) -> Option<FieldGet> {
129 self.fields.get(&(ty.to_owned(), name.to_owned()))?.0.clone()
130 }
131
132 pub(crate) fn find_set_field(&self, ty: &str, name: &str) -> Option<FieldSet> {
133 self.fields.get(&(ty.to_owned(), name.to_owned()))?.1.clone()
134 }
135
136 pub(crate) fn find_record(&self, ty: &str) -> Option<RecordFn> {
137 self.records.get(self.named(ty)).cloned()
138 }
139
140 pub fn name_type<T: 'static>(&mut self, name: &'static str) {
142 self.names.insert(TypeId::of::<T>(), name);
143 }
144
145 pub fn conversion<From: 'static, To: 'static>(&mut self, name: &'static str, convert: fn(From) -> To) {
148 self.name_type::<From>(name);
149 let convert: Convert = Rc::new(move |any: Box<dyn Any>| -> Box<dyn Any> {
150 match any.downcast::<From>() {
151 Ok(value) => Box::new(convert(*value)),
152 Err(other) => other,
153 }
154 });
155 self.conversions.insert((TypeId::of::<From>(), TypeId::of::<To>()), convert);
156 }
157
158 pub fn alias(&mut self, alias: &str, ty: &str) {
160 self.aliases.insert(alias.to_owned(), ty.to_owned());
161 }
162
163 fn named<'a>(&'a self, ty: &'a str) -> &'a str {
164 self.aliases.get(ty).map_or(ty, String::as_str)
165 }
166
167 pub(crate) fn find_function(&self, ty: &str, name: &str) -> Option<HostFn> {
168 self.functions.get(&(self.named(ty).to_owned(), name.to_owned())).cloned()
169 }
170
171 pub(crate) fn find_method(&self, ty: &str, name: &str) -> Option<HostFn> {
172 self.methods.get(&(ty.to_owned(), name.to_owned()))?.first().map(|(_, f)| f.clone())
173 }
174
175 pub(crate) fn find_method_for(&self, ty: &str, name: &str, held: Option<TypeId>) -> Option<HostFn> {
177 let list = self.methods.get(&(ty.to_owned(), name.to_owned()))?;
178 list.iter()
179 .find(|(id, _)| id.is_some() && *id == held)
180 .or_else(|| list.first())
181 .map(|(_, f)| f.clone())
182 }
183
184 pub(crate) fn find_constant(&self, ty: &str, name: &str) -> Option<Value> {
185 self.constants.get(&(self.named(ty).to_owned(), name.to_owned())).map(|make| make())
186 }
187
188 pub(crate) fn find_free(&self, name: &str) -> Option<HostFn> {
189 self.free.get(name).cloned()
190 }
191
192 pub(crate) fn knows_type(&self, ty: &str) -> bool {
194 let ty = self.named(ty);
195 self.functions.keys().chain(self.constants.keys()).any(|(t, _)| t == ty)
196 || self.records.contains_key(ty)
197 }
198
199 fn convert(&self, held: TypeId, target: TypeId) -> Option<Convert> {
200 self.conversions.get(&(held, target)).cloned()
201 }
202}
203
204thread_local! {
205 static CURRENT: RefCell<Option<Rc<Registry>>> = const { RefCell::new(None) };
206}
207
208pub(crate) fn use_registry(registry: Rc<Registry>) {
211 CURRENT.with(|current| *current.borrow_mut() = Some(registry));
212}
213
214fn current() -> Option<Rc<Registry>> {
215 CURRENT.with(|current| current.borrow().clone())
216}
217
218impl Host {
219 pub fn take_as<T: 'static>(&self) -> Result<T, String> {
221 if let Ok(value) = self.take::<T>() {
222 return Ok(value);
223 }
224 let convert = current()
225 .zip(self.held_type())
226 .and_then(|(registry, held)| registry.convert(held, TypeId::of::<T>()))
227 .ok_or_else(|| {
228 format!(
229 "a {} cannot go where a {} goes",
230 self.type_name,
231 crate::value::short(std::any::type_name::<T>())
232 )
233 })?;
234 let boxed = match self.copy {
236 Some(copy) => {
237 let cell = self.cell.borrow();
238 let any = cell.as_ref().ok_or_else(|| format!("this {} was already used", self.type_name))?;
239 copy(any.as_ref())
240 }
241 None => self
242 .cell
243 .borrow_mut()
244 .take()
245 .ok_or_else(|| format!("this {} was already used", self.type_name))?,
246 };
247 convert(boxed)
248 .downcast::<T>()
249 .map(|b| *b)
250 .map_err(|_| format!("a {} did not convert", self.type_name))
251 }
252}
253
254pub trait Fallback {
257 fn fallback() -> Self;
259}
260
261macro_rules! defaults {
262 ($($ty:ty),*) => {$(impl Fallback for $ty { fn fallback() -> Self { <$ty>::default() } })*};
263}
264
265defaults!((), bool, i8, i16, i32, i64, u8, u16, u32, u64, usize, isize, f32, f64, char, String);
266
267impl<T> Fallback for Option<T> {
268 fn fallback() -> Self {
269 None
270 }
271}
272
273impl<T, E: Fallback> Fallback for Result<T, E> {
274 fn fallback() -> Self {
275 Err(E::fallback())
276 }
277}
278
279impl<T> Fallback for Vec<T> {
280 fn fallback() -> Self {
281 Vec::new()
282 }
283}
284
285macro_rules! callbacks {
286 ($(($($arg:ident),*)),*) => {$(
287 impl<$($arg: IntoLive + 'static,)* R: FromLive + Fallback + 'static> FromLive for Box<dyn Fn($($arg),*) -> R> {
288 #[allow(non_snake_case)]
289 fn from_live(value: Value) -> Result<Self, String> {
290 let Value::Closure(closure) = value.read() else {
291 return Err(format!("expected a closure, found {}", value.kind()));
292 };
293 Ok(Box::new(move |$($arg: $arg),*| {
294 let arguments = vec![$($arg.into_live()),*];
295 match closure.call(arguments).and_then(|v| R::from_live(v).map_err(|e| closure.error(e))) {
296 Ok(result) => result,
297 Err(problem) => {
298 crate::value::report(problem);
299 R::fallback()
300 }
301 }
302 }))
303 }
304 }
305 impl<$($arg: IntoLive + 'static,)* R: FromLive + Fallback + 'static> FromLive for Rc<dyn Fn($($arg),*) -> R> {
306 fn from_live(value: Value) -> Result<Self, String> {
307 Box::<dyn Fn($($arg),*) -> R>::from_live(value).map(Rc::from)
308 }
309 }
310 )*};
311}
312
313callbacks!((), (A), (A, B), (A, B, C));
314
315impl<T: FromLive + IntoLive + Clone + 'static> FromLive for ravenrs_reactive::Binding<T> {
316 fn from_live(value: Value) -> Result<Self, String> {
317 let Some(state) = value.as_binding() else {
318 return Err(format!("expected a State or its binding, found {}", value.kind()));
319 };
320 let first = T::from_live(state.get())?;
321 let last = Rc::new(RefCell::new(first));
322 let (read, write, kept) = (state.clone(), state, last.clone());
323 Ok(ravenrs_reactive::Binding::new(
324 move || match T::from_live(read.get()) {
325 Ok(value) => {
326 *last.borrow_mut() = value.clone();
327 value
328 }
329 Err(_) => last.borrow().clone(),
330 },
331 move |value: T| {
332 *kept.borrow_mut() = value.clone();
333 write.set(value.into_live());
334 },
335 ))
336 }
337}