use crate::store::NodeId;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Basis {
Authored,
DirectlyObserved,
DeterministicallyDerived,
Inferred,
Heuristic,
Unresolved,
}
impl Basis {
pub const fn name(self) -> &'static str {
match self {
Basis::Authored => "authored",
Basis::DirectlyObserved => "directly-observed",
Basis::DeterministicallyDerived => "deterministically-derived",
Basis::Inferred => "inferred",
Basis::Heuristic => "heuristic",
Basis::Unresolved => "unresolved",
}
}
pub const fn is_exact(self) -> bool {
matches!(self, Basis::Authored | Basis::DirectlyObserved)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IntegrityScope {
None,
Node,
WholeSource,
}
impl IntegrityScope {
pub const fn name(self) -> &'static str {
match self {
IntegrityScope::None => "none",
IntegrityScope::Node => "node",
IntegrityScope::WholeSource => "whole-source",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AnswerValue {
Bytes(Vec<u8>),
Text(String),
Json(String),
None,
}
impl AnswerValue {
pub fn byte_len(&self) -> u64 {
match self {
AnswerValue::Bytes(b) => b.len() as u64,
AnswerValue::Text(s) | AnswerValue::Json(s) => s.len() as u64,
AnswerValue::None => 0,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FieldAnswer {
pub value: AnswerValue,
pub basis: Basis,
pub selector: String,
pub representation: String,
pub source_span: Option<(u64, u64)>,
pub provenance: String,
pub dependency_ids: Vec<NodeId>,
pub integrity_scope: IntegrityScope,
pub exact: bool,
}
pub(crate) fn json_escape(s: &str) -> String {
let mut out = String::with_capacity(s.len() + 2);
for c in s.chars() {
match c {
'"' => out.push_str("\\\""),
'\\' => out.push_str("\\\\"),
'\n' => out.push_str("\\n"),
'\r' => out.push_str("\\r"),
'\t' => out.push_str("\\t"),
c if (c as u32) < 0x20 => out.push_str(&format!("\\u{:04x}", c as u32)),
c => out.push(c),
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn only_authored_and_observed_are_exact() {
assert!(Basis::Authored.is_exact());
assert!(Basis::DirectlyObserved.is_exact());
assert!(!Basis::DeterministicallyDerived.is_exact());
assert!(!Basis::Inferred.is_exact());
assert!(!Basis::Heuristic.is_exact());
assert!(!Basis::Unresolved.is_exact());
}
#[test]
fn json_escape_is_deterministic_and_safe() {
assert_eq!(json_escape("a\"b\\c\nd"), "a\\\"b\\\\c\\nd");
assert_eq!(json_escape("plain"), "plain");
}
}