1use std::fmt;
2use std::path::PathBuf;
3use std::str::FromStr;
4
5use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
6
7use crate::config::Actor;
8use crate::error::Error;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct Instruction {
14 pub summary: String,
16 pub run_ref: Option<String>,
19 pub verbatim: Option<String>,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub struct SessionId(pub(crate) i64);
26
27impl fmt::Display for SessionId {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 write!(f, "s{}", self.0)
30 }
31}
32
33impl FromStr for SessionId {
34 type Err = Error;
35
36 fn from_str(text: &str) -> Result<Self, Self::Err> {
37 let not_found = || Error::SessionNotFound(text.to_owned());
38 let digits = text.strip_prefix('s').ok_or_else(not_found)?;
39 let row: i64 = digits.parse().map_err(|_| not_found())?;
40 Ok(Self(row))
41 }
42}
43
44#[derive(Debug, Clone, PartialEq, Eq)]
47pub struct Session {
48 pub id: SessionId,
50 pub actor: Actor,
52 pub state: SessionState,
54 pub change_id: String,
58 pub changes: Vec<SourceChange>,
61 pub working_copy: PathBuf,
66 pub instruction_summary: String,
68 pub instruction_run_ref: Option<String>,
70 pub opened_at_ms: i64,
72}
73
74#[derive(Debug, Clone, PartialEq, Eq)]
76pub struct SourceChange {
77 pub source: Option<String>,
79 pub change_id: String,
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub enum SessionState {
87 Open,
89 Landed,
91 Abandoned,
93}
94
95impl SessionState {
96 #[must_use]
98 pub fn as_str(self) -> &'static str {
99 match self {
100 Self::Open => "open",
101 Self::Landed => "landed",
102 Self::Abandoned => "abandoned",
103 }
104 }
105}
106
107impl fmt::Display for SessionState {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 f.write_str(self.as_str())
110 }
111}
112
113impl FromStr for SessionState {
114 type Err = Error;
115
116 fn from_str(text: &str) -> Result<Self, Self::Err> {
117 match text {
118 "open" => Ok(Self::Open),
119 "landed" => Ok(Self::Landed),
120 "abandoned" => Ok(Self::Abandoned),
121 other => Err(Error::Engine(format!("unknown session state: {other}"))),
122 }
123 }
124}
125
126impl ToSql for SessionState {
127 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
128 Ok(ToSqlOutput::from(self.as_str()))
129 }
130}
131
132impl FromSql for SessionState {
133 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
134 let text = value.as_str()?;
135 Self::from_str(text).map_err(|error| FromSqlError::Other(error.to_string().into()))
136 }
137}