netidx_bscript/typ/
tval.rs

1use super::Type;
2use crate::{env::Env, Ctx, UserEvent};
3use fxhash::FxHashSet;
4use netidx::publisher::Value;
5use netidx_netproto::value::NakedValue;
6use std::{cell::RefCell, collections::HashSet, fmt};
7
8/// A value with it's type, used for formatting
9pub struct TVal<'a, C: Ctx, E: UserEvent> {
10    pub env: &'a Env<C, E>,
11    pub typ: &'a Type,
12    pub v: &'a Value,
13}
14
15impl<'a, C: Ctx, E: UserEvent> TVal<'a, C, E> {
16    fn fmt_int(
17        &self,
18        f: &mut fmt::Formatter<'_>,
19        hist: &mut FxHashSet<(usize, usize)>,
20    ) -> fmt::Result {
21        if !self.typ.is_a(&self.env, &self.v) {
22            return write!(
23                f,
24                "error, type {} does not match value {}",
25                self.typ,
26                NakedValue(self.v)
27            );
28        }
29        match (&self.typ, &self.v) {
30            (Type::Primitive(_) | Type::Bottom | Type::Fn(_), v) => {
31                write!(f, "{}", NakedValue(v))
32            }
33            (Type::Ref { .. }, v) => match self.typ.lookup_ref(&self.env) {
34                Err(e) => write!(f, "error, {e:?}"),
35                Ok(typ) => {
36                    let typ_addr = (typ as *const Type).addr();
37                    let v_addr = (self.v as *const Value).addr();
38                    if !hist.contains(&(typ_addr, v_addr)) {
39                        hist.insert((typ_addr, v_addr));
40                        Self { typ, env: self.env, v }.fmt_int(f, hist)?
41                    }
42                    Ok(())
43                }
44            },
45            (Type::Array(et), Value::Array(a)) => {
46                write!(f, "[")?;
47                for (i, v) in a.iter().enumerate() {
48                    Self { typ: et, env: self.env, v }.fmt_int(f, hist)?;
49                    if i < a.len() - 1 {
50                        write!(f, ", ")?
51                    }
52                }
53                write!(f, "]")
54            }
55            (Type::Array(_), v) => write!(f, "{}", NakedValue(v)),
56            (Type::ByRef(_), v) => write!(f, "{}", NakedValue(v)),
57            (Type::Struct(flds), Value::Array(a)) => {
58                write!(f, "{{")?;
59                for (i, ((n, et), v)) in flds.iter().zip(a.iter()).enumerate() {
60                    write!(f, "{n}: ")?;
61                    match v {
62                        Value::Array(a) if a.len() == 2 => {
63                            Self { typ: et, env: self.env, v: &a[1] }.fmt_int(f, hist)?
64                        }
65                        _ => write!(f, "err")?,
66                    }
67                    if i < flds.len() - 1 {
68                        write!(f, ", ")?
69                    }
70                }
71                write!(f, "}}")
72            }
73            (Type::Struct(_), v) => write!(f, "{}", NakedValue(v)),
74            (Type::Tuple(flds), Value::Array(a)) => {
75                write!(f, "(")?;
76                for (i, (t, v)) in flds.iter().zip(a.iter()).enumerate() {
77                    Self { typ: t, env: self.env, v }.fmt_int(f, hist)?;
78                    if i < flds.len() - 1 {
79                        write!(f, ", ")?
80                    }
81                }
82                write!(f, ")")
83            }
84            (Type::Tuple(_), v) => write!(f, "{}", NakedValue(v)),
85            (Type::TVar(tv), v) => match &*tv.read().typ.read() {
86                None => write!(f, "{}", NakedValue(v)),
87                Some(typ) => TVal { env: self.env, typ, v }.fmt_int(f, hist),
88            },
89            (Type::Variant(n, flds), Value::Array(a)) if a.len() >= 2 => {
90                write!(f, "`{n}(")?;
91                for (i, (t, v)) in flds.iter().zip(a[1..].iter()).enumerate() {
92                    Self { typ: t, env: self.env, v }.fmt_int(f, hist)?;
93                    if i < flds.len() - 1 {
94                        write!(f, ", ")?
95                    }
96                }
97                write!(f, ")")
98            }
99            (Type::Variant(_, _), Value::String(s)) => write!(f, "`{s}"),
100            (Type::Variant(_, _), v) => write!(f, "{}", NakedValue(v)),
101            (Type::Set(ts), v) => match ts.iter().find(|t| t.is_a(&self.env, v)) {
102                None => write!(f, "{}", NakedValue(v)),
103                Some(t) => Self { typ: t, env: self.env, v }.fmt_int(f, hist),
104            },
105        }
106    }
107}
108
109impl<'a, C: Ctx, E: UserEvent> fmt::Display for TVal<'a, C, E> {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        thread_local! {
112            static HIST: RefCell<FxHashSet<(usize, usize)>> = RefCell::new(HashSet::default());
113        }
114        HIST.with_borrow_mut(|hist| self.fmt_int(f, hist))
115    }
116}