Skip to main content

cloud_sdk_testkit/
body.rs

1//! Bounded fixture response bodies.
2
3use core::fmt;
4
5/// Maximum fixture body length, including one byte beyond the common 8 MiB
6/// response-policy ceiling for oversized-input tests.
7pub const MAX_FIXTURE_BODY_BYTES: usize = 8_388_609;
8
9/// Fixture body construction or write error.
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub enum FixtureBodyError {
12    /// The represented body exceeds [`MAX_FIXTURE_BODY_BYTES`].
13    TooLarge,
14    /// The caller-owned destination is smaller than the represented body.
15    OutputTooSmall,
16}
17
18impl_static_error!(FixtureBodyError,
19    Self::TooLarge => "fixture body exceeds the size limit",
20    Self::OutputTooSmall => "fixture output buffer is too small",
21);
22
23/// Borrowed or compact repeated-byte fixture body.
24#[derive(Clone, Copy, Eq, PartialEq)]
25pub enum FixtureBody<'a> {
26    /// Borrowed response bytes.
27    Bytes(&'a [u8]),
28    /// A repeated byte with a bounded logical length.
29    Repeated {
30        /// Byte copied into the response destination.
31        byte: u8,
32        /// Logical body length.
33        len: usize,
34    },
35}
36
37impl<'a> FixtureBody<'a> {
38    /// Creates a bounded borrowed body.
39    pub const fn new(bytes: &'a [u8]) -> Result<Self, FixtureBodyError> {
40        if bytes.len() > MAX_FIXTURE_BODY_BYTES {
41            return Err(FixtureBodyError::TooLarge);
42        }
43        Ok(Self::Bytes(bytes))
44    }
45
46    /// Creates a compact repeated-byte body.
47    pub const fn repeated(byte: u8, len: usize) -> Result<Self, FixtureBodyError> {
48        if len > MAX_FIXTURE_BODY_BYTES {
49            return Err(FixtureBodyError::TooLarge);
50        }
51        Ok(Self::Repeated { byte, len })
52    }
53
54    /// Returns the represented body length.
55    #[must_use]
56    pub const fn len(self) -> usize {
57        match self {
58            Self::Bytes(bytes) => bytes.len(),
59            Self::Repeated { len, .. } => len,
60        }
61    }
62
63    /// Reports whether the represented body is empty.
64    #[must_use]
65    pub const fn is_empty(self) -> bool {
66        self.len() == 0
67    }
68
69    /// Returns borrowed bytes when this is a literal fixture.
70    #[must_use]
71    pub const fn as_bytes(self) -> Option<&'a [u8]> {
72        match self {
73            Self::Bytes(bytes) => Some(bytes),
74            Self::Repeated { .. } => None,
75        }
76    }
77
78    /// Atomically writes the represented body into a caller-owned buffer.
79    pub fn write_to(self, output: &mut [u8]) -> Result<usize, FixtureBodyError> {
80        let len = self.len();
81        let target = output
82            .get_mut(..len)
83            .ok_or(FixtureBodyError::OutputTooSmall)?;
84        match self {
85            Self::Bytes(bytes) => target.copy_from_slice(bytes),
86            Self::Repeated { byte, .. } => target.fill(byte),
87        }
88        Ok(len)
89    }
90}
91
92impl fmt::Debug for FixtureBody<'_> {
93    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
94        formatter
95            .debug_struct("FixtureBody")
96            .field("contents", &"[redacted]")
97            .field("len", &self.len())
98            .finish()
99    }
100}