r402_core/wire/base64.rs
1//! Lazy base64 byte container.
2
3use std::fmt::{self, Display, Formatter};
4
5use base64::Engine;
6use base64::engine::general_purpose::STANDARD as B64;
7
8/// Raw bytes holding the base64-encoded ASCII representation of some payload.
9///
10/// Useful as a field type for x402 wire messages that transport arbitrary
11/// binary data (for example, the raw Solana transaction wrapped in
12/// [`PaymentPayload`](super::PaymentPayload)). Encoding is eager, decoding
13/// is deferred.
14///
15/// # Examples
16///
17/// ```
18/// use r402_core::wire::Base64Bytes;
19///
20/// let encoded = Base64Bytes::encode(b"hello world");
21/// let decoded = encoded.decode().unwrap();
22/// assert_eq!(decoded, b"hello world");
23/// ```
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct Base64Bytes(pub Vec<u8>);
26
27impl Base64Bytes {
28 /// Decodes the inner base64 bytes into their raw binary form.
29 ///
30 /// # Errors
31 ///
32 /// Returns a [`base64::DecodeError`] when the stored bytes are not
33 /// valid base64.
34 pub fn decode(&self) -> Result<Vec<u8>, base64::DecodeError> {
35 B64.decode(&self.0)
36 }
37
38 /// Encodes arbitrary bytes into a [`Base64Bytes`] wrapper.
39 #[must_use]
40 pub fn encode<T: AsRef<[u8]>>(input: T) -> Self {
41 Self(B64.encode(input.as_ref()).into_bytes())
42 }
43}
44
45impl AsRef<[u8]> for Base64Bytes {
46 fn as_ref(&self) -> &[u8] {
47 &self.0
48 }
49}
50
51impl From<&[u8]> for Base64Bytes {
52 fn from(slice: &[u8]) -> Self {
53 Self(slice.to_vec())
54 }
55}
56
57impl Display for Base64Bytes {
58 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
59 f.write_str(&String::from_utf8_lossy(&self.0))
60 }
61}