qtest/
lib.rs

1/// Register module, used to represent and interact with hardware registers.
2pub mod register;
3/// Parser module, interface to interact with qtest
4pub mod session;
5/// Socket module, used to serve and manage qtest socket connections.
6pub mod socket;
7
8pub mod dispatcher;
9
10/// QTest Response enum
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub enum Response {
13    /// Successfull response, without any additional data
14    Ok,
15    /// Successfull response, with additional data
16    OkVal(String),
17    /// Error in processing the request
18    Err(String),
19}
20
21impl From<&str> for Response {
22    fn from(s: &str) -> Self {
23        let mut s_parts = s.split_whitespace();
24        if s_parts.next() != Some("OK") {
25            return Self::Err(s.to_string());
26        }
27        match s_parts.next() {
28            Some(val) => {
29                let msg = std::iter::once(val)
30                    .chain(s_parts)
31                    .collect::<Vec<_>>()
32                    .join(" ");
33                Self::OkVal(msg)
34            }
35            None => Self::Ok,
36        }
37    }
38}
39
40/// Struct for defining IRQ events propagated by QEMU.
41///
42/// The line and state depends on the machine that emits the event.
43/// Refer to QEMU documentation for your desired machine.
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
45pub struct Irq {
46    /// The line of the IRQ event
47    pub line: usize,
48    /// The state of the IRQ event
49    pub state: IrqState,
50}
51
52impl Irq {
53    /// Creates a new IRQ instance
54    pub fn new(line: usize, state: IrqState) -> Self {
55        Irq { line, state }
56    }
57}
58
59/// Enum for defining the state of an IRQ event
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
61pub enum IrqState {
62    /// The IRQ event is raised
63    Raise,
64    /// The IRQ event is lowered
65    Lower,
66}
67
68impl TryFrom<&str> for Irq {
69    type Error = &'static str;
70
71    fn try_from(s: &str) -> Result<Self, Self::Error> {
72        let mut s_parts = s.split_whitespace();
73
74        if s_parts.next() != Some("IRQ") {
75            return Err("Invalid IRQ string");
76        }
77        let ty = match s_parts.next() {
78            Some("raise") => IrqState::Raise,
79            Some("lower") => IrqState::Lower,
80            _ => return Err("Invalid IRQ type"),
81        };
82        let line = s_parts
83            .next()
84            .ok_or("Invalid IRQ line")?
85            .parse()
86            .map_err(|_| "Invalid IRQ line")?;
87
88        match s_parts.next() {
89            Some(_) => Err("Invalid IRQ string"),
90            None => Ok(Irq::new(line, ty)),
91        }
92    }
93}
94
95#[cfg(test)]
96mod test {
97    use super::*;
98
99    #[test]
100    fn test_response_from() {
101        let response = Response::from("OK");
102        assert_eq!(response, Response::Ok);
103
104        let response = Response::from("OK val");
105        assert_eq!(response, Response::OkVal("val".to_string()));
106
107        let response = Response::from("ERR error");
108        assert_eq!(response, Response::Err("ERR error".to_string()));
109    }
110
111    #[test]
112    fn test_irq_try_from() {
113        let irq = Irq::try_from("invalid");
114        assert_eq!(irq, Err("Invalid IRQ string"));
115
116        let irq = Irq::try_from("IRQ invalid");
117        assert_eq!(irq, Err("Invalid IRQ type"));
118
119        let irq = Irq::try_from("IRQ raise -1");
120        assert_eq!(irq, Err("Invalid IRQ line"));
121
122        let irq = Irq::try_from("IRQ raise 1 invalid");
123        assert_eq!(irq, Err("Invalid IRQ string"));
124
125        let irq = Irq::try_from("IRQ raise 1");
126        assert_eq!(irq, Ok(Irq::new(1, IrqState::Raise)));
127
128        let irq = Irq::try_from("IRQ lower 2");
129        assert_eq!(irq, Ok(Irq::new(2, IrqState::Lower)));
130    }
131}