use std::fmt;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use waos_package::ProgramId;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ToWaOS {
Run {
id: ProgramId,
#[serde(with = "serde_bytes")]
component: Vec<u8>,
},
Open { id: ProgramId, files: Vec<PathBuf> },
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum FromWaOS {
Started,
Output {
stream: OutputStream,
#[serde(with = "serde_bytes")]
bytes: Vec<u8>,
},
Ended(RunEnd),
Refused(String),
Opened,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum OutputStream {
Stdout,
Stderr,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum RunEnd {
Returned { success: bool },
Failed(String),
Stopped,
Replaced,
}
impl fmt::Debug for ToWaOS {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ToWaOS::Run { id, component } => f
.debug_struct("Run")
.field("id", &format_args!("{id}"))
.field("component", &format_args!("{} bytes", component.len()))
.finish(),
ToWaOS::Open { id, files } => f
.debug_struct("Open")
.field("id", &format_args!("{id}"))
.field("files", files)
.finish(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, PartialEq, Serialize, Deserialize)]
enum ToWaOSAsSequence {
Run { id: ProgramId, component: Vec<u8> },
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
enum FromWaOSAsSequence {
Started,
Output {
stream: OutputStream,
bytes: Vec<u8>,
},
}
fn bytes() -> Vec<u8> {
(0..=u8::MAX).cycle().take(1000).collect()
}
#[test]
fn a_run_is_encoded_as_it_was_when_its_component_was_a_sequence() {
let id: ProgramId = "dev.example.triangle".parse().unwrap();
let run = ToWaOS::Run {
id: id.clone(),
component: bytes(),
};
let as_sequence = ToWaOSAsSequence::Run {
id,
component: bytes(),
};
let encoded = postcard::to_allocvec(&run).unwrap();
assert_eq!(encoded, postcard::to_allocvec(&as_sequence).unwrap());
assert_eq!(
postcard::from_bytes::<ToWaOSAsSequence>(&encoded).unwrap(),
as_sequence
);
}
#[test]
fn output_is_encoded_as_it_was_when_its_bytes_were_a_sequence() {
let output = FromWaOS::Output {
stream: OutputStream::Stderr,
bytes: bytes(),
};
let as_sequence = FromWaOSAsSequence::Output {
stream: OutputStream::Stderr,
bytes: bytes(),
};
let encoded = postcard::to_allocvec(&output).unwrap();
assert_eq!(encoded, postcard::to_allocvec(&as_sequence).unwrap());
assert_eq!(postcard::from_bytes::<FromWaOS>(&encoded).unwrap(), output);
}
#[test]
fn an_opening_reads_back_as_written_and_prints_its_files() {
let open = ToWaOS::Open {
id: "dev.example.notes".parse().unwrap(),
files: vec![PathBuf::from("/Users/me/notes.md")],
};
let encoded = postcard::to_allocvec(&open).unwrap();
assert_eq!(postcard::from_bytes::<ToWaOS>(&encoded).unwrap(), open);
assert_eq!(
format!("{open:?}"),
"Open { id: dev.example.notes, files: [\"/Users/me/notes.md\"] }"
);
let opened = postcard::to_allocvec(&FromWaOS::Opened).unwrap();
assert_eq!(
postcard::from_bytes::<FromWaOS>(&opened).unwrap(),
FromWaOS::Opened
);
}
#[test]
fn a_run_prints_its_component_as_a_count() {
let run = ToWaOS::Run {
id: "dev.example.triangle".parse().unwrap(),
component: vec![0; 1024],
};
assert_eq!(
format!("{run:?}"),
"Run { id: dev.example.triangle, component: 1024 bytes }"
);
}
}