encode origin unit in type
This commit is contained in:
		
							parent
							
								
									672b5e0581
								
							
						
					
					
						commit
						e0647bacd6
					
				
					 10 changed files with 120 additions and 76 deletions
				
			
		|  | @ -44,6 +44,6 @@ fn main() { | |||
|     } | ||||
| 
 | ||||
|     connection | ||||
|         .send(Command::Cp437Data(Origin(0, 0), chars)) | ||||
|         .send(Command::Cp437Data(Origin::new(0, 0), chars)) | ||||
|         .expect("sending text failed"); | ||||
| } | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ fn main() { | |||
| 
 | ||||
|     connection | ||||
|         .send(BitmapLinearWin( | ||||
|             Origin(0, 0), | ||||
|             Origin::new(0, 0), | ||||
|             pixels, | ||||
|             CompressionCode::Uncompressed, | ||||
|         )) | ||||
|  | @ -33,6 +33,6 @@ fn main() { | |||
|     } | ||||
| 
 | ||||
|     connection | ||||
|         .send(Command::CharBrightness(Origin(0, 0), brightnesses)) | ||||
|         .send(Command::CharBrightness(Origin::new(0, 0), brightnesses)) | ||||
|         .expect("send failed"); | ||||
| } | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ fn main() { | |||
|     loop { | ||||
|         connection | ||||
|             .send(Command::BitmapLinearWin( | ||||
|                 Origin(0, 0), | ||||
|                 Origin::new(0, 0), | ||||
|                 field.clone(), | ||||
|                 CompressionCode::Lzma, | ||||
|             )) | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ fn main() { | |||
|         } | ||||
|         connection | ||||
|             .send(Command::BitmapLinearWin( | ||||
|                 Origin(0, 0), | ||||
|                 Origin::new(0, 0), | ||||
|                 pixels.clone(), | ||||
|                 CompressionCode::Lzma, | ||||
|             )) | ||||
|  |  | |||
|  | @ -1,26 +1,12 @@ | |||
| use bitvec::prelude::BitVec; | ||||
| 
 | ||||
| use crate::command_code::CommandCode; | ||||
| use crate::compression::{into_compressed, into_decompressed}; | ||||
| use crate::{ | ||||
|     Brightness, ByteGrid, CompressionCode, Grid, Header, Packet, PixelGrid, | ||||
|     SpBitVec, TILE_SIZE, | ||||
|     command_code::CommandCode, | ||||
|     compression::{into_compressed, into_decompressed}, | ||||
|     Brightness, ByteGrid, CompressionCode, Grid, Header, Origin, Packet, | ||||
|     PixelGrid, Pixels, SpBitVec, Tiles, TILE_SIZE, | ||||
| }; | ||||
| 
 | ||||
| /// An origin marks the top left position of a window sent to the display.
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq)] | ||||
| pub struct Origin(pub usize, pub usize); | ||||
| 
 | ||||
| impl std::ops::Add<Origin> for Origin { | ||||
|     type Output = Origin; | ||||
| 
 | ||||
|     fn add(self, rhs: Origin) -> Self::Output { | ||||
|         let Origin(x1, y1) = self; | ||||
|         let Origin(x2, y2) = rhs; | ||||
|         Origin(x1 + x2, y1 + y2) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Type alias for documenting the meaning of the u16 in enum values
 | ||||
| pub type Offset = usize; | ||||
| 
 | ||||
|  | @ -32,24 +18,20 @@ pub enum Command { | |||
| 
 | ||||
|     /// Show text on the screen.
 | ||||
|     ///
 | ||||
|     /// The origin is in tiles.
 | ||||
|     ///
 | ||||
|     /// <div class="warning">
 | ||||
|     ///     The library does not currently convert between UTF-8 and CP-437.
 | ||||
|     ///     Because Rust expects UTF-8 strings, it might be necessary to only send ASCII for now.
 | ||||
|     /// </div>
 | ||||
|     Cp437Data(Origin, ByteGrid), | ||||
|     Cp437Data(Origin<Tiles>, ByteGrid), | ||||
| 
 | ||||
|     /// Sets a window of pixels to the specified values
 | ||||
|     BitmapLinearWin(Origin, PixelGrid, CompressionCode), | ||||
|     BitmapLinearWin(Origin<Pixels>, PixelGrid, CompressionCode), | ||||
| 
 | ||||
|     /// Set the brightness of all tiles to the same value.
 | ||||
|     Brightness(Brightness), | ||||
| 
 | ||||
|     /// Set the brightness of individual tiles in a rectangular area of the display.
 | ||||
|     ///
 | ||||
|     /// The origin is in tiles.
 | ||||
|     CharBrightness(Origin, ByteGrid), | ||||
|     CharBrightness(Origin<Tiles>, ByteGrid), | ||||
| 
 | ||||
|     /// Set pixel data starting at the pixel offset on screen.
 | ||||
|     ///
 | ||||
|  | @ -116,11 +98,11 @@ impl From<Command> for Packet { | |||
|             Command::BitmapLegacy => { | ||||
|                 Command::command_code_only(CommandCode::BitmapLegacy) | ||||
|             } | ||||
|             Command::CharBrightness(Origin(x, y), grid) => Packet( | ||||
|             Command::CharBrightness(origin, grid) => Packet( | ||||
|                 Header( | ||||
|                     CommandCode::CharBrightness.into(), | ||||
|                     x as u16, | ||||
|                     y as u16, | ||||
|                     origin.x as u16, | ||||
|                     origin.y as u16, | ||||
|                     grid.width() as u16, | ||||
|                     grid.height() as u16, | ||||
|                 ), | ||||
|  | @ -171,11 +153,11 @@ impl From<Command> for Packet { | |||
|                     bits.into(), | ||||
|                 ) | ||||
|             } | ||||
|             Command::Cp437Data(Origin(x, y), grid) => Packet( | ||||
|             Command::Cp437Data(origin, grid) => Packet( | ||||
|                 Header( | ||||
|                     CommandCode::Cp437Data.into(), | ||||
|                     x as u16, | ||||
|                     y as u16, | ||||
|                     origin.x as u16, | ||||
|                     origin.y as u16, | ||||
|                     grid.width() as u16, | ||||
|                     grid.height() as u16, | ||||
|                 ), | ||||
|  | @ -187,15 +169,14 @@ impl From<Command> for Packet { | |||
| 
 | ||||
| #[allow(clippy::cast_possible_truncation)] | ||||
| fn bitmap_win_into_packet( | ||||
|     origin: Origin, | ||||
|     origin: Origin<Pixels>, | ||||
|     pixels: PixelGrid, | ||||
|     compression: CompressionCode, | ||||
| ) -> Packet { | ||||
|     let Origin(pixel_x, pixel_y) = origin; | ||||
|     debug_assert_eq!(pixel_x % 8, 0); | ||||
|     debug_assert_eq!(origin.x % 8, 0); | ||||
|     debug_assert_eq!(pixels.width() % 8, 0); | ||||
| 
 | ||||
|     let tile_x = (pixel_x / TILE_SIZE) as u16; | ||||
|     let tile_x = (origin.x / TILE_SIZE) as u16; | ||||
|     let tile_w = (pixels.width() / TILE_SIZE) as u16; | ||||
|     let pixel_h = pixels.height() as u16; | ||||
|     let payload = into_compressed(compression, pixels.into()); | ||||
|  | @ -214,7 +195,7 @@ fn bitmap_win_into_packet( | |||
|     }; | ||||
| 
 | ||||
|     Packet( | ||||
|         Header(command.into(), tile_x, pixel_y as u16, tile_w, pixel_h), | ||||
|         Header(command.into(), tile_x, origin.y as u16, tile_w, pixel_h), | ||||
|         payload, | ||||
|     ) | ||||
| } | ||||
|  | @ -289,14 +270,14 @@ impl TryFrom<Packet> for Command { | |||
|             CommandCode::Cp437Data => { | ||||
|                 let Packet(_, payload) = packet; | ||||
|                 Ok(Command::Cp437Data( | ||||
|                     Origin(a as usize, b as usize), | ||||
|                     Origin::new(a as usize, b as usize), | ||||
|                     ByteGrid::load(c as usize, d as usize, &payload), | ||||
|                 )) | ||||
|             } | ||||
|             CommandCode::CharBrightness => { | ||||
|                 let Packet(_, payload) = packet; | ||||
|                 Ok(Command::CharBrightness( | ||||
|                     Origin(a as usize, b as usize), | ||||
|                     Origin::new(a as usize, b as usize), | ||||
|                     ByteGrid::load(c as usize, d as usize, &payload), | ||||
|                 )) | ||||
|             } | ||||
|  | @ -362,7 +343,7 @@ impl Command { | |||
|         }; | ||||
| 
 | ||||
|         Ok(Command::BitmapLinearWin( | ||||
|             Origin(tiles_x as usize * TILE_SIZE, pixels_y as usize), | ||||
|             Origin::new(tiles_x as usize * TILE_SIZE, pixels_y as usize), | ||||
|             PixelGrid::load( | ||||
|                 tile_w as usize * TILE_SIZE, | ||||
|                 pixel_h as usize, | ||||
|  | @ -441,13 +422,10 @@ impl Command { | |||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use bitvec::prelude::BitVec; | ||||
| 
 | ||||
|     use crate::command::TryFromPacketError; | ||||
|     use crate::command_code::CommandCode; | ||||
|     use crate::{ | ||||
|         Brightness, ByteGrid, Command, CompressionCode, Header, Origin, Packet, | ||||
|         PixelGrid, | ||||
|         bitvec::prelude::BitVec, command::TryFromPacketError, | ||||
|         command_code::CommandCode, origin::Pixels, Brightness, ByteGrid, | ||||
|         Command, CompressionCode, Header, Origin, Packet, PixelGrid, | ||||
|     }; | ||||
| 
 | ||||
|     fn round_trip(original: Command) { | ||||
|  | @ -501,12 +479,15 @@ mod tests { | |||
| 
 | ||||
|     #[test] | ||||
|     fn round_trip_char_brightness() { | ||||
|         round_trip(Command::CharBrightness(Origin(5, 2), ByteGrid::new(7, 5))); | ||||
|         round_trip(Command::CharBrightness( | ||||
|             Origin::new(5, 2), | ||||
|             ByteGrid::new(7, 5), | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn round_trip_cp437_data() { | ||||
|         round_trip(Command::Cp437Data(Origin(5, 2), ByteGrid::new(7, 5))); | ||||
|         round_trip(Command::Cp437Data(Origin::new(5, 2), ByteGrid::new(7, 5))); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|  | @ -533,7 +514,7 @@ mod tests { | |||
|                 compression, | ||||
|             )); | ||||
|             round_trip(Command::BitmapLinearWin( | ||||
|                 Origin(0, 0), | ||||
|                 Origin::new(0, 0), | ||||
|                 PixelGrid::max_sized(), | ||||
|                 compression, | ||||
|             )); | ||||
|  | @ -619,7 +600,7 @@ mod tests { | |||
|     fn error_decompression_failed_win() { | ||||
|         for compression in all_compressions().to_owned() { | ||||
|             let p: Packet = Command::BitmapLinearWin( | ||||
|                 Origin(16, 8), | ||||
|                 Origin::new(16, 8), | ||||
|                 PixelGrid::new(8, 8), | ||||
|                 compression, | ||||
|             ) | ||||
|  | @ -743,6 +724,9 @@ mod tests { | |||
| 
 | ||||
|     #[test] | ||||
|     fn origin_add() { | ||||
|         assert_eq!(Origin(4, 2), Origin(1, 0) + Origin(3, 2)); | ||||
|         assert_eq!( | ||||
|             Origin::<Pixels>::new(4, 2), | ||||
|             Origin::new(1, 0) + Origin::new(3, 2) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -46,20 +46,27 @@ impl Connection { | |||
|     /// # Examples
 | ||||
|     ///
 | ||||
|     /// ```rust
 | ||||
|     /// use servicepoint::{Command, CompressionCode, Grid, PixelGrid};
 | ||||
|     /// let connection = servicepoint::Connection::open("172.23.42.29:2342")
 | ||||
|     ///     .expect("connection failed");
 | ||||
|     /// # use servicepoint::{Command, CompressionCode, Grid, PixelGrid};
 | ||||
|     /// # let connection = servicepoint::Connection::open("172.23.42.29:2342")
 | ||||
|     /// #     .expect("connection failed");
 | ||||
|     ///
 | ||||
|     ///  // turn off all pixels
 | ||||
|     ///  // turn off all pixels on display
 | ||||
|     ///  connection.send(Command::Clear)
 | ||||
|     ///     .expect("send failed");
 | ||||
|     ///
 | ||||
|     ///  // turn on all pixels
 | ||||
|     ///  // turn on all pixels in a grid
 | ||||
|     ///  let mut pixels = PixelGrid::max_sized();
 | ||||
|     ///  pixels.fill(true);
 | ||||
|     ///
 | ||||
|     ///  // send pixels to display
 | ||||
|     ///  connection.send(Command::BitmapLinearWin(servicepoint::Origin(0, 0), pixels, CompressionCode::Uncompressed))
 | ||||
|     ///  // create command to send pixels
 | ||||
|     ///  let command = Command::BitmapLinearWin(
 | ||||
|     ///     servicepoint::Origin::new(0, 0),
 | ||||
|     ///     pixels,
 | ||||
|     ///     CompressionCode::Uncompressed
 | ||||
|     ///  );
 | ||||
|     ///
 | ||||
|     ///  // send command to display
 | ||||
|     ///  connection.send(command)
 | ||||
|     ///     .expect("send failed");
 | ||||
|     /// ```
 | ||||
|     pub fn send( | ||||
|  |  | |||
|  | @ -7,11 +7,12 @@ use bitvec::prelude::{BitVec, Msb0}; | |||
| 
 | ||||
| pub use crate::brightness::Brightness; | ||||
| pub use crate::byte_grid::ByteGrid; | ||||
| pub use crate::command::{Command, Offset, Origin}; | ||||
| pub use crate::command::{Command, Offset}; | ||||
| pub use crate::compression_code::CompressionCode; | ||||
| pub use crate::connection::Connection; | ||||
| pub use crate::data_ref::DataRef; | ||||
| pub use crate::grid::Grid; | ||||
| pub use crate::origin::{Origin, Pixels, Tiles}; | ||||
| pub use crate::packet::{Header, Packet, Payload}; | ||||
| pub use crate::pixel_grid::PixelGrid; | ||||
| 
 | ||||
|  | @ -26,6 +27,7 @@ mod compression_code; | |||
| mod connection; | ||||
| mod data_ref; | ||||
| mod grid; | ||||
| mod origin; | ||||
| mod packet; | ||||
| mod pixel_grid; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										48
									
								
								crates/servicepoint/src/origin.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								crates/servicepoint/src/origin.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | |||
| use std::marker::PhantomData; | ||||
| 
 | ||||
| /// An origin marks the top left position of a window sent to the display.
 | ||||
| #[derive(Debug, Copy, Clone, PartialEq)] | ||||
| pub struct Origin<Unit: DisplayUnit> { | ||||
|     /// position in the width direction
 | ||||
|     pub x: usize, | ||||
|     /// position in the height direction
 | ||||
|     pub y: usize, | ||||
|     phantom_data: PhantomData<Unit>, | ||||
| } | ||||
| 
 | ||||
| impl<Unit: DisplayUnit> Origin<Unit> { | ||||
|     /// Create a new `Origin` instance for the provided position.
 | ||||
|     pub fn new(x: usize, y: usize) -> Self { | ||||
|         Self { | ||||
|             x, | ||||
|             y, | ||||
|             phantom_data: PhantomData::default(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: DisplayUnit> std::ops::Add<Origin<T>> for Origin<T> { | ||||
|     type Output = Origin<T>; | ||||
| 
 | ||||
|     fn add(self, rhs: Origin<T>) -> Self::Output { | ||||
|         Origin { | ||||
|             x: self.x + rhs.x, | ||||
|             y: self.y + rhs.y, | ||||
|             phantom_data: PhantomData::default(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub trait DisplayUnit {} | ||||
| 
 | ||||
| /// Marks something to be measured in number of pixels.
 | ||||
| #[derive(Debug, Copy, Clone, PartialEq)] | ||||
| pub struct Pixels(); | ||||
| 
 | ||||
| /// Marks something to be measured in number of iles.
 | ||||
| #[derive(Debug, Copy, Clone, PartialEq)] | ||||
| pub struct Tiles(); | ||||
| 
 | ||||
| impl DisplayUnit for Pixels {} | ||||
| 
 | ||||
| impl DisplayUnit for Tiles {} | ||||
|  | @ -105,9 +105,9 @@ pub unsafe extern "C" fn sp_command_fade_out() -> *mut Command { | |||
| /// - the returned `Command` instance is freed in some way, either by using a consuming function or
 | ||||
| ///   by explicitly calling `sp_command_dealloc`.
 | ||||
| #[no_mangle] | ||||
| pub unsafe extern "C" fn sp_command_brightness( | ||||
|     brightness: Brightness, | ||||
| ) -> *mut Command { | ||||
| pub unsafe extern "C" fn sp_command_brightness(brightness: u8) -> *mut Command { | ||||
|     let brightness = | ||||
|         Brightness::try_from(brightness).expect("invalid brightness"); | ||||
|     Box::into_raw(Box::new(Command::Brightness(brightness))) | ||||
| } | ||||
| 
 | ||||
|  | @ -129,7 +129,10 @@ pub unsafe extern "C" fn sp_command_char_brightness( | |||
|     byte_grid: *mut ByteGrid, | ||||
| ) -> *mut Command { | ||||
|     let byte_grid = *Box::from_raw(byte_grid); | ||||
|     Box::into_raw(Box::new(Command::CharBrightness(Origin(x, y), byte_grid))) | ||||
|     Box::into_raw(Box::new(Command::CharBrightness( | ||||
|         Origin::new(x, y), | ||||
|         byte_grid, | ||||
|     ))) | ||||
| } | ||||
| 
 | ||||
| /// Allocates a new `Command::BitmapLinear` instance.
 | ||||
|  | @ -254,7 +257,7 @@ pub unsafe extern "C" fn sp_command_cp437_data( | |||
|     byte_grid: *mut ByteGrid, | ||||
| ) -> *mut Command { | ||||
|     let byte_grid = *Box::from_raw(byte_grid); | ||||
|     Box::into_raw(Box::new(Command::Cp437Data(Origin(x, y), byte_grid))) | ||||
|     Box::into_raw(Box::new(Command::Cp437Data(Origin::new(x, y), byte_grid))) | ||||
| } | ||||
| 
 | ||||
| /// Allocates a new `Command::BitmapLinearWin` instance.
 | ||||
|  | @ -278,7 +281,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_win( | |||
| ) -> *mut Command { | ||||
|     let byte_grid = *Box::from_raw(pixel_grid); | ||||
|     Box::into_raw(Box::new(Command::BitmapLinearWin( | ||||
|         Origin(x, y), | ||||
|         Origin::new(x, y), | ||||
|         byte_grid, | ||||
|         compression_code, | ||||
|     ))) | ||||
|  |  | |||
|  | @ -121,7 +121,7 @@ namespace ServicePoint.BindGen | |||
|         [DllImport(__DllName, EntryPoint = "sp_command_fade_out", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern Command* sp_command_fade_out(); | ||||
| 
 | ||||
|         /// <summary>Allocates a new `Command::Brightness` instance.  # Safety  The caller has to make sure that:  - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary> | ||||
|         /// <summary>Allocates a new `Command::Brightness` instance for setting the brightness of all tiles to the same value.  # Panics  - When the provided brightness value is out of range (0-11).  # Safety  The caller has to make sure that:  - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp_command_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern Command* sp_command_brightness(byte brightness); | ||||
| 
 | ||||
|  | @ -262,17 +262,17 @@ namespace ServicePoint.BindGen | |||
|     public enum Command | ||||
|     { | ||||
|         Clear, | ||||
|         HardReset, | ||||
|         FadeOut, | ||||
|         CharBrightness, | ||||
|         Cp437Data, | ||||
|         BitmapLinearWin, | ||||
|         Brightness, | ||||
|         BitmapLegacy, | ||||
|         CharBrightness, | ||||
|         BitmapLinear, | ||||
|         BitmapLinearAnd, | ||||
|         BitmapLinearOr, | ||||
|         BitmapLinearXor, | ||||
|         Cp437Data, | ||||
|         BitmapLinearWin, | ||||
|         HardReset, | ||||
|         FadeOut, | ||||
|         BitmapLegacy, | ||||
|     } | ||||
| 
 | ||||
|     public enum CompressionCode : ushort | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vinzenz Schroeter
						Vinzenz Schroeter