pub fn pae(payload_type: &str, payload: &[u8]) -> Vec<u8> {
let type_len = payload_type.len();
let pay_len = payload.len();
let cap = 7
+ digits(type_len)
+ 1
+ type_len
+ 1
+ digits(pay_len)
+ 1
+ pay_len;
let mut buf = Vec::with_capacity(cap);
buf.extend_from_slice(b"DSSEv1 ");
buf.extend_from_slice(type_len.to_string().as_bytes());
buf.push(b' ');
buf.extend_from_slice(payload_type.as_bytes());
buf.push(b' ');
buf.extend_from_slice(pay_len.to_string().as_bytes());
buf.push(b' ');
buf.extend_from_slice(payload);
buf
}
fn digits(n: usize) -> usize {
if n == 0 { 1 } else { (n as f64).log10().floor() as usize + 1 }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn format_matches_spec() {
let got = pae("application/example", b"hello");
assert_eq!(got, b"DSSEv1 19 application/example 5 hello");
}
#[test]
fn empty_payload() {
let got = pae("text/plain", b"");
assert_eq!(got, b"DSSEv1 10 text/plain 0 ");
}
#[test]
fn deterministic() {
let payload = br#"{"type":"treeship/action/v1"}"#;
let a = pae("application/vnd.treeship.action.v1+json", payload);
let b = pae("application/vnd.treeship.action.v1+json", payload);
assert_eq!(a, b);
}
#[test]
fn type_isolation() {
let payload = b"{\"x\":1}";
let a = pae("application/type-a", payload);
let b = pae("application/type-b", payload);
assert_ne!(a, b, "PAE must differ for different payloadTypes");
}
#[test]
fn payload_isolation() {
let a = pae("application/example", b"hello");
let b = pae("application/example", b"world");
assert_ne!(a, b);
}
#[test]
fn capacity_is_exact() {
let pt = "application/vnd.treeship.action.v1+json";
let payload = br#"{"type":"treeship/action/v1","actor":"agent://researcher"}"#;
let result = pae(pt, payload);
assert_eq!(result.capacity(), result.len());
}
#[test]
fn treeship_action_type() {
let pt = "application/vnd.treeship.action.v1+json";
let payload = b"{}";
let got = pae(pt, payload);
assert_eq!(pt.len(), 39, "sanity: payload type length");
let want = b"DSSEv1 39 application/vnd.treeship.action.v1+json 2 {}";
assert_eq!(got, want.as_ref());
}
}