diff --git a/client/examples/controller.rs b/client/examples/controller.rs index 1c4e398..672e7ce 100644 --- a/client/examples/controller.rs +++ b/client/examples/controller.rs @@ -1,4 +1,4 @@ -use roblib::cmd::Concrete; +use roblib::{cmd::Concrete, text_format}; use roblib_client::{ transports::{udp::Udp, Transport}, Result, @@ -25,53 +25,60 @@ fn main() -> Result<()> { "" => continue, "exit" => break, inp => { - let Ok(cmd) = roblib::text_format::de::from_str(inp) else { + let Ok(cmd) = text_format::de::from_str::(inp) else { println!("Couldn't parse command"); continue; }; + println!("{}", text_format::ser::to_string(&cmd)?); + print!("< "); - match cmd { - Concrete::MoveRobot(c) => robot.cmd(c)?, - Concrete::MoveRobotByAngle(c) => robot.cmd(c)?, - Concrete::StopRobot(c) => robot.cmd(c)?, - Concrete::Led(c) => robot.cmd(c)?, - Concrete::RolandServo(c) => robot.cmd(c)?, - Concrete::Buzzer(c) => robot.cmd(c)?, - Concrete::TrackSensor(c) => println!("{:?}", robot.cmd(c)?), - Concrete::UltraSensor(c) => println!("{}", robot.cmd(c)?), + execute(cmd, &robot)?; + } + } + } + + Ok(()) +} - Concrete::PinMode(c) => robot.cmd(c)?, - Concrete::ReadPin(c) => println!("{}", robot.cmd(c)?), - Concrete::WritePin(c) => robot.cmd(c)?, - Concrete::Pwm(c) => robot.cmd(c)?, - Concrete::Servo(c) => robot.cmd(c)?, +fn execute(cmd: Concrete, robot: &impl Transport) -> Result<()> { + match cmd { + Concrete::MoveRobot(c) => robot.cmd(c)?, + Concrete::MoveRobotByAngle(c) => robot.cmd(c)?, + Concrete::StopRobot(c) => robot.cmd(c)?, + Concrete::Led(c) => robot.cmd(c)?, + Concrete::RolandServo(c) => robot.cmd(c)?, + Concrete::Buzzer(c) => robot.cmd(c)?, + Concrete::TrackSensor(c) => println!("{:?}", robot.cmd(c)?), + Concrete::UltraSensor(c) => println!("{}", robot.cmd(c)?), - Concrete::Subscribe(_) => { - println!("Subscribe no supported"); - } - Concrete::Unsubscribe(_) => { - println!("Unsubscribe no supported"); - } + Concrete::PinMode(c) => robot.cmd(c)?, + Concrete::ReadPin(c) => println!("{}", robot.cmd(c)?), + Concrete::WritePin(c) => robot.cmd(c)?, + Concrete::Pwm(c) => robot.cmd(c)?, + Concrete::Servo(c) => robot.cmd(c)?, - Concrete::Nop(c) => robot.cmd(c)?, - Concrete::GetUptime(c) => println!("{:?}", robot.cmd(c)?), + Concrete::Subscribe(_) => { + println!("Subscribe no supported"); + } + Concrete::Unsubscribe(_) => { + println!("Unsubscribe no supported"); + } - Concrete::GetPosition(c) => { - if let Some(p) = robot.cmd(c)? { - println!("{}", p) - } else { - println!("<") - } - } + Concrete::Nop(c) => robot.cmd(c)?, + Concrete::GetUptime(c) => println!("{:?}", robot.cmd(c)?), - Concrete::Abort(_) => { - println!("Abort no supported"); - } - } + Concrete::GetPosition(c) => { + if let Some(p) = robot.cmd(c)? { + println!("{}", p) + } else { + println!("<") } } - } + Concrete::Abort(_) => { + println!("Abort no supported"); + } + } Ok(()) } diff --git a/roblib/src/cmd/concrete.rs b/roblib/src/cmd/concrete.rs index 5ea4a4d..f9d92ba 100644 --- a/roblib/src/cmd/concrete.rs +++ b/roblib/src/cmd/concrete.rs @@ -64,6 +64,7 @@ impl std::fmt::Debug for Concrete { Self::TrackSensor(v) => v.fmt(f), #[cfg(feature = "roland")] Self::UltraSensor(v) => v.fmt(f), + #[cfg(feature = "gpio")] Self::PinMode(v) => v.fmt(f), #[cfg(feature = "gpio")] @@ -74,8 +75,10 @@ impl std::fmt::Debug for Concrete { Self::Pwm(v) => v.fmt(f), #[cfg(feature = "gpio")] Self::Servo(v) => v.fmt(f), + #[cfg(feature = "camloc")] Self::GetPosition(v) => v.fmt(f), + Self::Subscribe(v) => v.fmt(f), Self::Unsubscribe(v) => v.fmt(f), Self::Nop(v) => v.fmt(f), @@ -296,138 +299,56 @@ impl<'de> Deserialize<'de> for Concrete { .next_element()? .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Ok(match prefix { + match prefix { #[cfg(feature = "roland")] - cmd::MoveRobot::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::MoveRobot(cmd) - } + cmd::MoveRobot::PREFIX => seq.next_element()?.map(Concrete::MoveRobot), + #[cfg(feature = "roland")] cmd::MoveRobotByAngle::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::MoveRobotByAngle(cmd) + seq.next_element()?.map(Concrete::MoveRobotByAngle) } + #[cfg(feature = "roland")] - cmd::StopRobot::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::StopRobot(cmd) - } + cmd::StopRobot::PREFIX => seq.next_element()?.map(Concrete::StopRobot), + #[cfg(feature = "roland")] - cmd::Led::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::Led(cmd) - } + cmd::Led::PREFIX => seq.next_element()?.map(Concrete::Led), + #[cfg(feature = "roland")] - cmd::RolandServo::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::RolandServo(cmd) - } + cmd::RolandServo::PREFIX => seq.next_element()?.map(Concrete::RolandServo), + #[cfg(feature = "roland")] - cmd::Buzzer::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::Buzzer(cmd) - } + cmd::Buzzer::PREFIX => seq.next_element()?.map(Concrete::Buzzer), + #[cfg(feature = "roland")] - cmd::TrackSensor::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::TrackSensor(cmd) - } + cmd::TrackSensor::PREFIX => seq.next_element()?.map(Concrete::TrackSensor), + #[cfg(feature = "roland")] - cmd::UltraSensor::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::UltraSensor(cmd) - } + cmd::UltraSensor::PREFIX => seq.next_element()?.map(Concrete::UltraSensor), #[cfg(feature = "gpio")] - cmd::PinMode::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::PinMode(cmd) - } + cmd::PinMode::PREFIX => seq.next_element()?.map(Concrete::PinMode), + #[cfg(feature = "gpio")] - cmd::ReadPin::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::ReadPin(cmd) - } + cmd::ReadPin::PREFIX => seq.next_element()?.map(Concrete::ReadPin), + #[cfg(feature = "gpio")] - cmd::WritePin::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::WritePin(cmd) - } + cmd::WritePin::PREFIX => seq.next_element()?.map(Concrete::WritePin), + #[cfg(feature = "gpio")] - cmd::Pwm::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::Pwm(cmd) - } + cmd::Pwm::PREFIX => seq.next_element()?.map(Concrete::Pwm), + #[cfg(feature = "gpio")] - cmd::Servo::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::Servo(cmd) - } + cmd::Servo::PREFIX => seq.next_element()?.map(Concrete::Servo), #[cfg(feature = "camloc")] - cmd::GetPosition::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::GetPosition(cmd) - } + cmd::GetPosition::PREFIX => seq.next_element()?.map(Concrete::GetPosition), - cmd::Subscribe::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::Subscribe(cmd) - } - cmd::Unsubscribe::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::Unsubscribe(cmd) - } - cmd::Nop::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::Nop(cmd) - } - cmd::GetUptime::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::GetUptime(cmd) - } - cmd::Abort::PREFIX => { - let cmd = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - Concrete::Abort(cmd) - } + cmd::Subscribe::PREFIX => seq.next_element()?.map(Concrete::Subscribe), + cmd::Unsubscribe::PREFIX => seq.next_element()?.map(Concrete::Unsubscribe), + cmd::Nop::PREFIX => seq.next_element()?.map(Concrete::Nop), + cmd::GetUptime::PREFIX => seq.next_element()?.map(Concrete::GetUptime), + cmd::Abort::PREFIX => seq.next_element()?.map(Concrete::Abort), _ => { return Err(de::Error::invalid_value( @@ -435,7 +356,8 @@ impl<'de> Deserialize<'de> for Concrete { &"a command prefix", )) } - }) + } + .ok_or_else(|| de::Error::invalid_length(0, &self)) } } diff --git a/roblib/src/text_format/de.rs b/roblib/src/text_format/de.rs index 326aff7..413b0a5 100644 --- a/roblib/src/text_format/de.rs +++ b/roblib/src/text_format/de.rs @@ -32,7 +32,8 @@ where impl<'de, I: Iterator> Deserializer { fn next(&mut self) -> Result { - match self.iter.next() { + let v = self.iter.next(); + match v { Some("") => Err(Error::Empty), Some(s) => Ok(s), None => Err(Error::MissingArgument), @@ -222,11 +223,19 @@ impl<'de, 'a, I: Iterator> de::Deserializer<'de> for &'a mut De self.deserialize_seq(visitor) } - fn deserialize_tuple_struct(self, _: &'static str, _: usize, visitor: V) -> Result + fn deserialize_tuple_struct( + self, + _: &'static str, + fields: usize, + visitor: V, + ) -> Result where V: de::Visitor<'de>, { - self.deserialize_seq(visitor) + visitor.visit_seq(Seq { + de: self, + left: fields as u32, + }) } fn deserialize_map(self, visitor: V) -> Result @@ -297,7 +306,8 @@ impl<'de, 'a, I: Iterator> SeqAccess<'de> for Seq<'de, 'a, I> { if self.left > 0 { self.left -= 1; - seed.deserialize(&mut *self.de).map(Some) + let r = seed.deserialize(&mut *self.de); + r.map(Some) } else { Ok(None) } diff --git a/roblib/src/text_format/ser.rs b/roblib/src/text_format/ser.rs index 789ea37..cd983c7 100644 --- a/roblib/src/text_format/ser.rs +++ b/roblib/src/text_format/ser.rs @@ -7,15 +7,23 @@ use serde::{ }; use std::fmt::{self, Write}; +pub fn to_string(s: &impl Serialize) -> Result { + let mut r = String::new(); + s.serialize(&mut Serializer::new(&mut r))?; + Ok(r) +} + pub struct Serializer { - first: bool, + formatting: bool, + put_separator: bool, writer: W, } impl Serializer { pub fn new(writer: W) -> Self { Self { - first: true, + put_separator: false, + formatting: false, writer, } } @@ -23,10 +31,26 @@ impl Serializer { impl fmt::Write for Serializer { fn write_str(&mut self, s: &str) -> fmt::Result { - if !self.first { - self.writer.write_fmt(format_args!("{}", SEPARATOR))?; + if self.put_separator { + if self.formatting { + self.put_separator = false; + } + self.writer.write_fmt(format_args!("{}{s}", SEPARATOR)) + } else { + if !self.formatting { + self.put_separator = true; + } + self.writer.write_str(s) } - self.writer.write_str(s) + } + + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result { + self.put_separator = true; + self.formatting = true; + fmt::write(self, args)?; + self.formatting = false; + self.put_separator = true; + Ok(()) } }