1use std::fmt;
2
3pub trait Context: Default + Clone + fmt::Display + fmt::Debug + Send + Sync + 'static {
10 fn update(self, replacements: Self) -> Self;
12
13 fn is_empty(&self) -> bool;
15}
16
17#[derive(Default, Copy, Clone, Debug)]
19pub struct NoContext;
20
21impl fmt::Display for NoContext {
22 fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 Ok(())
24 }
25}
26
27impl Context for NoContext {
28 fn update(self, _replacements: Self) -> Self {
29 self
30 }
31
32 fn is_empty(&self) -> bool {
33 true
34 }
35}
36
37#[derive(Default, Clone, Debug)]
44pub struct AdhocContext {
45 data: indexmap::IndexMap<&'static str, Box<dyn AdhocValue>>,
46}
47
48impl AdhocContext {
49 pub fn new() -> Self {
51 Default::default()
52 }
53
54 pub fn insert<V>(mut self, key: &'static str, value: V) -> Self
68 where
69 V: AdhocValue + Clone,
70 {
71 self.data.insert(key, Box::new(value));
72 self
73 }
74}
75
76impl fmt::Display for AdhocContext {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 for (k, v) in self.data.iter() {
79 writeln!(f, "{}: {}", k, v)?;
80 }
81 Ok(())
82 }
83}
84
85impl Context for AdhocContext {
86 fn update(mut self, replacements: Self) -> Self {
87 self.data.extend(replacements.data);
88 self
89 }
90
91 fn is_empty(&self) -> bool {
92 self.data.is_empty()
93 }
94}
95
96pub trait AdhocValue: fmt::Display + fmt::Debug + Send + Sync + 'static {
98 fn clone_box(&self) -> Box<dyn AdhocValue>;
100}
101
102impl<V> AdhocValue for V
103where
104 V: Clone + fmt::Display + fmt::Debug + Send + Sync + 'static,
105{
106 fn clone_box(&self) -> Box<dyn AdhocValue> {
107 Box::new(self.clone())
108 }
109}
110
111impl Clone for Box<dyn AdhocValue> {
112 fn clone(&self) -> Box<dyn AdhocValue> {
113 self.clone_box()
114 }
115}
116
117#[cfg(test)]
118mod test {
119 use super::*;
120
121 use static_assertions::*;
122
123 #[test]
124 fn no_context() {
125 assert_impl_all!(
126 NoContext: Default,
127 Copy,
128 Clone,
129 fmt::Debug,
130 fmt::Display,
131 Context
132 );
133 }
134
135 #[test]
136 fn adhoc_context() {
137 assert_impl_all!(NoContext: Default, Clone, fmt::Debug, fmt::Display, Context);
138 }
139}