1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
6pub enum NexusIdError {
7 #[error("Nexus id cannot be negative: {0}")]
8 Negative(i64),
9 #[error("Nexus id {0} exceeds SQLite INTEGER range")]
10 TooLarge(u64),
11}
12
13macro_rules! nexus_id {
14 ($name:ident) => {
15 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
16 #[serde(transparent)]
17 pub struct $name(u64);
18
19 impl $name {
20 #[must_use]
21 pub const fn get(self) -> u64 {
22 self.0
23 }
24
25 pub fn to_i64(self) -> Result<i64, NexusIdError> {
26 i64::try_from(self.0).map_err(|_| NexusIdError::TooLarge(self.0))
27 }
28 }
29
30 impl From<u64> for $name {
31 fn from(value: u64) -> Self {
32 Self(value)
33 }
34 }
35
36 impl TryFrom<i64> for $name {
37 type Error = NexusIdError;
38
39 fn try_from(value: i64) -> Result<Self, Self::Error> {
40 if value < 0 {
41 return Err(NexusIdError::Negative(value));
42 }
43 Ok(Self(value as u64))
44 }
45 }
46
47 impl fmt::Display for $name {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 self.0.fmt(f)
50 }
51 }
52 };
53}
54
55nexus_id!(NexusModId);
56nexus_id!(NexusFileId);