wasmer_deploy_schema/
app_id.rs

1use serde::{Deserialize, Serialize};
2use std::{
3    fmt::Display,
4    net::{IpAddr, Ipv6Addr},
5    str::FromStr,
6};
7
8use crate::{NetworkId, NetworkIdEncodingMethod};
9
10#[derive(
11    Debug,
12    Clone,
13    Copy,
14    PartialEq,
15    Eq,
16    PartialOrd,
17    Ord,
18    Hash,
19    Serialize,
20    Deserialize,
21    schemars::JsonSchema,
22)]
23pub struct AppId(u64);
24
25impl AppId {
26    pub fn new(val: u64) -> Self {
27        assert!(val < 72_057_594_037_927_936); // 2^56 bits
28        Self(val)
29    }
30
31    pub fn as_u64(&self) -> u64 {
32        self.0
33    }
34
35    pub fn from_ip(addr: &IpAddr, method: NetworkIdEncodingMethod) -> Option<(Self, u32)> {
36        let (network_id, remainder) = NetworkId::from_ip(addr, method)?;
37        network_id.as_app_id().map(|app_id| (app_id, remainder))
38    }
39
40    pub fn from_ipv6(addr: &Ipv6Addr, method: NetworkIdEncodingMethod) -> Option<(Self, u32)> {
41        let (network_id, remainder) = NetworkId::from_ipv6(addr, method);
42        network_id.as_app_id().map(|app_id| (app_id, remainder))
43    }
44
45    pub fn into_ip(self, base: IpAddr, remainder: u32, method: NetworkIdEncodingMethod) -> IpAddr {
46        match base {
47            IpAddr::V4(base) => IpAddr::V4(base),
48            IpAddr::V6(base) => self.into_ipv6(base, remainder, method).into(),
49        }
50    }
51
52    pub fn into_ipv6(
53        self,
54        base: Ipv6Addr,
55        remainder: u32,
56        method: NetworkIdEncodingMethod,
57    ) -> Ipv6Addr {
58        NetworkId::into_ipv6(self.into(), base, remainder, method)
59    }
60}
61
62impl Display for AppId {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        write!(f, "{}", self.0)
65    }
66}
67
68impl TryFrom<&str> for AppId {
69    type Error = ();
70
71    fn try_from(value: &str) -> Result<Self, Self::Error> {
72        FromStr::from_str(value)
73    }
74}
75
76impl FromStr for AppId {
77    type Err = ();
78
79    fn from_str(s: &str) -> Result<Self, Self::Err> {
80        Ok(AppId(u64::from_str(s).map_err(|_| ())?))
81    }
82}
83
84impl From<u64> for AppId {
85    fn from(value: u64) -> Self {
86        // The AppId must be less than 56bits
87        assert!(value < 0x00ff_ffff_ffff_ffff);
88        Self(value)
89    }
90}
91
92impl From<AppId> for u64 {
93    fn from(value: AppId) -> Self {
94        value.0
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101
102    #[test]
103    fn test_app_id_cipher() {
104        let addrs = [
105            Ipv6Addr::LOCALHOST,
106            Ipv6Addr::UNSPECIFIED,
107            Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0),
108            Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1),
109            Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0),
110            Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
111        ];
112        let methods = [
113            NetworkIdEncodingMethod::PrivateProjection,
114            NetworkIdEncodingMethod::PublicProjection,
115        ];
116        let remainders = [0u32, 1u32, 128u32, 255u32, 16_777_215u32];
117
118        for method in methods {
119            for n in 0u64..1000u64 {
120                let n = n * 989;
121
122                let app_id = AppId::new(n);
123
124                for r in remainders {
125                    for base in addrs.iter() {
126                        let addr = app_id.into_ipv6(*base, r, method);
127
128                        let s1 = addr.segments();
129                        let s2 = base.segments();
130
131                        match method {
132                            NetworkIdEncodingMethod::PrivateProjection => {
133                                assert_eq!(s1[0], s2[0]);
134                                assert_eq!(s1[1], s2[1]);
135                                assert_eq!(s1[2].to_be_bytes()[0], s2[2].to_be_bytes()[0]);
136                            }
137                            NetworkIdEncodingMethod::PublicProjection => {
138                                assert_eq!(s1[0], s2[0]);
139                                assert_eq!(s1[1], s2[1]);
140                                assert_eq!(s1[2], s2[2]);
141                                assert_eq!(s1[3], s2[3]);
142                            }
143                        }
144
145                        let (ret_app_id, ret_r) = AppId::from_ipv6(&addr, method).unwrap();
146                        assert_eq!(app_id, ret_app_id);
147
148                        match method {
149                            NetworkIdEncodingMethod::PrivateProjection => assert_eq!(r, ret_r),
150                            NetworkIdEncodingMethod::PublicProjection => assert_eq!(0, ret_r),
151                        }
152                    }
153                }
154            }
155        }
156    }
157}