use super::constraint::TypeConstraint;
use super::section::SectionSchema;
pub fn image_schema() -> SectionSchema {
SectionSchema::new("image")
.description("Image capture metadata")
.field("width", TypeConstraint::AnyUnsigned)
.field("height", TypeConstraint::AnyUnsigned)
.field("format", TypeConstraint::AnyString) .field("bit_depth", TypeConstraint::AnyUnsigned) .field("timestamp", TypeConstraint::AnyEagleTime)
.field("exposure_time", TypeConstraint::AnyFloat) .field("iso", TypeConstraint::AnyUnsigned)
.field("focal_length", TypeConstraint::AnyFloat) .field("aperture", TypeConstraint::AnyFloat) }
pub fn camera_schema() -> SectionSchema {
SectionSchema::new("camera")
.description("Camera hardware configuration")
.field("model", TypeConstraint::AnyString)
.field("serial", TypeConstraint::AnyString)
.field("sensor_width", TypeConstraint::AnyFloat) .field("sensor_height", TypeConstraint::AnyFloat) .field("resolution_x", TypeConstraint::AnyUnsigned)
.field("resolution_y", TypeConstraint::AnyUnsigned)
.field("pixel_size", TypeConstraint::AnyFloat) .field("calibrated", TypeConstraint::AnyUnsigned) .field("timestamp", TypeConstraint::AnyEagleTime)
}
pub fn audio_schema() -> SectionSchema {
SectionSchema::new("audio")
.description("Audio stream metadata")
.field("sample_rate", TypeConstraint::AnyUnsigned) .field("channels", TypeConstraint::AnyUnsigned) .field("bit_depth", TypeConstraint::AnyUnsigned) .field("format", TypeConstraint::AnyString) .field("duration", TypeConstraint::AnyFloat) .field("timestamp", TypeConstraint::AnyEagleTime)
}
pub fn network_peer_schema() -> SectionSchema {
SectionSchema::new("network_peer")
.description("Network peer information")
.field("handle_hash", TypeConstraint::Blake3Provenance)
.field("device_pubkey", TypeConstraint::X25519Key)
.field("ip_address", TypeConstraint::AnyString)
.field("port", TypeConstraint::AnyUnsigned)
.field("last_seen", TypeConstraint::AnyEagleTime)
.field("protocol_version", TypeConstraint::AnyUnsigned)
}
pub fn announce_schema() -> SectionSchema {
SectionSchema::new("announce")
.description("FGTW bootstrap announce message")
.field("challenge_hash", TypeConstraint::Blake3Rolling)
.field("handle_hash", TypeConstraint::Blake3Provenance)
.field("port", TypeConstraint::AnyUnsigned)
.field("protocol_version", TypeConstraint::AnyUnsigned)
}
pub fn pipe_message_schema() -> SectionSchema {
SectionSchema::new("pipe_message")
.field("op", TypeConstraint::AsciiText)
.field("id", TypeConstraint::AnyUnsigned)
.field("n", TypeConstraint::AnyUnsigned)
.field("err", TypeConstraint::AsciiText)
.field("name", TypeConstraint::AsciiText)
.field("ver", TypeConstraint::AnyUnsigned)
.field("did", TypeConstraint::Blake3Provenance)
.field("clk", TypeConstraint::AnyUnsigned)
.field("up", TypeConstraint::AnyUnsigned)
.field("ms", TypeConstraint::AnyUnsigned)
.field("data", TypeConstraint::Wrapped(b'b'))
.field("pipe", TypeConstraint::AnyUnsigned)
}
pub fn error_schema() -> SectionSchema {
SectionSchema::new("error")
.field("reason", TypeConstraint::AnyString)
.field("detail", TypeConstraint::AnyString)
}
pub fn spectral_image_schema() -> SectionSchema {
SectionSchema::new("spectral_image")
.description("Spectral-first raw image: K channels of sensor counts")
.field("width", TypeConstraint::AnyUnsigned)
.field("height", TypeConstraint::AnyUnsigned)
.field("channel_count", TypeConstraint::AnyUnsigned)
.field("black", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyFloat)))
.field("white", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyFloat)))
.field("channel_names", TypeConstraint::AnyString) .field("layout", TypeConstraint::AnyString) .field("cfa", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyUnsigned))) .field("make", TypeConstraint::AnyString)
.field("model", TypeConstraint::AnyString)
.field("samples", TypeConstraint::BitPackedTensor)
}
pub fn spectral_response_schema() -> SectionSchema {
SectionSchema::new("spectral_response")
.description("Per-channel spectral sensitivity curves")
.field("curve_start", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyFloat)))
.field("curve_step", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyFloat)))
.field("curve_counts", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyUnsigned)))
.field("curve_values", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyFloat)))
}
pub fn provenance_schema() -> SectionSchema {
SectionSchema::new("provenance")
.description("ihi identity ingredients for a spectral image")
.field("handle", TypeConstraint::AnyString)
.field("calibration_hash", TypeConstraint::AnyHash)
.field("camera_ihi", TypeConstraint::AnyHash)
.field("identity", TypeConstraint::AnyHash)
}
pub fn colour_profile_schema() -> SectionSchema {
SectionSchema::new("colour_profile")
.description("Tiered camera->VSF-RGB characterization")
.field("target", TypeConstraint::AnyString)
.field("count", TypeConstraint::AnyUnsigned)
.field("matrices", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyFloat)))
.field("sources", TypeConstraint::AnyString) .field("classes", TypeConstraint::AnyString) .field("grades", TypeConstraint::AnyString) .field("illuminants", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyUnsigned)))
.field("transfers", TypeConstraint::AnyString) .field("dng_colormatrix1", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyFloat)))
.field("dng_illuminant1", TypeConstraint::AnyUnsigned)
.field("dng_colormatrix2", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyFloat)))
.field("dng_illuminant2", TypeConstraint::AnyUnsigned)
.field("patches_camera", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyFloat)))
.field("patches_reference", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyFloat)))
.field("cal_target_type", TypeConstraint::AnyUnsigned)
.field("cal_target_serial", TypeConstraint::AnyUnsigned)
.field("cal_timestamp", TypeConstraint::AnyString)
}
pub fn view_transform_schema() -> SectionSchema {
SectionSchema::new("view_transform")
.description("Ordered view transformations (translateration log)")
.field("space", TypeConstraint::AnyString)
.field("ops", TypeConstraint::AnyString) .field("classes", TypeConstraint::AnyString) .field("param_counts", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyUnsigned)))
.field("params", TypeConstraint::Tensor(Box::new(TypeConstraint::AnyFloat)))
}
#[cfg(feature = "registry")]
pub fn register_official_schemas(registry: &super::registry::SchemaRegistry) {
registry.register(image_schema());
registry.register(camera_schema());
registry.register(audio_schema());
registry.register(network_peer_schema());
registry.register(announce_schema());
registry.register(pipe_message_schema());
registry.register(error_schema());
registry.register(spectral_image_schema());
registry.register(spectral_response_schema());
registry.register(provenance_schema());
registry.register(colour_profile_schema());
registry.register(view_transform_schema());
}
#[cfg(test)]
mod tests {
use super::*;
use crate::schema::registry::SchemaRegistry;
#[test]
fn test_image_schema_creation() {
let schema = image_schema();
assert_eq!(schema.name, "image");
assert!(schema.fields.len() >= 5);
}
#[test]
fn test_camera_schema_creation() {
let schema = camera_schema();
assert_eq!(schema.name, "camera");
assert!(schema.fields.len() >= 5);
}
#[test]
fn test_audio_schema_creation() {
let schema = audio_schema();
assert_eq!(schema.name, "audio");
assert!(schema.fields.iter().any(|f| f.name == "sample_rate"));
}
#[test]
fn test_network_peer_schema() {
let schema = network_peer_schema();
assert_eq!(schema.name, "network_peer");
assert!(schema.fields.iter().any(|f| f.name == "handle_hash"));
}
#[test]
fn test_announce_schema() {
let schema = announce_schema();
assert_eq!(schema.name, "announce");
assert!(schema.fields.iter().any(|f| f.name == "challenge_hash"));
}
#[test]
fn test_register_all() {
let registry = SchemaRegistry::new();
register_official_schemas(®istry);
assert!(registry.get("image").is_ok());
assert!(registry.get("camera").is_ok());
assert!(registry.get("audio").is_ok());
assert!(registry.get("network_peer").is_ok());
assert!(registry.get("announce").is_ok());
}
}