1use std::{fmt::Display, marker::PhantomData};
18
19use crate::{
20 context::FileReader,
21 data::{DataMap, RoData, RwData},
22 mode::Cursors,
23 text::{Builder, Tag, Text, text},
24 ui::Ui,
25 widgets::{File, Widget},
26};
27
28enum Appender<T> {
30 NoArgs(Box<dyn FnMut() -> Append + Send + Sync + 'static>),
31 FromWidget(RelatedFn<T>),
32 FromFileAndWidget(FileAndRelatedFn<T>),
33 FromCursors(RelatedFn<Cursors>),
34 Str(String),
35 Text(Text),
36}
37
38pub struct State<T: 'static, Dummy, U> {
47 appender: Appender<T>,
48 checker: Option<Box<dyn Fn() -> bool + Send + Sync>>,
49 ghost: PhantomData<(Dummy, U)>,
50}
51
52impl<T: 'static, Dummy, U: Ui> State<T, Dummy, U> {
53 pub fn fns(self) -> (ReaderFn<U>, Box<dyn Fn() -> bool + Send + Sync>) {
54 (
55 match self.appender {
56 Appender::NoArgs(mut f) => Box::new(move |builder, _| f().push_to(builder)),
57 Appender::FromWidget(mut f) => Box::new(move |builder, reader| {
58 if let Some(append) = reader.inspect_related(&mut f) {
59 append.push_to(builder)
60 }
61 }),
62 Appender::FromFileAndWidget(mut f) => Box::new(move |builder, reader| {
63 if let Some(append) = reader.inspect_file_and(|file, widget| f(file, widget)) {
64 append.push_to(builder)
65 }
66 }),
67 Appender::FromCursors(mut f) => Box::new(move |builder, reader| {
68 reader
69 .inspect(|file, _| f(file.cursors().unwrap()))
70 .push_to(builder);
71 }),
72 Appender::Str(str) => Box::new(move |builder, _| {
73 if !(str == " " && builder.last_was_empty()) {
74 builder.push_str(&str)
75 }
76 }),
77 Appender::Text(text) => Box::new(move |builder, _| builder.push_text(text.clone())),
78 },
79 Box::new(move || self.checker.as_ref().is_some_and(|check| check())),
80 )
81 }
82}
83
84impl<D: Display + Send + Sync, U: Ui> From<D> for State<(), String, U> {
85 fn from(value: D) -> Self {
86 Self {
87 appender: Appender::Str::<()>(value.to_string()),
88 checker: None,
89 ghost: PhantomData,
90 }
91 }
92}
93
94impl<U: Ui> From<Text> for State<(), Text, U> {
95 fn from(value: Text) -> Self {
96 Self {
97 appender: Appender::Text::<()>(value),
98 checker: None,
99 ghost: PhantomData,
100 }
101 }
102}
103
104impl<U: Ui> From<Tag> for State<(), Tag, U> {
105 fn from(value: Tag) -> Self {
106 Self {
107 appender: Appender::Text::<()>(text!(value)),
108 checker: None,
109 ghost: PhantomData,
110 }
111 }
112}
113
114impl<D: Display + Send + Sync, U: Ui> From<RwData<D>> for State<(), DataArg<String>, U> {
115 fn from(value: RwData<D>) -> Self {
116 Self {
117 appender: Appender::NoArgs::<()>({
118 let value = RoData::from(&value);
119 Box::new(move || Append::String(value.read().to_string()))
120 }),
121 checker: Some(Box::new(move || value.has_changed())),
122 ghost: PhantomData,
123 }
124 }
125}
126
127impl<U: Ui> From<RwData<Text>> for State<(), DataArg<Text>, U> {
128 fn from(value: RwData<Text>) -> Self {
129 Self {
130 appender: Appender::NoArgs::<()>({
131 let value = RoData::from(&value);
132 Box::new(move || Append::Text(value.read().clone()))
133 }),
134 checker: Some(Box::new(move || value.has_changed())),
135 ghost: PhantomData,
136 }
137 }
138}
139
140impl<D: Display + Send + Sync, U: Ui> From<RoData<D>> for State<(), DataArg<String>, U> {
141 fn from(value: RoData<D>) -> Self {
142 Self {
143 appender: Appender::NoArgs::<()>({
144 let value = value.clone();
145 Box::new(move || Append::String(value.read().to_string()))
146 }),
147 checker: Some(Box::new(move || value.has_changed())),
148 ghost: PhantomData,
149 }
150 }
151}
152
153impl<U: Ui> From<RoData<Text>> for State<(), DataArg<Text>, U> {
154 fn from(value: RoData<Text>) -> Self {
155 Self {
156 appender: Appender::NoArgs::<()>({
157 let value = value.clone();
158 Box::new(move || Append::Text(value.read().clone()))
159 }),
160 checker: Some(Box::new(move || value.has_changed())),
161 ghost: PhantomData,
162 }
163 }
164}
165
166impl<U, I, O> From<DataMap<I, O>> for State<(), DataArg<String>, U>
167where
168 U: Ui,
169 I: ?Sized + Send + Sync,
170 O: Display + 'static,
171{
172 fn from(value: DataMap<I, O>) -> Self {
173 let (mut reader, checker) = value.fns();
174 State {
175 appender: Appender::NoArgs(Box::new(move || Append::String(reader().to_string()))),
176 checker: Some(checker),
177 ghost: PhantomData,
178 }
179 }
180}
181
182impl<U, I> From<DataMap<I, Text>> for State<(), DataArg<Text>, U>
183where
184 U: Ui,
185 I: ?Sized + Send + Sync,
186{
187 fn from(value: DataMap<I, Text>) -> Self {
188 let (mut reader, checker) = value.fns();
189 let reader = move || Append::Text(reader());
190 State {
191 appender: Appender::NoArgs(Box::new(reader)),
192 checker: Some(checker),
193 ghost: PhantomData,
194 }
195 }
196}
197
198impl<U, F, I, O> From<F> for State<(), IntoDataArg<String>, U>
199where
200 U: Ui,
201 F: FnOnce() -> DataMap<I, O>,
202 I: ?Sized + Send + Sync + 'static,
203 O: Display + 'static,
204{
205 fn from(value: F) -> Self {
206 let (mut reader, checker) = value().fns();
207 State {
208 appender: Appender::NoArgs(Box::new(move || Append::String(reader().to_string()))),
209 checker: Some(checker),
210 ghost: PhantomData,
211 }
212 }
213}
214
215impl<U, F, I> From<F> for State<(), IntoDataArg<Text>, U>
216where
217 U: Ui,
218 F: FnOnce() -> DataMap<I, Text>,
219 I: ?Sized + Send + Sync + 'static,
220{
221 fn from(value: F) -> Self {
222 let (mut reader, checker) = value().fns();
223 let reader = move || Append::Text(reader());
224 State {
225 appender: Appender::NoArgs(Box::new(reader)),
226 checker: Some(checker),
227 ghost: PhantomData,
228 }
229 }
230}
231
232impl<D, Reader, Checker, U> From<(Reader, Checker)> for State<(), NoArg<String>, U>
233where
234 D: Display,
235 Reader: Fn() -> D + Send + Sync + 'static,
236 Checker: Fn() -> bool + Send + Sync + 'static,
237 U: Ui,
238{
239 fn from((reader, checker): (Reader, Checker)) -> Self {
240 let reader = move || Append::String(reader().to_string());
241 State {
242 appender: Appender::NoArgs::<()>(Box::new(reader)),
243 checker: Some(Box::new(checker)),
244 ghost: PhantomData,
245 }
246 }
247}
248
249impl<Reader, Checker, U> From<(Reader, Checker)> for State<(), NoArg<Text>, U>
250where
251 Reader: Fn() -> Text + Send + Sync + 'static,
252 Checker: Fn() -> bool + Send + Sync + 'static,
253 U: Ui,
254{
255 fn from((reader, checker): (Reader, Checker)) -> Self {
256 let reader = move || Append::Text(reader());
257 State {
258 appender: Appender::NoArgs::<()>(Box::new(reader)),
259 checker: Some(Box::new(checker)),
260 ghost: PhantomData,
261 }
262 }
263}
264
265impl<D, W, ReadFn, U> From<ReadFn> for State<W, WidgetArg<String>, U>
266where
267 D: Display + Send + Sync,
268 W: Widget<U> + Sized,
269 ReadFn: Fn(&W) -> D + Send + Sync + 'static,
270 U: Ui,
271{
272 fn from(reader: ReadFn) -> Self {
273 let reader = move |arg: &W| Append::String(reader(arg).to_string());
274 State {
275 appender: Appender::FromWidget(Box::new(reader)),
276 checker: None,
277 ghost: PhantomData,
278 }
279 }
280}
281
282impl<W, ReadFn, U> From<ReadFn> for State<W, WidgetArg<Text>, U>
283where
284 W: Widget<U> + Sized,
285 ReadFn: Fn(&W) -> Text + Send + Sync + 'static,
286 U: Ui,
287{
288 fn from(reader: ReadFn) -> Self {
289 let reader = move |arg: &W| Append::Text(reader(arg));
290 State {
291 appender: Appender::FromWidget(Box::new(reader)),
292 checker: None,
293 ghost: PhantomData,
294 }
295 }
296}
297
298impl<D, W, ReadFn, U> From<ReadFn> for State<W, FileAndWidgetArg<String>, U>
299where
300 D: Display + Send + Sync,
301 W: Widget<U>,
302 ReadFn: Fn(&File, &W) -> D + Send + Sync + 'static,
303 U: Ui,
304{
305 fn from(reader: ReadFn) -> Self {
306 let reader = move |file: &File, arg: &W| Append::String(reader(file, arg).to_string());
307 State {
308 appender: Appender::FromFileAndWidget(Box::new(reader)),
309 checker: None,
310 ghost: PhantomData,
311 }
312 }
313}
314
315impl<W, ReadFn, U> From<ReadFn> for State<W, FileAndWidgetArg<Text>, U>
316where
317 W: Widget<U>,
318 ReadFn: Fn(&File, &W) -> Text + Send + Sync + 'static,
319 U: Ui,
320{
321 fn from(reader: ReadFn) -> Self {
322 let reader = move |file: &File, w: &W| Append::Text(reader(file, w));
323 State {
324 appender: Appender::FromFileAndWidget(Box::new(reader)),
325 checker: None,
326 ghost: PhantomData,
327 }
328 }
329}
330
331impl<D, ReadFn, U> From<ReadFn> for State<Cursors, CursorsArg<String>, U>
332where
333 D: Display + Send + Sync,
334 ReadFn: Fn(&Cursors) -> D + Send + Sync + 'static,
335 U: Ui,
336{
337 fn from(reader: ReadFn) -> Self {
338 let reader = move |arg: &Cursors| Append::String(reader(arg).to_string());
339 State {
340 appender: Appender::FromCursors(Box::new(reader)),
341 checker: None,
342 ghost: PhantomData,
343 }
344 }
345}
346
347impl<ReadFn, U> From<ReadFn> for State<Cursors, CursorsArg<Text>, U>
348where
349 ReadFn: Fn(&Cursors) -> Text + Send + Sync + 'static,
350 U: Ui,
351{
352 fn from(reader: ReadFn) -> Self {
353 let reader = move |arg: &Cursors| Append::Text(reader(arg));
354 State {
355 appender: Appender::FromCursors(Box::new(reader)),
356 checker: None,
357 ghost: PhantomData,
358 }
359 }
360}
361
362#[doc(hidden)]
364pub struct DataArg<T>(PhantomData<T>);
365#[doc(hidden)]
366pub struct IntoDataArg<T>(PhantomData<T>);
367#[doc(hidden)]
368pub struct NoArg<T>(PhantomData<T>);
369#[doc(hidden)]
370pub struct WidgetArg<T>(PhantomData<T>);
371#[doc(hidden)]
372pub struct FileAndWidgetArg<T>(PhantomData<T>);
373#[doc(hidden)]
374pub struct CursorsArg<T>(PhantomData<T>);
375
376type RelatedFn<T> = Box<dyn FnMut(&T) -> Append + Send + Sync + 'static>;
378type FileAndRelatedFn<T> = Box<dyn FnMut(&File, &T) -> Append + Send + Sync + 'static>;
379
380type ReaderFn<U> = Box<dyn FnMut(&mut Builder, &FileReader<U>) + Send + Sync>;
381
382enum Append {
383 String(String),
384 Text(Text),
385}
386
387impl Append {
388 fn push_to(self, builder: &mut Builder) {
389 match self {
390 Append::String(string) => builder.push_str(&string),
391 Append::Text(text) => builder.push_text(text),
392 }
393 }
394}