gl_client/lsps/lsps0/
common_schemas.rs1use core::str::FromStr;
2
3use std::fmt::{Display, Formatter};
4
5use anyhow::{anyhow, Context};
6
7use serde::de::Error as SeError;
8use serde::ser::Error as DeError;
9use serde::{Deserialize, Serialize, Deserializer, Serializer};
10
11use time::format_description::FormatItem;
12use time::macros::format_description;
13use time::{OffsetDateTime, PrimitiveDateTime};
14
15#[derive(Debug)]
30pub struct IsoDatetime {
31 pub datetime: PrimitiveDateTime,
32}
33
34const DATETIME_FORMAT: &[FormatItem] =
35 format_description!("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:3]Z");
36
37impl IsoDatetime {
38 pub fn from_offset_date_time(datetime: OffsetDateTime) -> Self {
39 let offset = time::UtcOffset::from_whole_seconds(0).unwrap();
40 let datetime_utc = datetime.to_offset(offset);
41 let primitive = PrimitiveDateTime::new(datetime_utc.date(), datetime.time());
42 Self {
43 datetime: primitive,
44 }
45 }
46
47 pub fn from_primitive_date_time(datetime: PrimitiveDateTime) -> Self {
48 Self { datetime }
49 }
50
51 pub fn datetime(&self) -> OffsetDateTime {
52 self.datetime.assume_utc()
53 }
54}
55
56impl Serialize for IsoDatetime {
57 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
58 where
59 S: serde::Serializer,
60 {
61 let datetime_str = self
62 .datetime
63 .format(&DATETIME_FORMAT)
64 .map_err(|err| S::Error::custom(format!("Failed to format datetime {:?}", err)))?;
65
66 serializer.serialize_str(&datetime_str)
67 }
68}
69
70impl<'de> Deserialize<'de> for IsoDatetime {
71 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
72 where
73 D: serde::Deserializer<'de>,
74 {
75 let str_repr = <String as serde::de::Deserialize>::deserialize(deserializer)?;
76 time::PrimitiveDateTime::parse(&str_repr, DATETIME_FORMAT)
77 .map_err(|err| D::Error::custom(format!("Failed to parse Datetime. {:?}", err)))
78 .map(Self::from_primitive_date_time)
79 }
80}
81
82#[derive(Debug)]
83pub struct SatAmount(u64);
84#[derive(Debug)]
85pub struct MsatAmount(u64);
86
87impl SatAmount {
88 pub fn sat_value(&self) -> u64 {
89 self.0
90 }
91
92 pub fn new(value: u64) -> Self {
93 SatAmount(value)
94 }
95}
96
97impl MsatAmount {
98 pub fn msat_value(&self) -> u64 {
99 self.0
100 }
101
102 pub fn new(value: u64) -> Self {
103 MsatAmount(value)
104 }
105}
106
107impl Serialize for SatAmount {
108 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
109 where
110 S: serde::Serializer,
111 {
112 let amount_str = self.0.to_string();
113 serializer.serialize_str(&amount_str)
114 }
115}
116
117impl Serialize for MsatAmount {
118 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
119 where
120 S: serde::Serializer,
121 {
122 let amount_str = self.0.to_string();
123 serializer.serialize_str(&amount_str)
124 }
125}
126
127impl<'de> Deserialize<'de> for SatAmount {
128 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
129 where
130 D: serde::Deserializer<'de>,
131 {
132 let str_repr = <String as serde::de::Deserialize>::deserialize(deserializer)?;
133 let u64_repr: Result<u64, _> = str_repr
134 .parse()
135 .map_err(|_| D::Error::custom(String::from("Failed to parse sat_amount")));
136 Ok(Self(u64_repr.unwrap()))
137 }
138}
139
140impl<'de> Deserialize<'de> for MsatAmount {
141 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
142 where
143 D: serde::Deserializer<'de>,
144 {
145 let str_repr = <String as serde::de::Deserialize>::deserialize(deserializer)?;
146 let u64_repr: Result<u64, _> = str_repr
147 .parse()
148 .map_err(|_| D::Error::custom(String::from("Failed to parse sat_amount")));
149 Ok(Self(u64_repr.unwrap()))
150 }
151}
152
153
154#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
155pub struct ShortChannelId(u64);
156
157impl Serialize for ShortChannelId {
158 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
159 where
160 S: Serializer,
161 {
162 serializer.serialize_str(&self.to_string())
163 }
164}
165
166impl<'de> Deserialize<'de> for ShortChannelId {
167 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
168 where
169 D: Deserializer<'de>,
170 {
171 use serde::de::Error;
172 let s: String = Deserialize::deserialize(deserializer)?;
173 Ok(Self::from_str(&s).map_err(|e| Error::custom(e.to_string()))?)
174 }
175}
176
177impl FromStr for ShortChannelId {
178 type Err = anyhow::Error;
179 fn from_str(s: &str) -> Result<Self, Self::Err> {
180 let parts: Result<Vec<u64>, _> = s.split('x').map(|p| p.parse()).collect();
181 let parts = parts.with_context(|| format!("Malformed short_channel_id: {}", s))?;
182 if parts.len() != 3 {
183 return Err(anyhow!(
184 "Malformed short_channel_id: element count mismatch"
185 ));
186 }
187
188 Ok(ShortChannelId(
189 (parts[0] << 40) | (parts[1] << 16) | (parts[2] << 0),
190 ))
191 }
192}
193impl Display for ShortChannelId {
194 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
195 write!(f, "{}x{}x{}", self.block(), self.txindex(), self.outnum())
196 }
197}
198impl ShortChannelId {
199 pub fn block(&self) -> u32 {
200 (self.0 >> 40) as u32 & 0xFFFFFF
201 }
202 pub fn txindex(&self) -> u32 {
203 (self.0 >> 16) as u32 & 0xFFFFFF
204 }
205 pub fn outnum(&self) -> u16 {
206 self.0 as u16 & 0xFFFF
207 }
208}
209
210#[cfg(test)]
211mod test {
212 use super::*;
213
214 #[test]
215 fn parsing_amount_sats() {
216 let json_str_number = "\"10000000001\"";
218
219 let int_number: u64 = 10000000001;
220
221 let x = serde_json::from_str::<SatAmount>(json_str_number).unwrap();
222 assert_eq!(x.sat_value(), int_number);
223 }
224
225 #[test]
226 fn serializing_amount_sats() {
227 let json_str_number = "\"10000000001\"";
230 let int_number: u64 = 10000000001;
231
232 let sat_amount = SatAmount::new(int_number);
233
234 let json_str = serde_json::to_string::<SatAmount>(&sat_amount).unwrap();
235 assert_eq!(json_str, json_str_number);
236 }
237
238 #[test]
239 fn parse_and_serialize_datetime() {
240 let datetime_str = "\"2023-01-01T23:59:59.999Z\"";
241
242 let dt = serde_json::from_str::<IsoDatetime>(datetime_str).unwrap();
243
244 assert_eq!(dt.datetime.year(), 2023);
245 assert_eq!(dt.datetime.month(), time::Month::January);
246 assert_eq!(dt.datetime.day(), 1);
247 assert_eq!(dt.datetime.hour(), 23);
248 assert_eq!(dt.datetime.minute(), 59);
249 assert_eq!(dt.datetime.second(), 59);
250
251 assert_eq!(
252 serde_json::to_string(&dt).expect("Can be serialized"),
253 datetime_str
254 )
255 }
256
257 #[test]
258 fn parse_datetime_that_doesnt_follow_spec() {
259 let datetime_str = "\"2023-01-01T23:59:59.99Z\"";
262
263 let result = serde_json::from_str::<IsoDatetime>(datetime_str);
264 result.expect_err("datetime_str should not be parsed if it doesn't follow spec");
265 }
266
267 #[test]
268 #[allow(clippy::unusual_byte_groupings)]
269 fn parse_scid_from_string() {
270 let scid_str = "16777215x16777215x65535";
280
281 let scid = ShortChannelId::from_str(scid_str).expect("The scid is parseable");
282 assert_eq!(scid.to_string(), scid_str);
283
284 let scid_str = "0x0x0";
286
287 let scid = ShortChannelId::from_str(scid_str).expect("The scid is parseable");
288 assert_eq!(scid.to_string(), scid_str);
289
290 let scid_str = "1x2x3";
291
292 let scid = ShortChannelId::from_str(scid_str).expect("The scid is parseable");
293 assert_eq!(scid.to_string(), scid_str);
294 assert!(ShortChannelId::from_str("xx").is_err());
296 assert!(ShortChannelId::from_str("0x0").is_err());
297 assert!(ShortChannelId::from_str("-2x-12x14").is_err());
298 }
299
300 #[test]
301 fn short_channel_id_is_serialized_as_str() {
302 let scid: ShortChannelId = ShortChannelId::from_str("10x5x8").unwrap();
303 let scid_json_obj = serde_json::to_string(&scid).expect("Can be serialized");
304 assert_eq!("\"10x5x8\"", scid_json_obj);
305 }
306
307 #[test]
308 fn short_channel_id_can_be_deserialized_from_str() {
309 let scid_json = "\"11x12x13\"";
310
311 let scid = serde_json::from_str::<ShortChannelId>(scid_json).expect("scid can be parsed");
312
313 assert_eq!(scid, ShortChannelId::from_str("11x12x13").unwrap());
314 }
315}