tilo_app/framework/
kinds.rs1use std::sync::Mutex;
4
5use tilo_resource::{Doc, Kinds, Resource, ResourceKind};
6
7use super::app::{ResourceApp, SeedCx, apply_seed};
8use tilo_lock::MutexRecover as _;
9
10#[must_use]
16pub const fn resource_kind<A: ResourceApp>() -> ResourceKind {
17 ResourceKind::of::<A::Resource>()
18 .hosted_by(A::ID, A::TITLE)
19 .named(name::<A>)
20}
21
22fn name<A: ResourceApp>(state: &dyn std::any::Any) -> Option<String> {
23 state
24 .downcast_ref::<<A::Resource as Resource>::State>()
25 .map(A::label)
26}
27
28type Seed = fn(&mut Doc, &str, &str, Option<&str>) -> Result<(), String>;
30static HOSTED: Mutex<(Kinds, Vec<(&'static str, Seed)>)> = Mutex::new((Kinds::new(), Vec::new()));
33
34pub(crate) fn register<A: ResourceApp>() {
36 let mut declared = super::Records::declaring();
39 A::records(&mut declared);
40 let app = super::app::hooks::<A>();
42 tilo_resource::words::name_app(app.title(), <A::Resource as Resource>::KIND);
47 let mut hosted = HOSTED.lock_recover();
48 hosted.0.insert(
49 ResourceKind::of::<A::Resource>()
50 .hosted_by(app.id(), app.title())
51 .named(name::<A>),
52 );
53 for chain in declared.into_chains() {
54 hosted.0.insert(chain.hosted_by(app.id(), app.title()));
55 }
56 let kind = <A::Resource as Resource>::KIND;
57 hosted.1.retain(|(known, _)| *known != kind);
58 hosted.1.push((kind, seed::<A>));
59}
60
61fn seed<A: ResourceApp>(
62 doc: &mut Doc,
63 me: &str,
64 device: &str,
65 workspace: Option<&str>,
66) -> Result<(), String> {
67 let seed = A::seed(&SeedCx {
68 me,
69 device,
70 host: None,
71 workspace,
72 });
73 apply_seed::<A>(doc, me, &seed)
74}
75
76pub fn seed_record(kind: &str, doc: &mut Doc, me: &str, device: &str) -> Result<(), String> {
80 seed_scoped(kind, doc, me, device, None)
81}
82
83pub fn seed_record_in_workspace(
86 kind: &str,
87 doc: &mut Doc,
88 me: &str,
89 device: &str,
90 workspace: &str,
91) -> Result<(), String> {
92 seed_scoped(kind, doc, me, device, Some(workspace))
93}
94
95fn seed_scoped(
96 kind: &str,
97 doc: &mut Doc,
98 me: &str,
99 device: &str,
100 workspace: Option<&str>,
101) -> Result<(), String> {
102 let seed = HOSTED
103 .lock_recover()
104 .1
105 .iter()
106 .find(|(known, _)| *known == kind)
107 .map(|(_, seed)| *seed);
108 seed.map_or(Ok(()), |seed| seed(doc, me, device, workspace))
109}
110
111#[must_use]
117pub fn hosted_kinds() -> Kinds {
118 HOSTED.lock_recover().0.clone()
119}