buntrail_protocol/
path.rs1use base64::{Engine as _, engine::general_purpose::STANDARD};
2use buntrail_core::contracts::{CoreError, ErrorCode, TargetPath};
3use serde::{Deserialize, Serialize};
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(rename_all = "snake_case")]
7pub enum PathKind {
8 Posix,
9 Windows,
10}
11
12#[derive(Clone, Debug, PartialEq, Eq)]
14pub struct WirePath(TargetPath);
15
16#[derive(Serialize, Deserialize)]
17#[serde(deny_unknown_fields)]
18struct EncodedPath {
19 kind: PathKind,
20 base64: String,
21}
22
23impl WirePath {
24 pub fn from_core(path: &TargetPath) -> Result<Self, CoreError> {
25 Ok(Self(match path {
26 TargetPath::PosixBytes(bytes) => TargetPath::posix(bytes.clone())?,
27 TargetPath::WindowsWide(units) => TargetPath::windows(units.clone())?,
28 }))
29 }
30
31 pub fn core(&self) -> TargetPath {
32 self.0.clone()
33 }
34
35 pub fn kind(&self) -> PathKind {
36 match self.0 {
37 TargetPath::PosixBytes(_) => PathKind::Posix,
38 TargetPath::WindowsWide(_) => PathKind::Windows,
39 }
40 }
41}
42
43impl Serialize for WirePath {
44 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
45 let bytes = match &self.0 {
46 TargetPath::PosixBytes(bytes) => bytes.clone(),
47 TargetPath::WindowsWide(units) => units.iter().flat_map(|u| u.to_le_bytes()).collect(),
48 };
49 EncodedPath {
50 kind: self.kind(),
51 base64: STANDARD.encode(bytes),
52 }
53 .serialize(serializer)
54 }
55}
56
57impl<'de> Deserialize<'de> for WirePath {
58 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
59 use serde::de::Error;
60 let encoded = EncodedPath::deserialize(deserializer)?;
61 let bytes = STANDARD.decode(encoded.base64).map_err(D::Error::custom)?;
62 let path = match encoded.kind {
63 PathKind::Posix => TargetPath::posix(bytes),
64 PathKind::Windows if bytes.len() % 2 == 0 => TargetPath::windows(
65 bytes
66 .as_chunks::<2>()
67 .0
68 .iter()
69 .map(|u| u16::from_le_bytes([u[0], u[1]]))
70 .collect(),
71 ),
72 PathKind::Windows => Err(CoreError::new(
73 ErrorCode::InvalidArgument,
74 "odd Windows path byte length",
75 )),
76 };
77 Ok(Self(path.map_err(|e| D::Error::custom(e.message))?))
78 }
79}