aede_core/parental/
document.rs

1//! Adapter to the existing independently versioned backup JSON vocabulary.
2use super::ParentalStore;
3use crate::{json::Json, store::StoreError};
4
5/// Preserve the protected parental document inside an Aède backup.
6/// This document contains account restrictions and usage, never credentials.
7pub fn to_json(store: &ParentalStore) -> Json {
8    // The derived model contains no floating-point values or fallible custom
9    // serializers. Bounds are validated before persistence/backup publication.
10    convert(serde_json::json!(store))
11}
12/// Validate a parental part independently from the other backup stores.
13pub fn from_json(document: &Json) -> Result<ParentalStore, StoreError> {
14    let bytes = document.to_string_compact();
15    if bytes.len() > 8 * 1024 * 1024 {
16        return Err(StoreError::Invalid("parental backup part exceeds 8 MiB"));
17    }
18    let value: ParentalStore = serde_json::from_str(&bytes)
19        .map_err(|_| StoreError::Invalid("invalid parental backup part"))?;
20    value
21        .validate()
22        .map_err(|_| StoreError::Invalid("inconsistent parental backup part"))?;
23    Ok(value)
24}
25fn convert(value: serde_json::Value) -> Json {
26    match value {
27        serde_json::Value::Null => Json::Null,
28        serde_json::Value::Bool(value) => Json::Bool(value),
29        serde_json::Value::Number(value) => value.as_f64().map_or(Json::Null, Json::Num),
30        serde_json::Value::String(value) => Json::Str(value),
31        serde_json::Value::Array(values) => Json::Arr(values.into_iter().map(convert).collect()),
32        serde_json::Value::Object(values) => Json::Obj(
33            values
34                .into_iter()
35                .map(|(key, value)| (key, convert(value)))
36                .collect(),
37        ),
38    }
39}