use std::fmt;
use std::str::FromStr;
use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
use crate::config::Actor;
use crate::error::Error;
use crate::session::SessionId;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RequestId(pub(crate) i64);
impl fmt::Display for RequestId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "r{}", self.0)
}
}
impl FromStr for RequestId {
type Err = Error;
fn from_str(text: &str) -> Result<Self, Self::Err> {
let not_found = || Error::RequestNotFound(text.to_owned());
let digits = text.strip_prefix('r').ok_or_else(not_found)?;
let row: i64 = digits.parse().map_err(|_| not_found())?;
Ok(Self(row))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LandingRequest {
pub id: RequestId,
pub session_id: SessionId,
pub requester: Actor,
pub state: RequestState,
pub approvals: Vec<Approval>,
pub created_at_ms: i64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RequestState {
Open,
Approved,
Landed,
Parked,
Rejected,
Abandoned,
}
impl RequestState {
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
Self::Open => "open",
Self::Approved => "approved",
Self::Landed => "landed",
Self::Parked => "parked",
Self::Rejected => "rejected",
Self::Abandoned => "abandoned",
}
}
}
impl fmt::Display for RequestState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl FromStr for RequestState {
type Err = Error;
fn from_str(text: &str) -> Result<Self, Self::Err> {
match text {
"open" => Ok(Self::Open),
"approved" => Ok(Self::Approved),
"landed" => Ok(Self::Landed),
"parked" => Ok(Self::Parked),
"rejected" => Ok(Self::Rejected),
"abandoned" => Ok(Self::Abandoned),
other => Err(Error::Engine(format!("unknown request state: {other}"))),
}
}
}
impl ToSql for RequestState {
fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
Ok(ToSqlOutput::from(self.as_str()))
}
}
impl FromSql for RequestState {
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
let text = value.as_str()?;
Self::from_str(text).map_err(|error| FromSqlError::Other(error.to_string().into()))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Approval {
pub actor: Actor,
pub snapshot: String,
pub at_ms: i64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Restore {
pub source: Option<String>,
pub head: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Landing {
pub source: Option<String>,
pub snapshot: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GateOutcome {
Landed {
landings: Vec<Landing>,
},
Pending {
request: LandingRequest,
required: u32,
},
Parked {
request: LandingRequest,
landings: Vec<Landing>,
parked: Vec<Option<String>>,
},
}