Skip to main content

conjure_serde/cbor/de/
client.rs

1// Copyright 2026 Palantir Technologies, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14use crate::de::delegating_visitor::{DelegatingVisitor, Visitor2};
15use crate::de::null_collections_behavior::NullCollectionsBehavior;
16use crate::de::Behavior;
17use serde::de::{self, Visitor};
18use serde::Deserializer;
19use serde_cbor_2::de::{IoRead, SliceRead};
20use serde_cbor_2::Error;
21use std::io;
22
23/// Deserializes a value from a reader of CBOR data.
24pub fn client_from_reader<R, T>(reader: R) -> Result<T, Error>
25where
26    R: io::Read,
27    T: de::DeserializeOwned,
28{
29    let mut de = ClientDeserializer::from_reader(reader);
30    T::deserialize(&mut de)
31}
32
33/// Deserializes a value from a slice of CBOR data.
34pub fn client_from_slice<'a, T>(s: &'a [u8]) -> Result<T, Error>
35where
36    T: de::Deserialize<'a>,
37{
38    let mut de = ClientDeserializer::from_slice(s);
39    T::deserialize(&mut de)
40}
41
42/// A serde CBOR deserializer appropriate for use by Conjure clients.
43pub struct ClientDeserializer<R>(serde_cbor_2::Deserializer<R>);
44
45impl<R> ClientDeserializer<IoRead<R>>
46where
47    R: io::Read,
48{
49    /// Creates a Conjure CBOR client deserializer from an `io::Read`.
50    pub fn from_reader(reader: R) -> Self {
51        ClientDeserializer(serde_cbor_2::Deserializer::from_reader(reader))
52    }
53}
54
55impl<'a> ClientDeserializer<SliceRead<'a>> {
56    /// Creates a Conjure CBOR client deserializer from a `&[u8]`.
57    pub fn from_slice(bytes: &'a [u8]) -> Self {
58        ClientDeserializer(serde_cbor_2::Deserializer::from_slice(bytes))
59    }
60}
61
62impl<'a, 'de, R> de::Deserializer<'de> for &'a mut ClientDeserializer<R>
63where
64    R: serde_cbor_2::de::Read<'de>,
65{
66    impl_deserialize_body!(
67        &'a mut serde_cbor_2::Deserializer<R>,
68        NullCollectionsBehavior<ValueBehavior>
69    );
70
71    fn is_human_readable(&self) -> bool {
72        false
73    }
74}
75
76pub enum ValueBehavior {}
77
78impl Behavior for ValueBehavior {
79    type KeyBehavior = KeyBehavior;
80}
81
82pub enum KeyBehavior {}
83
84impl Behavior for KeyBehavior {
85    type KeyBehavior = Self;
86
87    fn deserialize_bytes<'de, D, V>(de: D, visitor: V) -> Result<V::Value, D::Error>
88    where
89        D: Deserializer<'de>,
90        V: Visitor<'de>,
91    {
92        de.deserialize_any(DelegatingVisitor::new(UuidKeyVisitor, visitor))
93    }
94}
95
96/// Visitor that accepts UUID keys as either strings (Java format) or bytes (Rust format)
97struct UuidKeyVisitor;
98
99impl<'de, V> Visitor2<'de, V> for UuidKeyVisitor
100where
101    V: Visitor<'de>,
102{
103    // Forward byte arrays as-is (original Rust binary format)
104    fn visit_bytes<E>(self, visitor: V, v: &[u8]) -> Result<V::Value, E>
105    where
106        E: de::Error,
107    {
108        visitor.visit_bytes(v)
109    }
110
111    fn visit_borrowed_bytes<E>(self, visitor: V, v: &'de [u8]) -> Result<V::Value, E>
112    where
113        E: de::Error,
114    {
115        visitor.visit_borrowed_bytes(v)
116    }
117
118    fn visit_byte_buf<E>(self, visitor: V, v: Vec<u8>) -> Result<V::Value, E>
119    where
120        E: de::Error,
121    {
122        visitor.visit_byte_buf(v)
123    }
124
125    // Parse string format UUIDs (Java format) and convert to bytes
126    fn visit_str<E>(self, visitor: V, v: &str) -> Result<V::Value, E>
127    where
128        E: de::Error,
129    {
130        match conjure_object::Uuid::parse_str(v) {
131            Ok(uuid) => visitor.visit_byte_buf(uuid.as_bytes().to_vec()),
132            Err(_) => Err(E::custom(format!("invalid UUID string: {}", v))),
133        }
134    }
135
136    fn visit_borrowed_str<E>(self, visitor: V, v: &'de str) -> Result<V::Value, E>
137    where
138        E: de::Error,
139    {
140        match conjure_object::Uuid::parse_str(v) {
141            Ok(uuid) => visitor.visit_byte_buf(uuid.as_bytes().to_vec()),
142            Err(_) => Err(E::custom(format!("invalid UUID string: {}", v))),
143        }
144    }
145
146    fn visit_string<E>(self, visitor: V, v: String) -> Result<V::Value, E>
147    where
148        E: de::Error,
149    {
150        match conjure_object::Uuid::parse_str(&v) {
151            Ok(uuid) => visitor.visit_byte_buf(uuid.as_bytes().to_vec()),
152            Err(_) => Err(E::custom(format!("invalid UUID string: {}", v))),
153        }
154    }
155}