use bytes::Bytes;
use serde::ser::{SerializeStruct, Serializer};
use serde::{Deserialize, Deserializer, Serialize};
pub struct Placeholder {
num: usize,
}
impl Placeholder {
pub fn num(self) -> usize {
self.num
}
}
impl Serialize for Placeholder {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut s = serializer.serialize_struct("Placeholder", 2)?;
s.serialize_field("_placeholder", &true)?;
s.serialize_field("num", &self.num)?;
s.end()
}
}
#[derive(Deserialize)]
struct RawPlaceholder {
_placeholder: bool,
num: usize,
}
impl<'de> Deserialize<'de> for Placeholder {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let raw = RawPlaceholder::deserialize(deserializer)?;
if !raw._placeholder {
Err(serde::de::Error::custom("expected _placeholder to be true"))?;
}
Ok(Placeholder { num: raw.num })
}
}
#[derive(Default)]
pub struct AttachmentsBuilder {
buffer: Vec<Bytes>,
}
impl AttachmentsBuilder {
pub fn new() -> Self {
Default::default()
}
pub fn attach(&mut self, data: Bytes) -> Placeholder {
let num = self.buffer.len();
self.buffer.push(data);
Placeholder { num }
}
pub fn finish(self) -> Vec<Bytes> {
self.buffer
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builder_assigns_sequential_indices() {
let mut builder = AttachmentsBuilder::new();
let p0 = builder.attach(Bytes::from_static(b"first"));
let p1 = builder.attach(Bytes::from_static(b"second"));
assert_eq!(p0.num, 0);
assert_eq!(p1.num, 1);
let buffers = builder.finish();
assert_eq!(buffers.len(), 2);
assert_eq!(buffers[0], Bytes::from_static(b"first"));
assert_eq!(buffers[1], Bytes::from_static(b"second"));
}
#[test]
fn placeholder_serializes_to_wire_format() {
let p = Placeholder { num: 3 };
let json = serde_json::to_string(&p).unwrap();
assert!(json.contains("\"_placeholder\":true"));
assert!(json.contains("\"num\":3"));
}
#[test]
fn placeholder_round_trips_through_json() {
let original = Placeholder { num: 5 };
let json = serde_json::to_vec(&original).unwrap();
let decoded: Placeholder = serde_json::from_slice(&json).unwrap();
assert_eq!(decoded.num, 5);
}
#[test]
fn placeholder_rejects_false_flag() {
let json = r#"{"_placeholder":false,"num":0}"#;
let result: Result<Placeholder, _> = serde_json::from_str(json);
assert!(result.is_err());
}
#[test]
fn placeholder_num_consumes_value() {
let p = Placeholder { num: 42 };
assert_eq!(p.num(), 42);
}
}