firefly_runtime/
config.rs1use 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
13pub 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#[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}