saddle-boundary 0.3.34

Saddle 0.3 ProfuseContract unary boundary transport
//! Framework-owned grouped JSON encoder; values stay in their original JSON
//! spelling except the framework identity fields. No Value or float conversion.
use crate::ingress::IngressContextJson;

pub const LIMIT: usize = 4096;
pub const KEYS: [&str; 4] = ["trace-info-bin", "ldc-info-bin", "request-info-bin", "profuse-context-bin"];

#[derive(Debug)]
pub enum EncodeError { TooLarge, InvalidRange }
impl std::fmt::Display for EncodeError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(match self { Self::TooLarge => "context JSON exceeds 4096 bytes", Self::InvalidRange => "invalid validated context range" })
    }
}
impl std::error::Error for EncodeError {}

pub struct Encoded {
    bytes: [u8; LIMIT],
    lengths: [usize; 4],
    used: usize,
    profuse: bool,
}
impl Encoded {
    fn append(&mut self, bytes: &[u8]) -> Result<(), EncodeError> {
        let end = self.used.checked_add(bytes.len()).filter(|end| *end <= LIMIT).ok_or(EncodeError::TooLarge)?;
        self.bytes[self.used..end].copy_from_slice(bytes);
        self.used = end;
        Ok(())
    }
    fn string(&mut self, value: &str) -> Result<(), EncodeError> {
        self.append(b"\"")?;
        for byte in value.bytes() {
            match byte {
                b'"' => self.append(br#"\""#)?,
                b'\\' => self.append(br#"\\"#)?,
                0..=31 => {
                    const HEX: &[u8] = b"0123456789abcdef";
                    self.append(&[b'\\', b'u', b'0', b'0', HEX[(byte >> 4) as usize], HEX[(byte & 15) as usize]])?;
                }
                _ => self.append(&[byte])?,
            }
        }
        self.append(b"\"")
    }
    pub fn values(&self) -> impl Iterator<Item = (&'static str, &[u8])> {
        let mut at = 0;
        self.lengths.iter().enumerate().filter_map(move |(index, length)| {
            let start = at; at += length;
            (index != 3 || self.profuse).then_some((KEYS[index], &self.bytes[start..at]))
        })
    }
}

pub fn encode(raw: Option<&IngressContextJson>, trace: &str, rpc: &str, zone: &str, idc: &str, env: &str, request: &str, call: &str, deadline: i64) -> Result<Encoded, EncodeError> {
    let mut out = Encoded { bytes: [0; LIMIT], lengths: [0; 4], used: 0, profuse: raw.is_some_and(|raw| raw.profuse_context.is_some()) };
    if let Some(raw) = raw {
        let source = raw.trace_info.as_bytes();
        let rpc_range = &raw.rpc_value;
        let trace_range = raw.trace_value.as_ref();
        let mut patches = [(rpc_range.clone(), rpc), (trace_range.cloned().unwrap_or(0..0), trace)];
        if trace_range.is_some() && patches[1].0.start < patches[0].0.start { patches.swap(0, 1); }
        let count = if trace_range.is_some() { 2 } else { 1 };
        let mut at = 0;
        for (range, value) in &patches[..count] {
            out.append(source.get(at..range.start).ok_or(EncodeError::InvalidRange)?)?;
            out.string(value)?;
            at = range.end;
        }
        if trace_range.is_none() {
            out.append(source.get(at..source.len().checked_sub(1).ok_or(EncodeError::InvalidRange)?).ok_or(EncodeError::InvalidRange)?)?;
            out.append(b",\"traceId\":")?; out.string(trace)?; out.append(b"}")?;
        } else { out.append(source.get(at..).ok_or(EncodeError::InvalidRange)?)?; }
    } else {
        out.append(b"{\"traceId\":")?; out.string(trace)?; out.append(b",\"rpcId\":")?; out.string(rpc)?; out.append(b"}")?;
    }
    out.lengths[0] = out.used;
    if let Some(raw) = raw { out.append(raw.ldc_info.as_bytes())?; }
    else {
        out.append(b"{\"zone\":")?; out.string(zone)?; out.append(b",\"idc\":")?; out.string(idc)?; out.append(b",\"env\":")?; out.string(env)?; out.append(b"}")?;
    }
    out.lengths[1] = out.used - out.lengths[0];
    out.append(b"{\"requestId\":")?; out.string(request)?; out.append(b",\"callId\":")?; out.string(call)?; out.append(b",\"deadlineUnixMs\":")?;
    let mut digits = [0u8; 20];
    let mut n = deadline.unsigned_abs(); let mut at = digits.len();
    loop { at -= 1; digits[at] = b'0' + (n % 10) as u8; n /= 10; if n == 0 { break; } }
    if deadline < 0 { out.append(b"-")?; }
    out.append(&digits[at..])?; out.append(b"}")?;
    out.lengths[2] = out.used - out.lengths[0] - out.lengths[1];
    if let Some(value) = raw.and_then(|raw| raw.profuse_context.as_deref()) { out.append(value.as_bytes())?; out.lengths[3] = value.len(); }
    Ok(out)
}

impl Encoded {
    /// Tonic binary API does its own base64 transport encoding. For the locked
    /// tonic/bytes dependencies each value has one exact encoded buffer and a
    /// three-word shared owner installed by the first clone. Both are prepaid;
    /// later header/driver clones share them without another value allocation.
    pub fn metadata(&self, memory: &saddle_admission::RequestMemory) -> Result<saddle_admission::ReadOnlyInput<Vec<tonic::metadata::MetadataValue<tonic::metadata::Binary>>>, saddle_admission::AdmissionError> {
        let count = if self.profuse { 4 } else { 3 };
        memory.framework_output(|builder| builder.list(count, |index, builder| {
            let (_, value) = self.values().nth(index).unwrap();
            let encoded_len = (value.len() * 4 + 2) / 3;
            let layout = std::alloc::Layout::array::<u8>(encoded_len).map_err(|_| saddle_admission::AdmissionError::SizeOverflow)?;
            let metadata = builder.exact_value(layout, || tonic::metadata::MetadataValue::from_bytes(value))?;
            builder.exact_value(std::alloc::Layout::new::<[usize; 3]>(), || metadata.clone())
        }))
    }
}

pub struct ChildIds {
    rpc: [u8; 280],
    call: [u8; 280],
    rpc_len: usize,
    call_len: usize,
}
impl ChildIds {
    pub fn new(rpc: &str, call: &str, number: u64) -> Result<Self, EncodeError> {
        let mut digits = [0u8; 20]; let mut at = digits.len(); let mut n = number;
        loop { at -= 1; digits[at] = b'0' + (n % 10) as u8; n /= 10; if n == 0 { break; } }
        let digits = &digits[at..];
        let mut result = Self { rpc: [0; 280], call: [0; 280], rpc_len: 0, call_len: 0 };
        for (parent, separator, target, length) in [(rpc, b'.', &mut result.rpc, &mut result.rpc_len), (call, b'-', &mut result.call, &mut result.call_len)] {
            *length = parent.len() + 1 + digits.len();
            if *length > target.len() { return Err(EncodeError::TooLarge); }
            target[..parent.len()].copy_from_slice(parent.as_bytes()); target[parent.len()] = separator;
            target[parent.len()+1..*length].copy_from_slice(digits);
        }
        Ok(result)
    }
    pub fn rpc(&self) -> &str { std::str::from_utf8(&self.rpc[..self.rpc_len]).unwrap() }
    pub fn call(&self) -> &str { std::str::from_utf8(&self.call[..self.call_len]).unwrap() }
}

#[cfg(test)]
mod tests {
    use super::*;
    fn raw(trace: &str, profuse: Option<&str>) -> IngressContextJson {
        let rpc = trace.find("\"parent\"").unwrap();
        let id = trace.find("\"root\"").unwrap();
        IngressContextJson { trace_info: trace.into(), rpc_value: rpc..rpc+8, trace_value: Some(id..id+6), ldc_info: r#"{"zone":"z","idc":"i","env":"e","extra":[null,"中文",9007199254740993123456789]}"#.into(), profuse_context: profuse.map(str::to_owned) }
    }
    #[test]
    fn replaces_only_framework_identity_and_keeps_large_integer_spelling() {
        for source in [r#"{"rpcId":"parent","extension":{"n":9007199254740993123456789},"traceId":"root"}"#, r#"{"traceId":"root","extension":[null,"中文"],"rpcId":"parent"}"#] {
            let input = raw(source, Some("{}"));
            let value = encode(Some(&input), "root", "parent.2", "z", "i", "e", "request", "call-2", 123).unwrap();
            let values: Vec<_> = value.values().collect();
            assert_eq!(values.len(), 4);
            assert_eq!(std::str::from_utf8(values[0].1).unwrap(), source.replace("\"parent\"", "\"parent.2\""));
            assert_eq!(values[1].1, input.ldc_info.as_bytes());
            assert_eq!(values[3].1, b"{}");
        }
    }
    #[test]
    fn absence_and_empty_are_distinct_and_actual_limit_is_enforced() {
        let base = encode(None, "t", "r.1", "z", "i", "e", "q", "c-1", 123).unwrap();
        assert_eq!(base.values().count(), 3);
        let source = r#"{"rpcId":"parent","traceId":"root"}"#;
        let mut input = raw(source, Some("{}"));
        let initial = encode(Some(&input), "root", "parent.1", "z", "i", "e", "q", "c-1", 123).unwrap().used;
        input.profuse_context = Some(format!("{{\"x\":\"{}\"}}", "x".repeat(LIMIT - initial - 6)));
        assert_eq!(encode(Some(&input), "root", "parent.1", "z", "i", "e", "q", "c-1", 123).unwrap().used, LIMIT);
        input.profuse_context.as_mut().unwrap().push(' ');
        assert!(matches!(encode(Some(&input), "root", "parent.1", "z", "i", "e", "q", "c-1", 123), Err(EncodeError::TooLarge)));
    }
}