use serde::Deserialize;
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
pub struct ParticipantMetaContract {
pub role: String,
pub generation: String,
pub contract: String,
#[serde(default)]
pub external: bool,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
pub struct ParticipantMeta {
pub participant_api: String,
pub contracts: Vec<ParticipantMetaContract>,
}
pub fn parse_participant_metadata(section_bytes: &[u8]) -> serde_json::Result<ParticipantMeta> {
serde_json::from_slice(section_bytes)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_the_current_section_shape() {
let json = br#"{"participant_api":"Api","contracts":[
{"role":"subscribe","generation":"y2026_1","contract":"drive::Target","external":false},
{"role":"publish","generation":"y2026_1","contract":"drive::State","external":false}
]}"#;
let meta = parse_participant_metadata(json).expect("valid metadata JSON");
assert_eq!(meta.participant_api, "Api");
assert_eq!(
meta.contracts,
vec![
ParticipantMetaContract {
role: "subscribe".to_string(),
generation: "y2026_1".to_string(),
contract: "drive::Target".to_string(),
external: false,
},
ParticipantMetaContract {
role: "publish".to_string(),
generation: "y2026_1".to_string(),
contract: "drive::State".to_string(),
external: false,
},
]
);
}
#[test]
fn external_true_is_recorded() {
let json = br#"{"participant_api":"Api","contracts":[
{"role":"subscribe","generation":"y2026_1","contract":"drive::Target","external":true}
]}"#;
let meta = parse_participant_metadata(json).expect("valid metadata JSON");
assert!(meta.contracts[0].external);
}
#[test]
fn missing_external_key_defaults_to_false() {
let json = br#"{"participant_api":"Api","contracts":[
{"role":"publish","generation":"y2026_1","contract":"drive::State"}
]}"#;
let meta = parse_participant_metadata(json).expect("valid metadata JSON");
assert!(!meta.contracts[0].external);
}
#[test]
fn empty_contracts_list_parses() {
let json = br#"{"participant_api":"()","contracts":[]}"#;
let meta = parse_participant_metadata(json).expect("valid metadata JSON");
assert!(meta.contracts.is_empty());
}
#[test]
fn malformed_json_is_a_clear_error() {
let err = parse_participant_metadata(b"not json").unwrap_err();
assert!(err.to_string().contains("expected"));
}
}