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