markdown_it/parser/
extset.rs1use downcast_rs::{impl_downcast, Downcast};
6use std::fmt::Debug;
7
8pub trait MarkdownItExt : Debug + Downcast + Send + Sync {}
10impl_downcast!(MarkdownItExt);
11extension_set!(MarkdownItExtSet, MarkdownItExt);
12
13pub trait NodeExt : Debug + Downcast + Send + Sync {}
15impl_downcast!(NodeExt);
16extension_set!(NodeExtSet, NodeExt);
17
18pub trait InlineRootExt : Debug + Downcast + Send + Sync {}
20impl_downcast!(InlineRootExt);
21extension_set!(InlineRootExtSet, InlineRootExt);
22
23pub trait RootExt : Debug + Downcast + Send + Sync {}
25impl_downcast!(RootExt);
26extension_set!(RootExtSet, RootExt);
27
28pub trait RenderExt : Debug + Downcast + Send + Sync {}
30impl_downcast!(RenderExt);
31extension_set!(RenderExtSet, RenderExt);
32
33macro_rules! extension_set {
36 ($name: ident, $trait: ident) => {
37 #[derive(Debug, Default)]
38 pub struct $name(::std::collections::HashMap<crate::common::TypeKey, Box<dyn $trait>>);
39
40 impl $name {
41 #[must_use]
42 pub fn new() -> Self {
43 Self::default()
44 }
45
46 #[must_use]
47 pub fn is_empty(&self) -> bool {
48 self.0.is_empty()
49 }
50
51 #[must_use]
52 pub fn len(&self) -> usize {
53 self.0.len()
54 }
55
56 pub fn clear(&mut self) {
57 self.0.clear();
58 }
59
60 #[must_use]
61 pub fn contains<T: 'static>(&self) -> bool {
62 let key = crate::common::TypeKey::of::<T>();
63 self.0.contains_key(&key)
64 }
65
66 #[must_use]
67 pub fn get<T: $trait>(&self) -> Option<&T> {
68 let key = crate::common::TypeKey::of::<T>();
69 let result = self.0.get(&key)?;
70 result.downcast_ref::<T>()
71 }
72
73 #[must_use]
74 pub fn get_mut<T: $trait>(&mut self) -> Option<&mut T> {
75 let key = crate::common::TypeKey::of::<T>();
76 let result = self.0.get_mut(&key)?;
77 result.downcast_mut::<T>()
78 }
79
80 pub fn get_or_insert<T: $trait>(&mut self, value: T) -> &mut T {
81 let key = crate::common::TypeKey::of::<T>();
82 let result = self.0.entry(key).or_insert_with(|| Box::new(value));
83 result.downcast_mut::<T>().unwrap()
84 }
85
86 pub fn get_or_insert_with<T: $trait>(&mut self, f: impl FnOnce() -> T) -> &mut T {
87 let key = crate::common::TypeKey::of::<T>();
88 let result = self.0.entry(key).or_insert_with(|| Box::new(f()));
89 result.downcast_mut::<T>().unwrap()
90 }
91
92 pub fn get_or_insert_default<T: $trait + Default>(&mut self) -> &mut T {
93 let key = crate::common::TypeKey::of::<T>();
94 let result = self.0.entry(key).or_insert_with(|| Box::<T>::default());
95 result.downcast_mut::<T>().unwrap()
96 }
97
98 pub fn insert<T: $trait>(&mut self, value: T) -> Option<T> {
99 let key = crate::common::TypeKey::of::<T>();
100 let result = self.0.insert(key, Box::new(value))?;
101 Some(*result.downcast::<T>().unwrap())
102 }
103
104 pub fn remove<T: $trait>(&mut self) -> Option<T> {
105 let key = crate::common::TypeKey::of::<T>();
106 let result = self.0.remove(&key)?;
107 Some(*result.downcast::<T>().unwrap())
108 }
109 }
110 }
111}
112
113pub(crate) use extension_set;
114
115#[cfg(test)]
116mod tests {
117 use downcast_rs::{Downcast, impl_downcast};
118 use std::fmt::Debug;
119
120 pub trait TestExt : Debug + Downcast + Send + Sync {}
121 impl_downcast!(TestExt);
122
123 extension_set!(TestExtSet, TestExt);
124
125 impl<T: Debug + Downcast + Send + Sync> TestExt for T {}
126
127 #[test]
128 fn empty_set() {
129 let set = TestExtSet::new();
130 assert_eq!(set.len(), 0);
131 assert!(set.is_empty());
132 }
133
134 #[test]
135 fn insert_elements() {
136 let mut set = TestExtSet::new();
137 set.insert(42u8);
138 assert_eq!(set.len(), 1);
139 assert!(!set.is_empty());
140 set.insert(42u16);
141 assert_eq!(set.len(), 2);
142 assert!(!set.is_empty());
143 }
144
145 #[test]
146 fn contains() {
147 let mut set = TestExtSet::new();
148 set.insert(42u8);
149 assert!(!set.contains::<u16>());
150 set.insert(42u16);
151 assert!(set.contains::<u16>());
152 set.remove::<u16>();
153 assert!(!set.contains::<u16>());
154 }
155
156 #[test]
157 fn get() {
158 let mut set = TestExtSet::new();
159 set.insert(42u8);
160 assert_eq!(set.get::<u16>(), None);
161 set.insert(42u16);
162 set.insert(123u16);
163 assert_eq!(set.get::<u16>(), Some(&123u16));
164 }
165
166 #[test]
167 fn get_mut() {
168 let mut set = TestExtSet::new();
169 set.insert(42u16);
170 *set.get_mut::<u16>().unwrap() = 123u16;
171 assert_eq!(set.get::<u16>(), Some(&123u16));
172 }
173
174 #[test]
175 fn or_insert() {
176 let mut set = TestExtSet::new();
177 set.insert(123u8);
178 assert_eq!(set.get_or_insert(0u8), &mut 123u8);
179 assert_eq!(set.get_or_insert_default::<u8>(), &mut 123u8);
180 assert_eq!(set.get_or_insert_with(|| 0u8), &mut 123u8);
181 set.clear();
182 assert_eq!(set.get_or_insert(10u8), &mut 10u8);
183 set.clear();
184 assert_eq!(set.get_or_insert_with(|| 20u8), &mut 20u8);
185 set.clear();
186 assert_eq!(set.get_or_insert_default::<u8>(), &mut 0u8);
187 }
188
189 #[test]
190 fn different_types_stored_once() {
191 let mut set = TestExtSet::new();
192 set.insert("foo");
193 set.insert("bar");
194 set.insert("quux");
195 assert_eq!(set.len(), 1);
196 }
197
198 #[test]
199 fn zero_sized_types() {
200 #[derive(Debug, PartialEq, Eq)]
201 struct A;
202 #[derive(Debug, PartialEq, Eq)]
203 struct B;
204 let mut set = TestExtSet::new();
205 set.insert(A);
206 set.insert(B);
207 assert_eq!(set.len(), 2);
208 assert_eq!(set.get::<A>(), Some(&A));
209 }
210
211 #[test]
212 fn clear() {
213 let mut set = TestExtSet::new();
214 set.insert(42u8);
215 set.insert(42u16);
216 assert_eq!(set.len(), 2);
217 set.clear();
218 assert_eq!(set.len(), 0);
219 }
220
221 #[test]
222 fn debug() {
223 let mut set = TestExtSet::new();
224 set.insert(42);
225 set.insert("test");
226 let str = format!("{:?}", set);
227 assert!(str == "TestExtSet({i32: 42, &str: \"test\"})" ||
229 str == "TestExtSet({&str: \"test\", i32: 42})");
230 }
231}