boox_note_parser/
id.rs

1use std::{
2    cell::LazyCell,
3    collections::{HashMap, HashSet},
4    sync::{LazyLock, Mutex, OnceLock},
5};
6
7trait CheckUuid {
8    fn id(&self) -> &uuid::Uuid;
9    fn to_string(&self) -> String;
10}
11static KNOWN_UUIDS: OnceLock<Mutex<HashMap<uuid::Uuid, Vec<Box<dyn CheckUuid + Send + Sync>>>>> =
12    OnceLock::new();
13
14fn check_uuid(id: impl CheckUuid + Send + Sync + 'static) {
15    // Lock the mutex and clear the HashMap
16    let mut map = KNOWN_UUIDS
17        .get_or_init(|| Mutex::new(HashMap::new()))
18        .lock()
19        .unwrap();
20    // Check if the id already exists in the HashMap
21    if let Some(existing) = map.get(id.id()) {
22        // log::warn!("Duplicate UUID found: {}. Already registered as:", id.to_string());
23        let mut types = HashSet::new();
24        for existing_id in existing {
25            types.insert(existing_id.to_string());
26        }
27
28        if types.len() > 1 {
29            log::warn!(
30                "UUIDs with different types found: {}. Already registered as: {}",
31                id.to_string(),
32                types.into_iter().collect::<Vec<_>>().join(", ")
33            );
34        }
35    }
36
37    // Insert the id into the HashMap
38    map.entry(id.id().clone()).or_default().push(Box::new(id));
39}
40
41macro_rules! implement_uuid {
42    ($name:ident) => {
43        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
44        pub struct $name(uuid::Uuid);
45
46        impl $name {
47            pub fn new(id: uuid::Uuid) -> Self {
48                let id = Self(id);
49                check_uuid(id.clone());
50                id
51            }
52
53            pub fn from_str(s: &str) -> crate::error::Result<Self> {
54                let id = Self(uuid::Uuid::parse_str(s).inspect_err(|e| {
55                    log::error!("Failed to parse UUID from byte string: {}", s);
56                })?);
57                check_uuid(id.clone());
58                Ok(id)
59            }
60
61            pub fn from_byte_str(s: &[u8]) -> crate::error::Result<Self> {
62                let s =
63                    std::str::from_utf8(s).map_err(|e| crate::error::Error::UuidInvalidUtf8(e))?;
64                let id = Self(uuid::Uuid::parse_str(s).inspect_err(|e| {
65                    log::error!("Failed to parse UUID from byte string: {}", s);
66                })?);
67                check_uuid(id.clone());
68                Ok(id)
69            }
70
71            pub fn to_simple_string(&self) -> String {
72                self.0.simple().to_string()
73            }
74
75            pub fn to_hyphenated_string(&self) -> String {
76                self.0.hyphenated().to_string()
77            }
78        }
79
80        impl std::fmt::Display for $name {
81            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82                write!(f, "{}({})", stringify!($name), self.0.to_string())
83            }
84        }
85
86        impl<'de> serde::Deserialize<'de> for $name {
87            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
88            where
89                D: serde::Deserializer<'de>,
90            {
91                let id: uuid::Uuid = serde::Deserialize::deserialize(deserializer)?;
92                Ok(Self(id))
93            }
94        }
95
96        impl CheckUuid for $name {
97            fn id(&self) -> &uuid::Uuid {
98                &self.0
99            }
100
101            fn to_string(&self) -> String {
102                format!("{}({})", stringify!($name), self.0.to_string())
103            }
104        }
105    };
106}
107
108implement_uuid!(NoteUuid);
109implement_uuid!(VirtualPageUuid);
110implement_uuid!(VirtualDocUuid);
111implement_uuid!(StrokeUuid);
112implement_uuid!(PageUuid);
113implement_uuid!(PageModelUuid);
114implement_uuid!(PenUuid);
115implement_uuid!(ShapeGroupUuid);
116implement_uuid!(PointsUuid);
117
118#[derive(Debug, Clone, PartialEq, Eq)]
119pub enum PenId {
120    Uuid(PenUuid),
121    Id(u32),
122}
123
124impl PenId {
125    pub fn from_uuid(uuid: PenUuid) -> Self {
126        Self::Uuid(uuid)
127    }
128
129    pub fn from_id(id: u32) -> Self {
130        Self::Id(id)
131    }
132}
133
134impl std::fmt::Display for PenId {
135    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136        match self {
137            Self::Uuid(uuid) => write!(f, "{}", uuid),
138            Self::Id(id) => write!(f, "PenId({})", id),
139        }
140    }
141}
142
143impl<'de> serde::Deserialize<'de> for PenId {
144    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
145    where
146        D: serde::Deserializer<'de>,
147    {
148        let id: String = serde::Deserialize::deserialize(deserializer)?;
149        if id.len() == 32 {
150            // UUID format
151            let uuid = PenUuid::from_str(&id).map_err(serde::de::Error::custom)?;
152            return Ok(Self::from_uuid(uuid));
153        }
154        Ok(Self::from_id(id.parse().map_err(serde::de::Error::custom)?))
155    }
156}
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
159pub struct LayerId(u32);
160
161impl LayerId {
162    pub fn new(id: u32) -> Self {
163        Self(id)
164    }
165}
166
167impl std::fmt::Display for LayerId {
168    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169        write!(f, "LayerId({})", self.0)
170    }
171}
172
173impl<'de> serde::Deserialize<'de> for LayerId {
174    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
175    where
176        D: serde::Deserializer<'de>,
177    {
178        let id: u32 = serde::Deserialize::deserialize(deserializer)?;
179        Ok(Self(id))
180    }
181}