vv-agent 0.8.0

VectorVein agent runtime, SDK, CLI, tools, and workspace backends
Documentation
use super::*;

pub fn resolve_json_pointer<'a>(value: &'a Value, pointer: &str) -> CheckpointResult<&'a Value> {
    let tokens = pointer_tokens(pointer)?;
    let mut current = value;
    for token in tokens {
        current = match current {
            Value::Object(object) => object.get(&token).ok_or_else(|| {
                CheckpointError::new(
                    "checkpoint_credential_slot_unresolved",
                    format!("JSON pointer {pointer} does not resolve"),
                )
            })?,
            Value::Array(array) => {
                let index = token.parse::<usize>().map_err(|_| {
                    CheckpointError::new(
                        "checkpoint_credential_slot_unresolved",
                        format!("JSON pointer {pointer} has an invalid array index"),
                    )
                })?;
                array.get(index).ok_or_else(|| {
                    CheckpointError::new(
                        "checkpoint_credential_slot_unresolved",
                        format!("JSON pointer {pointer} does not resolve"),
                    )
                })?
            }
            _ => {
                return Err(CheckpointError::new(
                    "checkpoint_credential_slot_unresolved",
                    format!("JSON pointer {pointer} does not resolve"),
                ));
            }
        };
    }
    Ok(current)
}

pub fn set_json_pointer(
    value: &mut Value,
    pointer: &str,
    replacement: Value,
) -> CheckpointResult<()> {
    let tokens = pointer_tokens(pointer)?;
    if tokens.is_empty() {
        *value = replacement;
        return Ok(());
    }
    let mut current = value;
    for token in &tokens[..tokens.len() - 1] {
        current = match current {
            Value::Object(object) => object.get_mut(token).ok_or_else(|| {
                CheckpointError::new(
                    "checkpoint_credential_slot_unresolved",
                    format!("JSON pointer {pointer} does not resolve"),
                )
            })?,
            Value::Array(array) => {
                let index = token.parse::<usize>().map_err(|_| {
                    CheckpointError::new(
                        "checkpoint_credential_slot_unresolved",
                        format!("JSON pointer {pointer} has an invalid array index"),
                    )
                })?;
                array.get_mut(index).ok_or_else(|| {
                    CheckpointError::new(
                        "checkpoint_credential_slot_unresolved",
                        format!("JSON pointer {pointer} does not resolve"),
                    )
                })?
            }
            _ => {
                return Err(CheckpointError::new(
                    "checkpoint_credential_slot_unresolved",
                    format!("JSON pointer {pointer} does not resolve"),
                ));
            }
        };
    }
    let last = tokens.last().expect("non-empty pointer tokens");
    match current {
        Value::Object(object) => {
            if !object.contains_key(last) {
                return Err(CheckpointError::new(
                    "checkpoint_credential_slot_unresolved",
                    format!("JSON pointer {pointer} does not resolve"),
                ));
            }
            object.insert(last.clone(), replacement);
        }
        Value::Array(array) => {
            let index = last.parse::<usize>().map_err(|_| {
                CheckpointError::new(
                    "checkpoint_credential_slot_unresolved",
                    format!("JSON pointer {pointer} has an invalid array index"),
                )
            })?;
            let Some(item) = array.get_mut(index) else {
                return Err(CheckpointError::new(
                    "checkpoint_credential_slot_unresolved",
                    format!("JSON pointer {pointer} does not resolve"),
                ));
            };
            *item = replacement;
        }
        _ => {
            return Err(CheckpointError::new(
                "checkpoint_credential_slot_unresolved",
                format!("JSON pointer {pointer} does not resolve"),
            ));
        }
    }
    Ok(())
}

pub(in crate::checkpoint) fn validate_pointer(pointer: &str) -> CheckpointResult<()> {
    pointer_tokens(pointer).map(|_| ())
}

fn pointer_tokens(pointer: &str) -> CheckpointResult<Vec<String>> {
    if pointer.is_empty() {
        return Ok(Vec::new());
    }
    if !pointer.starts_with('/') {
        return Err(CheckpointError::new(
            "checkpoint_credential_slots_invalid",
            "JSON pointer must be empty or start with '/'",
        ));
    }
    pointer
        .split('/')
        .skip(1)
        .map(|raw| {
            let mut token = String::with_capacity(raw.len());
            let bytes = raw.as_bytes();
            let mut index = 0;
            while index < bytes.len() {
                if bytes[index] != b'~' {
                    let character = raw[index..].chars().next().expect("valid UTF-8");
                    token.push(character);
                    index += character.len_utf8();
                    continue;
                }
                if index + 1 >= bytes.len() {
                    return Err(CheckpointError::new(
                        "checkpoint_credential_slots_invalid",
                        "JSON pointer contains an invalid escape",
                    ));
                }
                match bytes[index + 1] {
                    b'0' => token.push('~'),
                    b'1' => token.push('/'),
                    _ => {
                        return Err(CheckpointError::new(
                            "checkpoint_credential_slots_invalid",
                            "JSON pointer contains an invalid escape",
                        ));
                    }
                }
                index += 2;
            }
            Ok(token)
        })
        .collect()
}