ftd_rt/
lib.rs

1extern crate self as ftd_rt;
2
3mod condition;
4mod dnode;
5mod event;
6mod html;
7mod ui;
8#[cfg(feature = "wasm")]
9mod wasm;
10
11pub use condition::Condition;
12pub use event::{Action, Event};
13pub use html::{anchor, color, length, overflow, Node};
14pub use ui::{
15    Anchor, AttributeType, Code, Color, Column, Common, ConditionalAttribute, ConditionalValue,
16    Container, Element, ExternalFont, FontDisplay, GradientDirection, IFrame, Image, Input, Length,
17    NamedFont, Overflow, Position, Region, Row, Scene, Style, Text, TextAlign, TextBlock,
18    TextFormat, Weight,
19};
20
21#[derive(serde::Serialize, serde::Deserialize, Eq, PartialEq, Debug, Default, Clone)]
22pub struct Rendered {
23    pub original: String,
24    pub rendered: String,
25}
26
27impl From<&str> for Rendered {
28    fn from(item: &str) -> Self {
29        Rendered {
30            original: item.to_string(),
31            rendered: item.to_string(),
32        }
33    }
34}
35
36#[derive(thiserror::Error, Debug)]
37pub enum Error {
38    #[error("invalid input: {message}")]
39    InvalidInput { message: String, context: String },
40}
41
42pub type Map = std::collections::BTreeMap<String, String>;
43type Result<T> = std::result::Result<T, Error>;
44
45#[derive(serde::Deserialize)]
46#[cfg_attr(
47    not(feature = "wasm"),
48    derive(serde::Serialize, PartialEq, Debug, Default, Clone)
49)]
50pub struct Document {
51    pub html: String,
52    pub data: ftd_rt::DataDependenciesMap,
53    pub external_children: ExternalChildrenDependenciesMap,
54}
55
56pub fn e<T, S1, S2>(m: S1, c: S2) -> Result<T>
57where
58    S1: Into<String>,
59    S2: Into<String>,
60{
61    Err(Error::InvalidInput {
62        message: m.into(),
63        context: c.into(),
64    })
65}
66
67pub fn get_name<'a, 'b>(prefix: &'a str, s: &'b str, doc_id: &str) -> ftd_rt::Result<&'b str> {
68    match s.split_once(' ') {
69        Some((p1, p2)) => {
70            if p1 != prefix {
71                return ftd_rt::e(format!("must start with {}", prefix), doc_id);
72            }
73            Ok(p2)
74        }
75        None => ftd_rt::e(
76            format!("{} does not contain space (prefix={})", s, prefix),
77            doc_id,
78        ),
79    }
80}
81
82pub type DataDependenciesMap = std::collections::BTreeMap<String, Data>;
83
84#[derive(serde::Deserialize)]
85#[cfg_attr(
86    not(feature = "wasm"),
87    derive(serde::Serialize, PartialEq, Debug, Default, Clone)
88)]
89pub struct Data {
90    pub value: String,
91    pub dependencies: ftd_rt::Map,
92}
93
94pub type ExternalChildrenDependenciesMap =
95    std::collections::BTreeMap<String, Vec<ExternalChildrenCondition>>;
96
97#[derive(serde::Deserialize)]
98#[cfg_attr(
99    not(feature = "wasm"),
100    derive(serde::Serialize, PartialEq, Debug, Default, Clone)
101)]
102pub struct ExternalChildrenCondition {
103    pub condition: Vec<String>,
104    pub set_at: String,
105}
106
107#[derive(serde::Deserialize)]
108#[cfg_attr(
109    not(feature = "wasm"),
110    derive(PartialEq, Debug, Clone, serde::Serialize)
111)]
112pub enum DependencyType {
113    Style,
114    Visible,
115    Value,
116}
117
118#[derive(serde::Deserialize)]
119#[cfg_attr(
120    not(feature = "wasm"),
121    derive(serde::Serialize, PartialEq, Debug, Clone)
122)]
123pub struct Dependencies {
124    pub dependency_type: DependencyType,
125    pub condition: Option<String>,
126    pub parameters: std::collections::BTreeMap<String, ValueWithDefault>,
127}
128
129#[derive(serde::Deserialize)]
130#[cfg_attr(
131    not(feature = "wasm"),
132    derive(serde::Serialize, PartialEq, Debug, Clone)
133)]
134pub struct ValueWithDefault {
135    pub value: ConditionalValue,
136    pub default: Option<ConditionalValue>,
137}
138
139#[cfg(test)]
140mod test {
141    #[test]
142    fn get_name() {
143        assert_eq!(super::get_name("fn", "fn foo").unwrap(), "foo")
144    }
145}