1use std::convert::{From, TryFrom};
2
3use rosc::{OscMessage, OscType};
4use thiserror::Error;
5
6#[derive(Debug, Clone, Error)]
7pub enum MessageError {
8 #[error("Invalid address `{0}`")]
9 InvalidAddr(String),
10 #[error("Invalid arguments")]
11 InvalidArgs,
12}
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum Request {
16 InitZero(i32, i32),
17 X(i32, i32),
18 Y(i32, i32),
19 Z(i32, i32),
20 H(i32, i32),
21 S(i32, i32),
22 Sdg(i32, i32),
23 T(i32, i32),
24 Tdg(i32, i32),
25 CX(i32, i32, i32, i32),
26 Mz(i32, i32),
27}
28
29impl TryFrom<OscMessage> for Request {
30 type Error = anyhow::Error;
31
32 fn try_from(msg: OscMessage) -> anyhow::Result<Request> {
33 let OscMessage { addr, args } = msg;
34 let args = args.into_iter()
35 .map(|x| x.int().ok_or(MessageError::InvalidArgs))
36 .collect::<Result<Vec<_>, _>>()?;
37 let get = |n: usize| args.get(n).map(|x| *x).ok_or(MessageError::InvalidArgs);
38 match addr.as_str() {
39 "/InitZero" => Ok(Request::InitZero(get(0)?, get(1)?)),
40 "/X" => Ok(Request::X(get(0)?, get(1)?)),
41 "/Y" => Ok(Request::Y(get(0)?, get(1)?)),
42 "/Z" => Ok(Request::Z(get(0)?, get(1)?)),
43 "/H" => Ok(Request::H(get(0)?, get(1)?)),
44 "/S" => Ok(Request::S(get(0)?, get(1)?)),
45 "/Sdg" => Ok(Request::Sdg(get(0)?, get(1)?)),
46 "/T" => Ok(Request::T(get(0)?, get(1)?)),
47 "/Tdg" => Ok(Request::Tdg(get(0)?, get(1)?)),
48 "/CX" => Ok(Request::CX(get(0)?, get(1)?, get(2)?, get(3)?)),
49 "/Mz" => Ok(Request::Mz(get(0)?, get(1)?)),
50 _ => Err(MessageError::InvalidAddr(addr).into())
51 }
52 }
53}
54
55impl From<&Request> for OscMessage {
56 fn from(msg: &Request) -> OscMessage {
57 match msg {
58 Request::InitZero(n1, n2) => OscMessage { addr: "/InitZero".to_owned(), args: vec![OscType::Int(*n1), OscType::Int(*n2)] },
59 Request::X(n1, n2) => OscMessage { addr: "/X".to_owned(), args: vec![OscType::Int(*n1), OscType::Int(*n2)] },
60 Request::Y(n1, n2) => OscMessage { addr: "/Y".to_owned(), args: vec![OscType::Int(*n1), OscType::Int(*n2)] },
61 Request::Z(n1, n2) => OscMessage { addr: "/Z".to_owned(), args: vec![OscType::Int(*n1), OscType::Int(*n2)] },
62 Request::H(n1, n2) => OscMessage { addr: "/H".to_owned(), args: vec![OscType::Int(*n1), OscType::Int(*n2)] },
63 Request::S(n1, n2) => OscMessage { addr: "/S".to_owned(), args: vec![OscType::Int(*n1), OscType::Int(*n2)] },
64 Request::Sdg(n1, n2) => OscMessage { addr: "/Sdg".to_owned(), args: vec![OscType::Int(*n1), OscType::Int(*n2)] },
65 Request::T(n1, n2) => OscMessage { addr: "/T".to_owned(), args: vec![OscType::Int(*n1), OscType::Int(*n2)] },
66 Request::Tdg(n1, n2) => OscMessage { addr: "/Tdg".to_owned(), args: vec![OscType::Int(*n1), OscType::Int(*n2)] },
67 Request::CX(n1, n2, n3, n4) => OscMessage { addr: "/CX".to_owned(), args: vec![OscType::Int(*n1), OscType::Int(*n2), OscType::Int(*n3), OscType::Int(*n4)] },
68 Request::Mz(n1, n2) => OscMessage { addr: "/Mz".to_owned(), args: vec![OscType::Int(*n1), OscType::Int(*n2)] },
69 }
70 }
71}
72
73#[derive(Debug, Clone, PartialEq)]
74pub enum Response {
75 Mz(i32, f32),
76}
77
78impl TryFrom<OscMessage> for Response {
79 type Error = anyhow::Error;
80
81 fn try_from(msg: OscMessage) -> anyhow::Result<Response> {
82 let OscMessage { addr, args } = msg;
83 match addr.as_str() {
84 "/Mz" => Ok(Response::Mz(args.get(0).and_then(|x| x.clone().int()).ok_or(MessageError::InvalidArgs)?,
85 args.get(1).and_then(|x| x.clone().float()).ok_or(MessageError::InvalidArgs)?)),
86 _ => Err(MessageError::InvalidAddr(addr).into())
87 }
88 }
89}
90
91impl From<&Response> for OscMessage {
92 fn from(msg: &Response) -> OscMessage {
93 match msg {
94 Response::Mz(n1, f1) => OscMessage { addr: "/Mz".to_owned(), args: vec![OscType::Int(*n1), OscType::Float(*f1)] },
95 }
96 }
97}