use base64::Engine;
use serde_json::{json, Value};
pub fn encoded_bytes_value(bytes: &[u8]) -> Value {
json!({
"__agentOSType": "bytes",
"base64": base64::engine::general_purpose::STANDARD.encode(bytes),
})
}
pub fn decode_encoded_bytes_value(value: &Value) -> Result<Vec<u8>, String> {
let Some(base64_value) = value
.get("__agentOSType")
.and_then(Value::as_str)
.filter(|kind| *kind == "bytes")
.and_then(|_| value.get("base64"))
.and_then(Value::as_str)
else {
return Err(String::from("must be a string or encoded bytes payload"));
};
decode_base64(base64_value)
}
pub fn bridge_buffer_value(bytes: &[u8]) -> Value {
json!({
"__type": "buffer",
"value": base64::engine::general_purpose::STANDARD.encode(bytes),
})
}
pub fn decode_bridge_buffer_value(value: &Value) -> Result<Vec<u8>, String> {
let base64_value = value
.as_object()
.filter(|object| object.get("__type").and_then(Value::as_str) == Some("buffer"))
.and_then(|object| object.get("value"))
.and_then(Value::as_str)
.ok_or_else(|| String::from("must be a serialized bridge buffer"))?;
decode_base64(base64_value)
}
pub fn decode_base64(value: &str) -> Result<Vec<u8>, String> {
base64::engine::general_purpose::STANDARD
.decode(value)
.map_err(|error| format!("contains invalid base64: {error}"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trips_encoded_bytes_payload() {
let value = encoded_bytes_value(b"hello");
assert_eq!(decode_encoded_bytes_value(&value), Ok(b"hello".to_vec()));
}
#[test]
fn round_trips_bridge_buffer_payload() {
let value = bridge_buffer_value(b"secret");
assert_eq!(decode_bridge_buffer_value(&value), Ok(b"secret".to_vec()));
}
#[test]
fn rejects_wrong_payload_shapes() {
assert_eq!(
decode_encoded_bytes_value(&json!({ "__agentOSType": "text", "base64": "aGk=" })),
Err(String::from("must be a string or encoded bytes payload"))
);
assert_eq!(
decode_bridge_buffer_value(&json!({ "__type": "bytes", "value": "aGk=" })),
Err(String::from("must be a serialized bridge buffer"))
);
}
#[test]
fn labels_invalid_base64() {
assert!(decode_base64("not base64!")
.expect_err("invalid base64 should fail")
.starts_with("contains invalid base64:"));
}
}