1#![doc = include_str!("../README.md")]
2#![doc = include_str!("../tests/data/qemu-config.json")]
16#![doc = include_str!("../tests/data/container-config.json")]
27use std::time::SystemTime;
29use std::future::Future;
30use tokio::io::AsyncWrite;
31use tokio::io::AsyncRead;
32
33#[derive(Debug, PartialEq)]
35pub enum Key {
36 Enter,
37 Backspace,
38 Char {
39 chr: char
40 }
41}
42
43#[derive(Debug, PartialEq)]
45pub enum Status {
46 Running,
47 Paused,
48 Suspended,
49 Shutdown,
50}
51
52#[derive(Debug, PartialEq)]
54pub enum EventKind {
55 Shutdown,
56 Resume,
57 Pause,
58 Suspend,
59}
60
61pub struct Event {
63 pub kind: EventKind,
65
66 pub timestamp: SystemTime,
68}
69
70pub trait EventSubscriber: Send + Sync + 'static {
72 fn on_event(&mut self, event: &Event);
74}
75
76pub trait SystemHarness<'sys> {
78
79 type Terminal: SystemTerminal;
80
81 fn terminal(&'sys mut self) -> impl Future<Output = Result<Self::Terminal, Error>>;
83
84 fn pause(&mut self) -> impl Future<Output = Result<(), Error>>;
86
87 fn resume(&mut self) -> impl Future<Output = Result<(), Error>>;
89
90 fn shutdown(&mut self) -> impl Future<Output = Result<(), Error>>;
92
93 fn status(&mut self) -> impl Future<Output = Result<Status, Error>>;
95
96 fn running(&mut self) -> impl Future<Output = Result<bool, Error>>;
98}
99
100pub trait SystemConfig<'sys> {
102
103 type System: SystemHarness<'sys>;
104
105 fn spawn(&self) -> impl Future<Output = Result<Self::System, Error>>;
107
108}
109
110pub trait SystemTerminal: AsyncWrite + AsyncRead + Unpin {
113
114 fn send_key(&mut self, key: Key) -> impl Future<Output = Result<(), Error>>;
116
117 fn send_command(&mut self, command: &str) -> impl Future<Output = Result<(), Error>> {
119 async move {
120 for chr in command.chars() {
121 self.send_key(Key::Char { chr }).await?;
122 }
123 self.send_key(Key::Enter).await
124 }
125 }
126
127}
128
129pub trait EventPublisher {
131 fn subscribe(&mut self, subscriber: impl EventSubscriber) -> Result<(), Error>;
133}
134
135impl<F> EventSubscriber for F
136where
137 F: FnMut(&Event) + Send + Sync + 'static,
138{
139 fn on_event(&mut self, event: &Event) {
140 (self)(event)
141 }
142}
143
144mod error;
145pub use error::Error;
146pub use error::ErrorKind;
147
148#[cfg(all(target_family = "unix", feature = "container"))]
149mod container;
150#[cfg(all(target_family = "unix", feature = "container"))]
151pub use container::*;
152
153#[cfg(all(target_family = "unix", feature = "qemu"))]
154mod qemu;
155#[cfg(all(target_family = "unix", feature = "qemu"))]
156pub use qemu::*;
157
158#[cfg(test)]
159mod tests {
160
161 use super::*;
162
163 struct FakeEventPublisher(Vec<Box<dyn EventSubscriber>>);
164
165 impl FakeEventPublisher {
166 pub fn publish(&mut self) {
167 let event = Event {
168 kind: EventKind::Shutdown,
169 timestamp: SystemTime::now(),
170 };
171 for subscriber in &mut self.0 {
172 subscriber.on_event(&event);
173 }
174 }
175 }
176
177 impl EventPublisher for FakeEventPublisher {
178 fn subscribe(&mut self, subscriber: impl EventSubscriber) -> Result<(), Error> {
179 self.0.push(Box::new(subscriber));
180 Ok(())
181 }
182 }
183
184 #[test]
185 fn fn_subscribe() {
186 let mut publisher = FakeEventPublisher(Vec::new());
187 publisher.subscribe(|_event: &Event| {}).unwrap();
188 publisher.publish();
189 }
190}