compose_library/foundations/cast/
reflect.rs1use crate::repr::separated_list;
2use compose_library::{Type, Value};
3use ecow::{eco_format, EcoString};
4use std::fmt::Write;
5
6pub trait Reflect {
7 fn input() -> CastInfo;
9
10 fn output() -> CastInfo;
12
13 fn castable(value: &Value) -> bool;
15
16 fn error(found: &Value) -> EcoString {
17 Self::input().error(found)
18 }
19}
20
21pub enum CastInfo {
22 Any,
23 Type(Type),
25 Union(Vec<Self>),
26}
27
28impl CastInfo {
29 pub fn error(&self, found: &Value) -> EcoString {
30 let mut parts = vec![];
31
32 self.walk(|info| match info {
33 CastInfo::Any => parts.push("any".into()),
34 CastInfo::Type(ty) => parts.push(eco_format!("{ty}")),
35 CastInfo::Union(_) => {}
36 });
37
38 let mut msg = String::from("expected ");
39
40 msg.push_str(&separated_list(&parts, "or"));
41
42 msg.push_str(", found ");
43 write!(msg, "{}", found.ty()).unwrap();
44
45 msg.into()
46 }
47
48 pub fn walk<F>(&self, mut f: F)
49 where
50 F: FnMut(&Self),
51 {
52 fn inner<F>(info: &CastInfo, f: &mut F)
53 where
54 F: FnMut(&CastInfo),
55 {
56 match info {
57 CastInfo::Union(infos) => {
58 for info in infos {
59 inner(info, f);
60 }
61 }
62 _ => f(info),
63 }
64 }
65
66 inner(self, &mut f);
67 }
68}