Into, TryFrom
This commit is contained in:
		
							parent
							
								
									30c26db9f7
								
							
						
					
					
						commit
						9eaa7462bc
					
				
					 6 changed files with 128 additions and 38 deletions
				
			
		|  | @ -9,6 +9,9 @@ struct Cli { | |||
|     text: Vec<String>, | ||||
| } | ||||
| 
 | ||||
| /// example: `cargo run -- --text "Hallo,
 | ||||
| /// CCCB"`
 | ||||
| 
 | ||||
| fn main() { | ||||
|     let cli = Cli::parse(); | ||||
|     println!("starting with args: {:?}", &cli); | ||||
|  |  | |||
							
								
								
									
										126
									
								
								src/command.rs
									
										
									
									
									
								
							
							
						
						
									
										126
									
								
								src/command.rs
									
										
									
									
									
								
							|  | @ -1,5 +1,6 @@ | |||
| use crate::{BitVec, Header, Packet, PixelGrid, TILE_SIZE, ToPacket}; | ||||
| use crate::command_codes::DisplayCommandCode; | ||||
| use crate::{BitVec, Packet, PixelGrid, TILE_SIZE}; | ||||
| use crate::command_codes::CommandCode; | ||||
| use crate::packet::Header; | ||||
| 
 | ||||
| /// A window
 | ||||
| #[derive(Debug, Copy, Clone)] | ||||
|  | @ -33,53 +34,142 @@ pub enum Command { | |||
|     BitmapLinearWin(Origin, PixelGrid), | ||||
| } | ||||
| 
 | ||||
| fn offset_and_payload(command: DisplayCommandCode, offset: Offset, payload: Vec<u8>) -> Packet { | ||||
| fn offset_and_payload(command: CommandCode, offset: Offset, payload: Vec<u8>) -> Packet { | ||||
|     Packet(Header(command.to_primitive(), offset, payload.len() as u16, 0, 0), payload) | ||||
| } | ||||
| 
 | ||||
| fn window_and_payload(command: DisplayCommandCode, window: Window, payload: Vec<u8>) -> Packet { | ||||
| fn window_and_payload(command: CommandCode, window: Window, payload: Vec<u8>) -> Packet { | ||||
|     let Window(Origin(x, y), Size(w, h)) = window; | ||||
|     Packet(Header(command.to_primitive(), x, y, w, h), payload.into()) | ||||
| } | ||||
| 
 | ||||
| fn command_code_only(code: DisplayCommandCode) -> Packet { | ||||
| fn command_code_only(code: CommandCode) -> Packet { | ||||
|     Packet(Header(code.to_primitive(), 0x0000, 0x0000, 0x0000, 0x0000), vec!()) | ||||
| } | ||||
| 
 | ||||
| impl ToPacket for Command { | ||||
|     fn to_packet(self) -> Packet { | ||||
| impl Into<Packet> for Command { | ||||
|     fn into(self) -> Packet { | ||||
|         match self { | ||||
|             Command::Clear => command_code_only(DisplayCommandCode::Clear), | ||||
|             Command::FadeOut => command_code_only(DisplayCommandCode::FadeOut), | ||||
|             Command::HardReset => command_code_only(DisplayCommandCode::HardReset), | ||||
|             Command::Clear => command_code_only(CommandCode::Clear), | ||||
|             Command::FadeOut => command_code_only(CommandCode::FadeOut), | ||||
|             Command::HardReset => command_code_only(CommandCode::HardReset), | ||||
| 
 | ||||
|             Command::CharBrightness(window, payload) => { | ||||
|                 window_and_payload(DisplayCommandCode::CharBrightness, window, payload) | ||||
|                 window_and_payload(CommandCode::CharBrightness, window, payload) | ||||
|             } | ||||
|             Command::Brightness(brightness) => { | ||||
|                 Packet(Header(DisplayCommandCode::Brightness.to_primitive(), 0x00000, 0x0000, 0x0000, 0x0000), vec!(brightness)) | ||||
|                 Packet(Header(CommandCode::Brightness.to_primitive(), 0x00000, 0x0000, 0x0000, 0x0000), vec!(brightness)) | ||||
|             } | ||||
| 
 | ||||
|             Command::BitmapLinear(offset, bits) => { | ||||
|                 offset_and_payload(DisplayCommandCode::BitmapLinear, offset, bits.into()) | ||||
|                 offset_and_payload(CommandCode::BitmapLinear, offset, bits.into()) | ||||
|             } | ||||
|             Command::BitmapLinearWin(Origin(pixel_x, pixel_y), pixels) => { | ||||
|                 debug_assert_eq!(pixel_x % 8, 0); | ||||
|                 debug_assert_eq!(pixels.width % 8, 0); | ||||
|                 Packet(Header(0x0013, pixel_x / TILE_SIZE, pixel_y, pixels.width as u16 / TILE_SIZE, pixels.height as u16), pixels.into()) | ||||
|                 Packet( | ||||
|                     Header(CommandCode::BitmapLinearWin.to_primitive(), pixel_x / TILE_SIZE, pixel_y, pixels.width as u16 / TILE_SIZE, pixels.height as u16), | ||||
|                     pixels.into()) | ||||
|             } | ||||
|             Command::BitmapLinearAnd(offset, bits) => { | ||||
|                 offset_and_payload(DisplayCommandCode::BitmapLinearAnd, offset, bits.into()) | ||||
|                 offset_and_payload(CommandCode::BitmapLinearAnd, offset, bits.into()) | ||||
|             } | ||||
|             Command::BitmapLinearOr(offset, bits) => { | ||||
|                 offset_and_payload(DisplayCommandCode::BitmapLinearOr, offset, bits.into()) | ||||
|                 offset_and_payload(CommandCode::BitmapLinearOr, offset, bits.into()) | ||||
|             } | ||||
|             Command::BitmapLinearXor(offset, bits) => { | ||||
|                 offset_and_payload(DisplayCommandCode::BitmapLinearXor, offset, bits.into()) | ||||
|                 offset_and_payload(CommandCode::BitmapLinearXor, offset, bits.into()) | ||||
|             } | ||||
|             Command::Cp437Data(window, payload) => { | ||||
|                 window_and_payload(DisplayCommandCode::Cp437data, window, payload) | ||||
|                 window_and_payload(CommandCode::Cp437Data, window, payload) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum TryFromPacketError { | ||||
|     InvalidCommand(u16), | ||||
|     ExtraneousPayload(usize, usize), | ||||
|     ExtraneousHeaderValues, | ||||
| } | ||||
| 
 | ||||
| fn check_empty_header(packet: &Packet) -> Option<TryFromPacketError> { | ||||
|     let Packet(Header(_, a, b, c, d), _) = &packet; | ||||
|     if *a != 0 || *b != 0 || *c != 0 || *d != 0 { | ||||
|         Some(TryFromPacketError::ExtraneousHeaderValues) | ||||
|     } else { | ||||
|         None | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn check_command_only(packet: &Packet) -> Option<TryFromPacketError> { | ||||
|     let Packet(_, payload) = packet; | ||||
|     if payload.len() != 0 { | ||||
|         Some(TryFromPacketError::ExtraneousPayload(0, payload.len())) | ||||
|     } else { | ||||
|         check_empty_header(packet) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TryFrom<Packet> for Command { | ||||
|     type Error = TryFromPacketError; | ||||
| 
 | ||||
|     fn try_from(value: Packet) -> Result<Self, Self::Error> { | ||||
|         let Packet(Header(command_u16, a, b, c, d), payload) = &value; | ||||
|         let command_code = match CommandCode::from_primitive(*command_u16) { | ||||
|             None => return Err(TryFromPacketError::InvalidCommand(*command_u16)), | ||||
|             Some(value) => value | ||||
|         }; | ||||
| 
 | ||||
|         match command_code { | ||||
|             CommandCode::Clear => { | ||||
|                 if let Some(err) = check_command_only(&value) { | ||||
|                     return Err(err); | ||||
|                 } | ||||
|                 Ok(Command::Clear) | ||||
|             } | ||||
|             CommandCode::Brightness => { | ||||
|                 if let Some(err) = check_empty_header(&value) { | ||||
|                     return Err(err); | ||||
|                 } | ||||
|                 Ok(Command::Brightness(payload[0])) | ||||
|             } | ||||
|             CommandCode::HardReset => { | ||||
|                 if let Some(err) = check_command_only(&value) { | ||||
|                     return Err(err); | ||||
|                 } | ||||
|                 Ok(Command::HardReset) | ||||
|             } | ||||
|             CommandCode::FadeOut => { | ||||
|                 if let Some(err) = check_command_only(&value) { | ||||
|                     return Err(err); | ||||
|                 } | ||||
|                 Ok(Command::FadeOut) | ||||
|             } | ||||
|             CommandCode::Cp437Data => { | ||||
|                 Ok(Command::Cp437Data( | ||||
|                     Window(Origin(*a, *b), Size(*c, *d)), | ||||
|                     payload.clone(), | ||||
|                 )) | ||||
|             } | ||||
|             CommandCode::CharBrightness => { | ||||
|                 Ok(Command::CharBrightness( | ||||
|                     Window(Origin(*a, *b), Size(*c, *d)), | ||||
|                     payload.clone(), | ||||
|                 )) | ||||
|             } | ||||
|             CommandCode::BitmapLegacy => { todo!() } | ||||
|             CommandCode::BitmapLinear => { todo!() } | ||||
|             CommandCode::BitmapLinearWin => { | ||||
|                 Ok(Command::BitmapLinearWin( | ||||
|                     Origin(*a * TILE_SIZE, *b), | ||||
|                     PixelGrid::load(*c as usize * TILE_SIZE as usize, *d as usize, payload), | ||||
|                 )) | ||||
|             } | ||||
|             CommandCode::BitmapLinearAnd => { todo!() } | ||||
|             CommandCode::BitmapLinearOr => { todo!() } | ||||
|             CommandCode::BitmapLinearXor => { todo!() } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -3,9 +3,9 @@ use num_derive::{FromPrimitive, ToPrimitive}; | |||
| 
 | ||||
| #[repr(u16)] | ||||
| #[derive(Debug, FromPrimitive, ToPrimitive)] | ||||
| pub enum DisplayCommandCode { | ||||
| pub enum CommandCode { | ||||
|     Clear = 0x0002, | ||||
|     Cp437data = 0x0003, | ||||
|     Cp437Data = 0x0003, | ||||
|     CharBrightness = 0x0005, | ||||
|     Brightness = 0x0007, | ||||
|     HardReset = 0x000b, | ||||
|  | @ -18,7 +18,7 @@ pub enum DisplayCommandCode { | |||
|     BitmapLinearXor = 0x0016, | ||||
| } | ||||
| 
 | ||||
| impl DisplayCommandCode { | ||||
| impl CommandCode { | ||||
|     pub fn from_primitive(value: u16) -> Option<Self> { | ||||
|         FromPrimitive::from_u16(value) | ||||
|     } | ||||
|  |  | |||
|  | @ -1,14 +1,10 @@ | |||
| use std::net::{ToSocketAddrs, UdpSocket}; | ||||
| use crate::{Packet}; | ||||
| use crate::Packet; | ||||
| 
 | ||||
| pub struct Connection { | ||||
|     socket: UdpSocket, | ||||
| } | ||||
| 
 | ||||
| pub trait ToPacket { | ||||
|     fn to_packet(self) -> Packet; | ||||
| } | ||||
| 
 | ||||
| impl Connection { | ||||
|     /// Open a new UDP socket and create a display instance
 | ||||
|     pub fn open(addr: impl ToSocketAddrs) -> std::io::Result<Self> { | ||||
|  | @ -18,9 +14,10 @@ impl Connection { | |||
|     } | ||||
| 
 | ||||
|     /// Send a command to the display
 | ||||
|     pub fn send(&self, packet: impl ToPacket) -> std::io::Result<()> { | ||||
|         let packet = packet.to_packet(); | ||||
|         self.socket.send(&*packet.to_bytes())?; | ||||
|     pub fn send(&self, packet: impl Into<Packet>) -> std::io::Result<()> { | ||||
|         let packet = packet.into(); | ||||
|         let data: Vec<u8> = packet.into(); | ||||
|         self.socket.send(&*data)?; | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -5,12 +5,12 @@ mod packet; | |||
| mod command; | ||||
| mod command_codes; | ||||
| 
 | ||||
| pub use crate::connection::{Connection, ToPacket}; | ||||
| pub use crate::connection::{Connection}; | ||||
| pub use crate::pixel_grid::{PixelGrid}; | ||||
| pub use crate::bit_vec::{BitVec}; | ||||
| pub use crate::packet::{Packet, Header, Payload}; | ||||
| pub use crate::command::{Command, Size, Origin, Window}; | ||||
| pub use crate::command_codes::{DisplayCommandCode}; | ||||
| pub use crate::command_codes::{CommandCode}; | ||||
| 
 | ||||
| pub const TILE_SIZE: u16 = 8; | ||||
| pub const TILE_WIDTH: u16 = 56; | ||||
|  |  | |||
|  | @ -4,16 +4,16 @@ pub type Payload = Vec<u8>; | |||
| 
 | ||||
| pub struct Packet(pub Header, pub Payload); | ||||
| 
 | ||||
| impl Packet { | ||||
|     pub fn to_bytes(&self) -> Vec<u8> { | ||||
| impl Into<Vec<u8>> for Packet { | ||||
|     fn into(self) -> Vec<u8> { | ||||
|         let Packet(Header(mode, a, b, c, d), payload) = self; | ||||
| 
 | ||||
|         let mut packet = vec!(0u8; 10 + payload.len()); | ||||
|         packet[0..=1].copy_from_slice(&u16::to_be_bytes(*mode)); | ||||
|         packet[2..=3].copy_from_slice(&u16::to_be_bytes(*a)); | ||||
|         packet[4..=5].copy_from_slice(&u16::to_be_bytes(*b)); | ||||
|         packet[6..=7].copy_from_slice(&u16::to_be_bytes(*c)); | ||||
|         packet[8..=9].copy_from_slice(&u16::to_be_bytes(*d)); | ||||
|         packet[0..=1].copy_from_slice(&u16::to_be_bytes(mode)); | ||||
|         packet[2..=3].copy_from_slice(&u16::to_be_bytes(a)); | ||||
|         packet[4..=5].copy_from_slice(&u16::to_be_bytes(b)); | ||||
|         packet[6..=7].copy_from_slice(&u16::to_be_bytes(c)); | ||||
|         packet[8..=9].copy_from_slice(&u16::to_be_bytes(d)); | ||||
| 
 | ||||
|         packet[10..].copy_from_slice(&*payload); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vinzenz Schroeter
						Vinzenz Schroeter