use serde_json::{Map, Value};
use super::convs::AgentState;
use super::fields;
pub(crate) const KIND: &str = "rail";
pub const NO_COMMIT: &str = "—";
const SHORT_OID: usize = 7;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Rail {
pub notches: Vec<Notch>,
pub cards: Vec<Card>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Notch {
pub seq: String,
pub commit: Option<String>,
pub budget: u64,
pub seat: Option<Seat>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Seat {
pub row: String,
pub cut: u64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Card {
pub agent: String,
pub name: String,
pub fork: String,
pub state: AgentState,
pub tokens: u64,
pub tail: Option<String>,
pub notch: u64,
}
impl Notch {
pub fn operable(&self) -> bool {
self.commit.is_some()
}
pub fn short(&self) -> String {
self.commit.as_ref().map_or_else(
|| NO_COMMIT.to_owned(),
|oid| oid.get(..SHORT_OID).unwrap_or(oid).to_owned(),
)
}
}
pub(crate) fn rail(obj: &Map<String, Value>) -> Result<Rail, String> {
Ok(Rail {
notches: fields::rows(obj, notch)?,
cards: fields::list(obj, "cards", card)?,
})
}
fn notch(value: &Value) -> Result<Notch, String> {
let obj: &Map<String, Value> = value.as_object().ok_or("notch: not an object")?;
let seat = match fields::opt_text(obj, "row")? {
None => None,
Some(row) => Some(Seat {
row,
cut: fields::count(obj, "cut")?,
}),
};
Ok(Notch {
seq: fields::text(obj, "seq")?,
commit: fields::opt_text(obj, "commit")?,
budget: fields::count(obj, "budget")?,
seat,
})
}
fn card(value: &Value) -> Result<Card, String> {
let obj: &Map<String, Value> = value.as_object().ok_or("card: not an object")?;
Ok(Card {
agent: fields::text(obj, "agent")?,
name: fields::text(obj, "name")?,
fork: fields::text(obj, "fork")?,
state: AgentState::of(&fields::text(obj, "state")?),
tokens: fields::count(obj, "tokens")?,
tail: fields::opt_text(obj, "tail")?,
notch: fields::count(obj, "notch")?,
})
}
#[cfg(test)]
mod tests;