use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ConformanceLevel {
#[serde(rename = "L0")]
L0,
#[serde(rename = "L1")]
L1,
#[serde(rename = "L2")]
L2,
}
impl ConformanceLevel {
pub fn level(&self) -> u8 {
match self {
Self::L0 => 0,
Self::L1 => 1,
Self::L2 => 2,
}
}
pub fn satisfies(&self, required: &Self) -> bool {
self.level() >= required.level()
}
}
impl std::fmt::Display for ConformanceLevel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::L0 => write!(f, "L0"),
Self::L1 => write!(f, "L1"),
Self::L2 => write!(f, "L2"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DidDocument {
pub id: String,
pub verification_key: String,
pub kind: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LineageProof {
pub chain: Vec<LineageLink>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LineageLink {
pub from: String,
pub to: String,
pub signature: String,
pub issued_at: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiscoveryDocument {
pub auth_endpoint: String,
pub supported_versions: Vec<u32>,
pub server_did: String,
pub required_conformance_level: ConformanceLevel,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn conformance_level_satisfies() {
assert!(ConformanceLevel::L2.satisfies(&ConformanceLevel::L0));
assert!(ConformanceLevel::L2.satisfies(&ConformanceLevel::L1));
assert!(ConformanceLevel::L2.satisfies(&ConformanceLevel::L2));
assert!(ConformanceLevel::L1.satisfies(&ConformanceLevel::L0));
assert!(!ConformanceLevel::L0.satisfies(&ConformanceLevel::L1));
}
#[test]
fn conformance_level_display() {
assert_eq!(ConformanceLevel::L0.to_string(), "L0");
assert_eq!(ConformanceLevel::L1.to_string(), "L1");
assert_eq!(ConformanceLevel::L2.to_string(), "L2");
}
#[test]
fn discovery_document_serializes() {
let doc = DiscoveryDocument {
auth_endpoint: "/.well-known/openagent/auth".into(),
supported_versions: vec![1],
server_did: "did:oas:l1fe:service:api".into(),
required_conformance_level: ConformanceLevel::L2,
};
let json = serde_json::to_string(&doc);
assert!(json.is_ok());
let parsed: Result<DiscoveryDocument, _> = serde_json::from_str(&json.unwrap_or_default());
assert!(parsed.is_ok());
}
#[test]
fn did_document_round_trip() {
let doc = DidDocument {
id: "did:oas:l1fe:agent:test".into(),
verification_key: "z6Mk...".into(),
kind: "agent".into(),
parent: Some("did:oas:l1fe:hmr:alice".into()),
};
let json = serde_json::to_string(&doc);
assert!(json.is_ok());
}
}