Skip to main content

firefly_runtime/
config.rs

1use crate::color::FromRGB;
2use crate::error::Error;
3use crate::state::NetHandler;
4use core::fmt;
5use embedded_graphics::draw_target::DrawTarget;
6use embedded_graphics::geometry::OriginDimensions;
7use embedded_graphics::pixelcolor::RgbColor;
8use firefly_hal::*;
9use firefly_types::validate_id;
10use heapless::String;
11use serde::{Deserialize, Serialize};
12
13/// Contains the basic information and resources needed to run an app.
14pub struct RuntimeConfig<'a, D, C>
15where
16    D: DrawTarget<Color = C> + OriginDimensions,
17    C: RgbColor + FromRGB,
18{
19    pub id: Option<FullID>,
20    pub device: DeviceImpl<'a>,
21    pub display: D,
22    pub net_handler: NetHandler<'a>,
23}
24
25pub enum FullIDError {
26    NoDot,
27    LongAuthor,
28    LongApp,
29}
30
31impl FullIDError {
32    fn as_str(&self) -> &'static str {
33        match self {
34            Self::NoDot => "the full app ID must contain a dot",
35            Self::LongAuthor => "author ID is too long",
36            Self::LongApp => "app ID is too long",
37        }
38    }
39}
40
41impl fmt::Display for FullIDError {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        write!(f, "{}", self.as_str())
44    }
45}
46
47/// The author and app ID combo. Must be unique. Cannot be changed.
48#[derive(PartialEq, Clone, Serialize, Deserialize)]
49pub struct FullID {
50    author: String<16>,
51    app: String<16>,
52}
53
54impl FullID {
55    pub fn new(author: String<16>, app: String<16>) -> Self {
56        Self { author, app }
57    }
58
59    pub fn from_str(author: &str, app: &str) -> Option<Self> {
60        let Ok(author) = String::try_from(author) else {
61            return None;
62        };
63        let Ok(app) = String::try_from(app) else {
64            return None;
65        };
66        Some(Self { author, app })
67    }
68
69    pub fn author(&self) -> &str {
70        &self.author
71    }
72
73    pub fn app(&self) -> &str {
74        &self.app
75    }
76
77    pub(crate) fn validate(&self) -> Result<(), Error> {
78        if let Err(err) = validate_id(&self.author) {
79            return Err(Error::InvalidAuthorID(err));
80        }
81        if let Err(err) = validate_id(&self.app) {
82            return Err(Error::InvalidAppID(err));
83        }
84        Ok(())
85    }
86}
87
88impl TryFrom<&str> for FullID {
89    type Error = FullIDError;
90
91    fn try_from(value: &str) -> Result<Self, Self::Error> {
92        let Some(dot) = value.find('.') else {
93            return Err(FullIDError::NoDot);
94        };
95        let (author_id, app_id) = value.split_at(dot);
96        let Ok(author_id) = heapless::String::try_from(author_id) else {
97            return Err(FullIDError::LongAuthor);
98        };
99        let Ok(app_id) = heapless::String::try_from(&app_id[1..]) else {
100            return Err(FullIDError::LongApp);
101        };
102        Ok(FullID::new(author_id, app_id))
103    }
104}