tilo_app/framework/
kinds.rs1use std::sync::{Mutex, PoisonError};
4
5use tilo_resource::{Doc, Kinds, Resource, ResourceKind};
6
7use super::app::{ResourceApp, SeedCx, apply_seed};
8
9#[must_use]
15pub const fn resource_kind<A: ResourceApp>() -> ResourceKind {
16 ResourceKind::of::<A::Resource>()
17 .hosted_by(A::ID, A::TITLE)
18 .named(name::<A>)
19}
20
21fn name<A: ResourceApp>(state: &dyn std::any::Any) -> Option<String> {
22 state
23 .downcast_ref::<<A::Resource as Resource>::State>()
24 .map(A::label)
25}
26
27type Seed = fn(&mut Doc, &str, &str, Option<&str>) -> Result<(), String>;
29
30static HOSTED: Mutex<(Kinds, Vec<(&'static str, Seed)>)> = Mutex::new((Kinds::new(), Vec::new()));
33
34pub(crate) fn register<A: ResourceApp>() {
36 let mut hosted = HOSTED.lock().unwrap_or_else(PoisonError::into_inner);
37 hosted.0.insert(resource_kind::<A>());
38 let kind = <A::Resource as Resource>::KIND;
39 hosted.1.retain(|(known, _)| *known != kind);
40 hosted.1.push((kind, seed::<A>));
41}
42
43fn seed<A: ResourceApp>(
44 doc: &mut Doc,
45 me: &str,
46 device: &str,
47 room: Option<&str>,
48) -> Result<(), String> {
49 let seed = A::seed(&SeedCx {
50 me,
51 device,
52 host: None,
53 room,
54 });
55 apply_seed::<A>(doc, me, &seed)
56}
57
58pub fn seed_record(kind: &str, doc: &mut Doc, me: &str, device: &str) -> Result<(), String> {
65 seed_scoped(kind, doc, me, device, None)
66}
67
68pub fn seed_record_in_room(
74 kind: &str,
75 doc: &mut Doc,
76 me: &str,
77 device: &str,
78 room: &str,
79) -> Result<(), String> {
80 seed_scoped(kind, doc, me, device, Some(room))
81}
82
83fn seed_scoped(
84 kind: &str,
85 doc: &mut Doc,
86 me: &str,
87 device: &str,
88 room: Option<&str>,
89) -> Result<(), String> {
90 let seed = HOSTED
91 .lock()
92 .unwrap_or_else(PoisonError::into_inner)
93 .1
94 .iter()
95 .find(|(known, _)| *known == kind)
96 .map(|(_, seed)| *seed);
97 seed.map_or(Ok(()), |seed| seed(doc, me, device, room))
98}
99
100#[must_use]
106pub fn hosted_kinds() -> Kinds {
107 HOSTED
108 .lock()
109 .unwrap_or_else(PoisonError::into_inner)
110 .0
111 .clone()
112}