u16 only in implementation details to remove need to cast for user
This commit is contained in:
		
							parent
							
								
									8adf563320
								
							
						
					
					
						commit
						b21040c1f3
					
				
					 11 changed files with 218 additions and 160 deletions
				
			
		|  | @ -9,7 +9,7 @@ | |||
| /**
 | ||||
|  * pixel count on whole screen | ||||
|  */ | ||||
| #define sp2_PIXEL_COUNT ((size_t)sp2_PIXEL_WIDTH * (size_t)sp2_PIXEL_HEIGHT) | ||||
| #define sp2_PIXEL_COUNT (sp2_PIXEL_WIDTH * sp2_PIXEL_HEIGHT) | ||||
| 
 | ||||
| /**
 | ||||
|  * screen height in pixels | ||||
|  | @ -111,7 +111,7 @@ typedef struct sp2_CByteSlice { | |||
| /**
 | ||||
|  * Type alias for documenting the meaning of the u16 in enum values | ||||
|  */ | ||||
| typedef uint16_t sp2_Offset; | ||||
| typedef size_t sp2_Offset; | ||||
| 
 | ||||
| /**
 | ||||
|  * Type alias for documenting the meaning of the u16 in enum values | ||||
|  | @ -282,8 +282,8 @@ struct sp2_Command *sp2_command_bitmap_linear_or(sp2_Offset offset, | |||
|  * Allocates a new `Command::BitmapLinearWin` instance. | ||||
|  * The passed `PixelGrid` gets deallocated in the process. | ||||
|  */ | ||||
| struct sp2_Command *sp2_command_bitmap_linear_win(uint16_t x, | ||||
|                                                   uint16_t y, | ||||
| struct sp2_Command *sp2_command_bitmap_linear_win(size_t x, | ||||
|                                                   size_t y, | ||||
|                                                   struct sp2_PixelGrid *byte_grid, | ||||
|                                                   sp2_CompressionCode compression_code); | ||||
| 
 | ||||
|  | @ -304,8 +304,8 @@ struct sp2_Command *sp2_command_brightness(sp2_Brightness brightness); | |||
|  * Allocates a new `Command::CharBrightness` instance. | ||||
|  * The passed `ByteGrid` gets deallocated in the process. | ||||
|  */ | ||||
| struct sp2_Command *sp2_command_char_brightness(uint16_t x, | ||||
|                                                 uint16_t y, | ||||
| struct sp2_Command *sp2_command_char_brightness(size_t x, | ||||
|                                                 size_t y, | ||||
|                                                 struct sp2_ByteGrid *byte_grid); | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -322,8 +322,8 @@ struct sp2_Command *sp2_command_clone(const struct sp2_Command *original); | |||
|  * Allocates a new `Command::Cp437Data` instance. | ||||
|  * The passed `ByteGrid` gets deallocated in the process. | ||||
|  */ | ||||
| struct sp2_Command *sp2_command_cp437_data(uint16_t x, | ||||
|                                            uint16_t y, | ||||
| struct sp2_Command *sp2_command_cp437_data(size_t x, | ||||
|                                            size_t y, | ||||
|                                            struct sp2_ByteGrid *byte_grid); | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -125,31 +125,31 @@ namespace ServicePoint2.BindGen | |||
| 
 | ||||
|         /// <summary>Allocates a new `Command::CharBrightness` instance. The passed `ByteGrid` gets deallocated in the process.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_command_char_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern Command* sp2_command_char_brightness(ushort x, ushort y, ByteGrid* byte_grid); | ||||
|         public static extern Command* sp2_command_char_brightness(nuint x, nuint y, ByteGrid* byte_grid); | ||||
| 
 | ||||
|         /// <summary>Allocates a new `Command::BitmapLinear` instance. The passed `BitVec` gets deallocated in the process.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern Command* sp2_command_bitmap_linear(ushort offset, BitVec* bit_vec, CompressionCode compression); | ||||
|         public static extern Command* sp2_command_bitmap_linear(nuint offset, BitVec* bit_vec, CompressionCode compression); | ||||
| 
 | ||||
|         /// <summary>Allocates a new `Command::BitmapLinearAnd` instance. The passed `BitVec` gets deallocated in the process.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_and", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern Command* sp2_command_bitmap_linear_and(ushort offset, BitVec* bit_vec, CompressionCode compression); | ||||
|         public static extern Command* sp2_command_bitmap_linear_and(nuint offset, BitVec* bit_vec, CompressionCode compression); | ||||
| 
 | ||||
|         /// <summary>Allocates a new `Command::BitmapLinearOr` instance. The passed `BitVec` gets deallocated in the process.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_or", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern Command* sp2_command_bitmap_linear_or(ushort offset, BitVec* bit_vec, CompressionCode compression); | ||||
|         public static extern Command* sp2_command_bitmap_linear_or(nuint offset, BitVec* bit_vec, CompressionCode compression); | ||||
| 
 | ||||
|         /// <summary>Allocates a new `Command::BitmapLinearXor` instance. The passed `BitVec` gets deallocated in the process.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_xor", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern Command* sp2_command_bitmap_linear_xor(ushort offset, BitVec* bit_vec, CompressionCode compression); | ||||
|         public static extern Command* sp2_command_bitmap_linear_xor(nuint offset, BitVec* bit_vec, CompressionCode compression); | ||||
| 
 | ||||
|         /// <summary>Allocates a new `Command::Cp437Data` instance. The passed `ByteGrid` gets deallocated in the process.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_command_cp437_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern Command* sp2_command_cp437_data(ushort x, ushort y, ByteGrid* byte_grid); | ||||
|         public static extern Command* sp2_command_cp437_data(nuint x, nuint y, ByteGrid* byte_grid); | ||||
| 
 | ||||
|         /// <summary>Allocates a new `Command::BitmapLinearWin` instance. The passed `PixelGrid` gets deallocated in the process.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_command_bitmap_linear_win", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|         public static extern Command* sp2_command_bitmap_linear_win(ushort x, ushort y, PixelGrid* byte_grid, CompressionCode compression_code); | ||||
|         public static extern Command* sp2_command_bitmap_linear_win(nuint x, nuint y, PixelGrid* byte_grid, CompressionCode compression_code); | ||||
| 
 | ||||
|         /// <summary>Deallocates a `Command`. Note that connection_send does this implicitly, so you only need to do this if you use the library for parsing commands.</summary> | ||||
|         [DllImport(__DllName, EntryPoint = "sp2_command_dealloc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| use crate::DataRef; | ||||
| 
 | ||||
| /// A vector of bits
 | ||||
| #[derive(Clone, PartialEq)] | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| pub struct BitVec { | ||||
|     size: usize, | ||||
|     data: Vec<u8>, | ||||
|  | @ -15,6 +15,11 @@ impl BitVec { | |||
|     /// * `size`: size in bits. Must be dividable by 8.
 | ||||
|     ///
 | ||||
|     /// returns: bit vector with all bits set to false.
 | ||||
|     ///
 | ||||
|     /// # Panics
 | ||||
|     ///
 | ||||
|     /// When size is not a multiple of 8.
 | ||||
|     #[must_use] | ||||
|     pub fn new(size: usize) -> BitVec { | ||||
|         assert_eq!(size % 8, 0); | ||||
|         Self { | ||||
|  | @ -53,6 +58,7 @@ impl BitVec { | |||
|     /// * `index`: the bit index to read
 | ||||
|     ///
 | ||||
|     /// returns: value of the bit
 | ||||
|     #[must_use] | ||||
|     pub fn get(&self, index: usize) -> bool { | ||||
|         let (byte_index, bit_mask) = self.get_indexes(index); | ||||
|         self.data[byte_index] & bit_mask != 0 | ||||
|  | @ -76,23 +82,24 @@ impl BitVec { | |||
|     } | ||||
| 
 | ||||
|     /// Gets the length in bits
 | ||||
|     #[must_use] | ||||
|     pub fn len(&self) -> usize { | ||||
|         self.size | ||||
|     } | ||||
| 
 | ||||
|     /// returns true if length is 0.
 | ||||
|     #[must_use] | ||||
|     pub fn is_empty(&self) -> bool { | ||||
|         self.data.is_empty() | ||||
|     } | ||||
| 
 | ||||
|     /// Calculates the byte index and bitmask for a specific bit in the vector
 | ||||
|     fn get_indexes(&self, bit_index: usize) -> (usize, u8) { | ||||
|         if bit_index >= self.size { | ||||
|             panic!( | ||||
|                 "bit index {bit_index} is outside of range 0..<{}", | ||||
|                 self.size | ||||
|             ) | ||||
|         } | ||||
|         assert!( | ||||
|             bit_index < self.size, | ||||
|             "bit index {bit_index} is outside of range 0..<{}", | ||||
|             self.size | ||||
|         ); | ||||
| 
 | ||||
|         let byte_index = bit_index / 8; | ||||
|         let bit_in_byte_index = 7 - bit_index % 8; | ||||
|  | @ -128,16 +135,6 @@ impl From<&[u8]> for BitVec { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| impl std::fmt::Debug for BitVec { | ||||
|     /// Formats a `BitVec` for debug. The manual implementation includes the length of the instance.
 | ||||
|     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         fmt.debug_struct("BitVec") | ||||
|             .field("len", &self.len()) | ||||
|             .field("data", &self.data) | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(feature = "c_api")] | ||||
| pub mod c_api { | ||||
|     use crate::{BitVec, CByteSlice, DataRef}; | ||||
|  |  | |||
|  | @ -9,13 +9,14 @@ pub struct ByteGrid { | |||
| } | ||||
| 
 | ||||
| impl ByteGrid { | ||||
|     /// Loads a byte grid with the specified dimensions from the provided data.
 | ||||
|     /// Loads a `ByteGrid` with the specified dimensions from the provided data.
 | ||||
|     ///
 | ||||
|     /// returns: ByteGrid that contains a copy of the provided data
 | ||||
|     /// returns: `ByteGrid` that contains a copy of the provided data
 | ||||
|     ///
 | ||||
|     /// # Panics
 | ||||
|     ///
 | ||||
|     /// - when the dimensions and data size do not match exactly.
 | ||||
|     #[must_use] | ||||
|     pub fn load(width: usize, height: usize, data: &[u8]) -> Self { | ||||
|         assert_eq!(width * height, data.len()); | ||||
|         Self { | ||||
|  | @ -26,19 +27,23 @@ impl ByteGrid { | |||
|     } | ||||
| 
 | ||||
|     fn check_indexes(&self, x: usize, y: usize) { | ||||
|         if x >= self.width { | ||||
|             panic!("cannot access byte {x}-{y} because x is outside of bounds 0..{}", self.width) | ||||
|         } | ||||
|         if y >= self.height { | ||||
|             panic!("cannot access byte {x}-{y} because y is outside of bounds 0..{}", self.height) | ||||
|         } | ||||
|         assert!( | ||||
|             x < self.width, | ||||
|             "cannot access byte {x}-{y} because x is outside of bounds 0..{}", | ||||
|             self.width | ||||
|         ); | ||||
|         assert!( | ||||
|             y < self.height, | ||||
|             "cannot access byte {x}-{y} because y is outside of bounds 0..{}", | ||||
|             self.height | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Grid<u8> for ByteGrid { | ||||
|     /// Creates a new byte grid with the specified dimensions.
 | ||||
|     /// Creates a new `ByteGrid` with the specified dimensions.
 | ||||
|     ///
 | ||||
|     /// returns: ByteGrid initialized to 0.
 | ||||
|     /// returns: `ByteGrid` initialized to 0.
 | ||||
|     fn new(width: usize, height: usize) -> Self { | ||||
|         Self { | ||||
|             data: vec![0; width * height], | ||||
|  | @ -61,7 +66,7 @@ impl Grid<u8> for ByteGrid { | |||
|     } | ||||
| 
 | ||||
|     fn fill(&mut self, value: u8) { | ||||
|         self.data.fill(value) | ||||
|         self.data.fill(value); | ||||
|     } | ||||
| 
 | ||||
|     fn width(&self) -> usize { | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ use crate::{ | |||
| 
 | ||||
| /// An origin marks the top left position of a window sent to the display.
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq)] | ||||
| pub struct Origin(pub u16, pub u16); | ||||
| pub struct Origin(pub usize, pub usize); | ||||
| 
 | ||||
| impl std::ops::Add<Origin> for Origin { | ||||
|     type Output = Origin; | ||||
|  | @ -19,12 +19,8 @@ impl std::ops::Add<Origin> for Origin { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Size defines the width and height of a window
 | ||||
| #[derive(Debug, Clone, Copy)] | ||||
| pub struct Size(pub u16, pub u16); | ||||
| 
 | ||||
| /// Type alias for documenting the meaning of the u16 in enum values
 | ||||
| pub type Offset = u16; | ||||
| pub type Offset = usize; | ||||
| 
 | ||||
| /// Type alias for documenting the meaning of the u16 in enum values
 | ||||
| pub type Brightness = u8; | ||||
|  | @ -46,16 +42,16 @@ pub enum Command { | |||
|     /// Legacy command code, gets ignored by the real display.
 | ||||
|     BitmapLegacy, | ||||
|     /// Set pixel data starting at the offset.
 | ||||
|     /// The contained BitVec is always uncompressed.
 | ||||
|     /// The contained `BitVec` is always uncompressed.
 | ||||
|     BitmapLinear(Offset, BitVec, CompressionCode), | ||||
|     /// Set pixel data according to an and-mask starting at the offset.
 | ||||
|     /// The contained BitVec is always uncompressed.
 | ||||
|     /// The contained `BitVec` is always uncompressed.
 | ||||
|     BitmapLinearAnd(Offset, BitVec, CompressionCode), | ||||
|     /// Set pixel data according to an or-mask starting at the offset.
 | ||||
|     /// The contained BitVec is always uncompressed.
 | ||||
|     /// The contained `BitVec` is always uncompressed.
 | ||||
|     BitmapLinearOr(Offset, BitVec, CompressionCode), | ||||
|     /// Set pixel data according to an xor-mask starting at the offset.
 | ||||
|     /// The contained BitVec is always uncompressed.
 | ||||
|     /// Set pixel data according to a xor-mask starting at the offset.
 | ||||
|     /// The contained `BitVec` is always uncompressed.
 | ||||
|     BitmapLinearXor(Offset, BitVec, CompressionCode), | ||||
|     /// Show text on the screen. Note that the byte data has to be CP437 encoded.
 | ||||
|     Cp437Data(Origin, ByteGrid), | ||||
|  | @ -65,6 +61,7 @@ pub enum Command { | |||
| 
 | ||||
| impl From<Command> for Packet { | ||||
|     /// Move the `Command` into a `Packet` instance for sending.
 | ||||
|     #[allow(clippy::cast_possible_truncation)] | ||||
|     fn from(value: Command) -> Self { | ||||
|         match value { | ||||
|             Command::Clear => Command::command_code_only(CommandCode::Clear), | ||||
|  | @ -81,8 +78,8 @@ impl From<Command> for Packet { | |||
|             Command::CharBrightness(Origin(x, y), grid) => Packet( | ||||
|                 Header( | ||||
|                     CommandCode::CharBrightness.into(), | ||||
|                     x, | ||||
|                     y, | ||||
|                     x as u16, | ||||
|                     y as u16, | ||||
|                     grid.width() as u16, | ||||
|                     grid.height() as u16, | ||||
|                 ), | ||||
|  | @ -98,36 +95,8 @@ impl From<Command> for Packet { | |||
|                 ), | ||||
|                 vec![brightness], | ||||
|             ), | ||||
|             Command::BitmapLinearWin( | ||||
|                 Origin(pixel_x, pixel_y), | ||||
|                 pixels, | ||||
|                 compression, | ||||
|             ) => { | ||||
|                 debug_assert_eq!(pixel_x % 8, 0); | ||||
|                 debug_assert_eq!(pixels.width() % 8, 0); | ||||
| 
 | ||||
|                 let tile_x = pixel_x / TILE_SIZE; | ||||
|                 let tile_w = pixels.width() as u16 / TILE_SIZE; | ||||
|                 let pixel_h = pixels.height() as u16; | ||||
|                 let payload = into_compressed(compression, pixels.into()); | ||||
|                 let command = match compression { | ||||
|                     CompressionCode::Uncompressed => { | ||||
|                         CommandCode::BitmapLinearWinUncompressed | ||||
|                     } | ||||
|                     #[cfg(feature = "compression_zlib")] | ||||
|                     CompressionCode::Zlib => CommandCode::BitmapLinearWinZlib, | ||||
|                     #[cfg(feature = "compression_bzip2")] | ||||
|                     CompressionCode::Bzip2 => CommandCode::BitmapLinearWinBzip2, | ||||
|                     #[cfg(feature = "compression_lzma")] | ||||
|                     CompressionCode::Lzma => CommandCode::BitmapLinearWinLzma, | ||||
|                     #[cfg(feature = "compression_zstd")] | ||||
|                     CompressionCode::Zstd => CommandCode::BitmapLinearWinZstd, | ||||
|                 }; | ||||
| 
 | ||||
|                 Packet( | ||||
|                     Header(command.into(), tile_x, pixel_y, tile_w, pixel_h), | ||||
|                     payload, | ||||
|                 ) | ||||
|             Command::BitmapLinearWin(origin, pixels, compression) => { | ||||
|                 bitmap_win_into_packet(origin, pixels, compression) | ||||
|             } | ||||
|             Command::BitmapLinear(offset, bits, compression) => { | ||||
|                 Command::bitmap_linear_into_packet( | ||||
|  | @ -164,8 +133,8 @@ impl From<Command> for Packet { | |||
|             Command::Cp437Data(Origin(x, y), grid) => Packet( | ||||
|                 Header( | ||||
|                     CommandCode::Cp437Data.into(), | ||||
|                     x, | ||||
|                     y, | ||||
|                     x as u16, | ||||
|                     y as u16, | ||||
|                     grid.width() as u16, | ||||
|                     grid.height() as u16, | ||||
|                 ), | ||||
|  | @ -175,6 +144,40 @@ impl From<Command> for Packet { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| #[allow(clippy::cast_possible_truncation)] | ||||
| fn bitmap_win_into_packet( | ||||
|     origin: Origin, | ||||
|     pixels: PixelGrid, | ||||
|     compression: CompressionCode, | ||||
| ) -> Packet { | ||||
|     let Origin(pixel_x, pixel_y) = origin; | ||||
|     debug_assert_eq!(pixel_x % 8, 0); | ||||
|     debug_assert_eq!(pixels.width() % 8, 0); | ||||
| 
 | ||||
|     let tile_x = (pixel_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()); | ||||
|     let command = match compression { | ||||
|         CompressionCode::Uncompressed => { | ||||
|             CommandCode::BitmapLinearWinUncompressed | ||||
|         } | ||||
|         #[cfg(feature = "compression_zlib")] | ||||
|         CompressionCode::Zlib => CommandCode::BitmapLinearWinZlib, | ||||
|         #[cfg(feature = "compression_bzip2")] | ||||
|         CompressionCode::Bzip2 => CommandCode::BitmapLinearWinBzip2, | ||||
|         #[cfg(feature = "compression_lzma")] | ||||
|         CompressionCode::Lzma => CommandCode::BitmapLinearWinLzma, | ||||
|         #[cfg(feature = "compression_zstd")] | ||||
|         CompressionCode::Zstd => CommandCode::BitmapLinearWinZstd, | ||||
|     }; | ||||
| 
 | ||||
|     Packet( | ||||
|         Header(command.into(), tile_x, pixel_y as u16, tile_w, pixel_h), | ||||
|         payload, | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| /// Err values for `Command::try_from`.
 | ||||
| #[derive(PartialEq)] | ||||
|  | @ -200,7 +203,7 @@ impl TryFrom<Packet> for Command { | |||
|     fn try_from(packet: Packet) -> Result<Self, Self::Error> { | ||||
|         let Packet(Header(command_u16, a, b, c, d), _) = packet; | ||||
|         let command_code = match CommandCode::try_from(command_u16) { | ||||
|             Err(_) => { | ||||
|             Err(()) => { | ||||
|                 return Err(TryFromPacketError::InvalidCommand(command_u16)); | ||||
|             } | ||||
|             Ok(value) => value, | ||||
|  | @ -238,14 +241,14 @@ impl TryFrom<Packet> for Command { | |||
|             CommandCode::Cp437Data => { | ||||
|                 let Packet(_, payload) = packet; | ||||
|                 Ok(Command::Cp437Data( | ||||
|                     Origin(a, b), | ||||
|                     Origin(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, b), | ||||
|                     Origin(a as usize, b as usize), | ||||
|                     ByteGrid::load(c as usize, d as usize, &payload), | ||||
|                 )) | ||||
|             } | ||||
|  | @ -254,22 +257,22 @@ impl TryFrom<Packet> for Command { | |||
|             CommandCode::BitmapLinear => { | ||||
|                 let (vec, compression) = | ||||
|                     Self::packet_into_linear_bitmap(packet)?; | ||||
|                 Ok(Command::BitmapLinear(a, vec, compression)) | ||||
|                 Ok(Command::BitmapLinear(a as Offset, vec, compression)) | ||||
|             } | ||||
|             CommandCode::BitmapLinearAnd => { | ||||
|                 let (vec, compression) = | ||||
|                     Self::packet_into_linear_bitmap(packet)?; | ||||
|                 Ok(Command::BitmapLinearAnd(a, vec, compression)) | ||||
|                 Ok(Command::BitmapLinearAnd(a as Offset, vec, compression)) | ||||
|             } | ||||
|             CommandCode::BitmapLinearOr => { | ||||
|                 let (vec, compression) = | ||||
|                     Self::packet_into_linear_bitmap(packet)?; | ||||
|                 Ok(Command::BitmapLinearOr(a, vec, compression)) | ||||
|                 Ok(Command::BitmapLinearOr(a as Offset, vec, compression)) | ||||
|             } | ||||
|             CommandCode::BitmapLinearXor => { | ||||
|                 let (vec, compression) = | ||||
|                     Self::packet_into_linear_bitmap(packet)?; | ||||
|                 Ok(Command::BitmapLinearXor(a, vec, compression)) | ||||
|                 Ok(Command::BitmapLinearXor(a as Offset, vec, compression)) | ||||
|             } | ||||
|             CommandCode::BitmapLinearWinUncompressed => { | ||||
|                 Self::packet_into_bitmap_win( | ||||
|  | @ -311,9 +314,9 @@ impl Command { | |||
|         }; | ||||
| 
 | ||||
|         Ok(Command::BitmapLinearWin( | ||||
|             Origin(tiles_x * TILE_SIZE, pixels_y), | ||||
|             Origin(tiles_x as usize * TILE_SIZE, pixels_y as usize), | ||||
|             PixelGrid::load( | ||||
|                 tile_w as usize * TILE_SIZE as usize, | ||||
|                 tile_w as usize * TILE_SIZE, | ||||
|                 pixel_h as usize, | ||||
|                 &payload, | ||||
|             ), | ||||
|  | @ -321,7 +324,8 @@ impl Command { | |||
|         )) | ||||
|     } | ||||
| 
 | ||||
|     /// Helper method for BitMapLinear*-Commands into Packet
 | ||||
|     /// Helper method for `BitMapLinear*`-Commands into `Packet`
 | ||||
|     #[allow(clippy::cast_possible_truncation)] | ||||
|     fn bitmap_linear_into_packet( | ||||
|         command: CommandCode, | ||||
|         offset: Offset, | ||||
|  | @ -331,7 +335,13 @@ impl Command { | |||
|         let length = payload.len() as u16; | ||||
|         let payload = into_compressed(compression, payload); | ||||
|         Packet( | ||||
|             Header(command.into(), offset, length, compression.into(), 0), | ||||
|             Header( | ||||
|                 command.into(), | ||||
|                 offset as u16, | ||||
|                 length, | ||||
|                 compression.into(), | ||||
|                 0, | ||||
|             ), | ||||
|             payload, | ||||
|         ) | ||||
|     } | ||||
|  | @ -353,7 +363,7 @@ impl Command { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Helper method for Packets into BitMapLinear*-Commands
 | ||||
|     /// Helper method for Packets into `BitMapLinear*`-Commands
 | ||||
|     fn packet_into_linear_bitmap( | ||||
|         packet: Packet, | ||||
|     ) -> Result<(BitVec, CompressionCode), TryFromPacketError> { | ||||
|  | @ -362,7 +372,7 @@ impl Command { | |||
|             return Err(TryFromPacketError::ExtraneousHeaderValues); | ||||
|         } | ||||
|         let sub = match CompressionCode::try_from(sub) { | ||||
|             Err(_) => { | ||||
|             Err(()) => { | ||||
|                 return Err(TryFromPacketError::InvalidCompressionCode(sub)); | ||||
|             } | ||||
|             Ok(value) => value, | ||||
|  | @ -442,8 +452,8 @@ pub mod c_api { | |||
|     /// The passed `ByteGrid` gets deallocated in the process.
 | ||||
|     #[no_mangle] | ||||
|     pub unsafe extern "C" fn sp2_command_char_brightness( | ||||
|         x: u16, | ||||
|         y: u16, | ||||
|         x: usize, | ||||
|         y: usize, | ||||
|         byte_grid: *mut ByteGrid, | ||||
|     ) -> *mut Command { | ||||
|         let byte_grid = *Box::from_raw(byte_grid); | ||||
|  | @ -521,8 +531,8 @@ pub mod c_api { | |||
|     /// The passed `ByteGrid` gets deallocated in the process.
 | ||||
|     #[no_mangle] | ||||
|     pub unsafe extern "C" fn sp2_command_cp437_data( | ||||
|         x: u16, | ||||
|         y: u16, | ||||
|         x: usize, | ||||
|         y: usize, | ||||
|         byte_grid: *mut ByteGrid, | ||||
|     ) -> *mut Command { | ||||
|         let byte_grid = *Box::from_raw(byte_grid); | ||||
|  | @ -533,8 +543,8 @@ pub mod c_api { | |||
|     /// The passed `PixelGrid` gets deallocated in the process.
 | ||||
|     #[no_mangle] | ||||
|     pub unsafe extern "C" fn sp2_command_bitmap_linear_win( | ||||
|         x: u16, | ||||
|         y: u16, | ||||
|         x: usize, | ||||
|         y: usize, | ||||
|         byte_grid: *mut PixelGrid, | ||||
|         compression_code: CompressionCode, | ||||
|     ) -> *mut Command { | ||||
|  |  | |||
|  | @ -37,39 +37,61 @@ impl TryFrom<u16> for CommandCode { | |||
| 
 | ||||
|     /// Returns the enum value for the specified `u16` or `Error` if the code is unknown.
 | ||||
|     fn try_from(value: u16) -> Result<Self, Self::Error> { | ||||
|         use CommandCode::*; | ||||
| 
 | ||||
|         match value { | ||||
|             value if value == Clear as u16 => Ok(Clear), | ||||
|             value if value == Cp437Data as u16 => Ok(Cp437Data), | ||||
|             value if value == CharBrightness as u16 => Ok(CharBrightness), | ||||
|             value if value == Brightness as u16 => Ok(Brightness), | ||||
|             value if value == HardReset as u16 => Ok(HardReset), | ||||
|             value if value == FadeOut as u16 => Ok(FadeOut), | ||||
|             #[allow(deprecated)] | ||||
|             value if value == BitmapLegacy as u16 => Ok(BitmapLegacy), | ||||
|             value if value == BitmapLinear as u16 => Ok(BitmapLinear), | ||||
|             value if value == BitmapLinearWinUncompressed as u16 => { | ||||
|                 Ok(BitmapLinearWinUncompressed) | ||||
|             value if value == CommandCode::Clear as u16 => { | ||||
|                 Ok(CommandCode::Clear) | ||||
|             } | ||||
|             value if value == CommandCode::Cp437Data as u16 => { | ||||
|                 Ok(CommandCode::Cp437Data) | ||||
|             } | ||||
|             value if value == CommandCode::CharBrightness as u16 => { | ||||
|                 Ok(CommandCode::CharBrightness) | ||||
|             } | ||||
|             value if value == CommandCode::Brightness as u16 => { | ||||
|                 Ok(CommandCode::Brightness) | ||||
|             } | ||||
|             value if value == CommandCode::HardReset as u16 => { | ||||
|                 Ok(CommandCode::HardReset) | ||||
|             } | ||||
|             value if value == CommandCode::FadeOut as u16 => { | ||||
|                 Ok(CommandCode::FadeOut) | ||||
|             } | ||||
|             #[allow(deprecated)] | ||||
|             value if value == CommandCode::BitmapLegacy as u16 => { | ||||
|                 Ok(CommandCode::BitmapLegacy) | ||||
|             } | ||||
|             value if value == CommandCode::BitmapLinear as u16 => { | ||||
|                 Ok(CommandCode::BitmapLinear) | ||||
|             } | ||||
|             value | ||||
|                 if value == CommandCode::BitmapLinearWinUncompressed as u16 => | ||||
|             { | ||||
|                 Ok(CommandCode::BitmapLinearWinUncompressed) | ||||
|             } | ||||
|             value if value == CommandCode::BitmapLinearAnd as u16 => { | ||||
|                 Ok(CommandCode::BitmapLinearAnd) | ||||
|             } | ||||
|             value if value == CommandCode::BitmapLinearOr as u16 => { | ||||
|                 Ok(CommandCode::BitmapLinearOr) | ||||
|             } | ||||
|             value if value == CommandCode::BitmapLinearXor as u16 => { | ||||
|                 Ok(CommandCode::BitmapLinearXor) | ||||
|             } | ||||
|             value if value == BitmapLinearAnd as u16 => Ok(BitmapLinearAnd), | ||||
|             value if value == BitmapLinearOr as u16 => Ok(BitmapLinearOr), | ||||
|             value if value == BitmapLinearXor as u16 => Ok(BitmapLinearXor), | ||||
|             #[cfg(feature = "compression_zstd")] | ||||
|             value if value == BitmapLinearWinZstd as u16 => { | ||||
|                 Ok(BitmapLinearWinZstd) | ||||
|             value if value == CommandCode::BitmapLinearWinZstd as u16 => { | ||||
|                 Ok(CommandCode::BitmapLinearWinZstd) | ||||
|             } | ||||
|             #[cfg(feature = "compression_lzma")] | ||||
|             value if value == BitmapLinearWinLzma as u16 => { | ||||
|                 Ok(BitmapLinearWinLzma) | ||||
|             value if value == CommandCode::BitmapLinearWinLzma as u16 => { | ||||
|                 Ok(CommandCode::BitmapLinearWinLzma) | ||||
|             } | ||||
|             #[cfg(feature = "compression_zlib")] | ||||
|             value if value == BitmapLinearWinZlib as u16 => { | ||||
|                 Ok(BitmapLinearWinZlib) | ||||
|             value if value == CommandCode::BitmapLinearWinZlib as u16 => { | ||||
|                 Ok(CommandCode::BitmapLinearWinZlib) | ||||
|             } | ||||
|             #[cfg(feature = "compression_bzip2")] | ||||
|             value if value == BitmapLinearWinBzip2 as u16 => { | ||||
|                 Ok(BitmapLinearWinBzip2) | ||||
|             value if value == CommandCode::BitmapLinearWinBzip2 as u16 => { | ||||
|                 Ok(CommandCode::BitmapLinearWinBzip2) | ||||
|             } | ||||
|             _ => Err(()), | ||||
|         } | ||||
|  |  | |||
|  | @ -1,5 +1,3 @@ | |||
| use CompressionCode::*; | ||||
| 
 | ||||
| /// Specifies the kind of compression to use. Availability depends on features.
 | ||||
| #[repr(u16)] | ||||
| #[derive(Debug, Clone, Copy, PartialEq)] | ||||
|  | @ -26,15 +24,25 @@ impl TryFrom<u16> for CompressionCode { | |||
| 
 | ||||
|     fn try_from(value: u16) -> Result<Self, Self::Error> { | ||||
|         match value { | ||||
|             value if value == Uncompressed as u16 => Ok(Uncompressed), | ||||
|             value if value == CompressionCode::Uncompressed as u16 => { | ||||
|                 Ok(CompressionCode::Uncompressed) | ||||
|             } | ||||
|             #[cfg(feature = "compression_zlib")] | ||||
|             value if value == Zlib as u16 => Ok(Zlib), | ||||
|             value if value == CompressionCode::Zlib as u16 => { | ||||
|                 Ok(CompressionCode::Zlib) | ||||
|             } | ||||
|             #[cfg(feature = "compression_bzip2")] | ||||
|             value if value == Bzip2 as u16 => Ok(Bzip2), | ||||
|             value if value == CompressionCode::Bzip2 as u16 => { | ||||
|                 Ok(CompressionCode::Bzip2) | ||||
|             } | ||||
|             #[cfg(feature = "compression_lzma")] | ||||
|             value if value == Lzma as u16 => Ok(Lzma), | ||||
|             value if value == CompressionCode::Lzma as u16 => { | ||||
|                 Ok(CompressionCode::Lzma) | ||||
|             } | ||||
|             #[cfg(feature = "compression_zstd")] | ||||
|             value if value == Zstd as u16 => Ok(Zstd), | ||||
|             value if value == CompressionCode::Zstd as u16 => { | ||||
|                 Ok(CompressionCode::Zstd) | ||||
|             } | ||||
|             _ => Err(()), | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -15,6 +15,10 @@ impl Connection { | |||
|     ///
 | ||||
|     /// Note that this is UDP, which means that the open call can succeed even if the display is unreachable.
 | ||||
|     ///
 | ||||
|     /// # Errors
 | ||||
|     ///
 | ||||
|     /// Any errors resulting from binding the udp socket.
 | ||||
|     ///
 | ||||
|     /// # Examples
 | ||||
|     /// ```rust
 | ||||
|     ///  let connection = servicepoint2::Connection::open("172.23.42.29:2342")
 | ||||
|  | @ -35,6 +39,10 @@ impl Connection { | |||
|     ///
 | ||||
|     /// returns: Ok if packet was sent, otherwise socket error
 | ||||
|     ///
 | ||||
|     /// # Errors
 | ||||
|     ///
 | ||||
|     /// Any errors produced while sending using the underlying socket.
 | ||||
|     ///
 | ||||
|     /// # Examples
 | ||||
|     ///
 | ||||
|     /// ```rust
 | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| pub trait Grid<T> { | ||||
|     #[must_use] | ||||
|     fn new(width: usize, height: usize) -> Self; | ||||
| 
 | ||||
|     /// Sets the value at the specified position
 | ||||
|  | @ -47,5 +48,6 @@ pub trait Grid<T> { | |||
|     ///
 | ||||
|     /// let (l, r) = split(ByteGrid::new(9, 5));
 | ||||
|     /// ```
 | ||||
|     #[must_use] | ||||
|     fn window(&self, x: usize, y: usize, w: usize, h: usize) -> Self; | ||||
| } | ||||
|  |  | |||
|  | @ -1,16 +1,16 @@ | |||
| use std::time::Duration; | ||||
| 
 | ||||
| pub use crate::bit_vec::BitVec; | ||||
| pub use crate::byte_grid::ByteGrid; | ||||
| pub use crate::command::{Brightness, Command, Offset, Origin, Size}; | ||||
| #[cfg(feature = "c_api")] | ||||
| pub use crate::c_slice::CByteSlice; | ||||
| pub use crate::command::{Brightness, Command, Offset, Origin}; | ||||
| 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::packet::{Header, Packet, Payload}; | ||||
| pub use crate::pixel_grid::PixelGrid; | ||||
| use std::time::Duration; | ||||
| 
 | ||||
| #[cfg(feature = "c_api")] | ||||
| pub use crate::c_slice::CByteSlice; | ||||
| 
 | ||||
| mod bit_vec; | ||||
| mod byte_grid; | ||||
|  | @ -26,22 +26,22 @@ mod packet; | |||
| mod pixel_grid; | ||||
| 
 | ||||
| /// size of a single tile in one dimension
 | ||||
| pub const TILE_SIZE: u16 = 8; | ||||
| pub const TILE_SIZE: usize = 8; | ||||
| 
 | ||||
| /// tile count in the x-direction
 | ||||
| pub const TILE_WIDTH: u16 = 56; | ||||
| pub const TILE_WIDTH: usize = 56; | ||||
| 
 | ||||
| /// tile count in the y-direction
 | ||||
| pub const TILE_HEIGHT: u16 = 20; | ||||
| pub const TILE_HEIGHT: usize = 20; | ||||
| 
 | ||||
| /// screen width in pixels
 | ||||
| pub const PIXEL_WIDTH: u16 = TILE_WIDTH * TILE_SIZE; | ||||
| pub const PIXEL_WIDTH: usize = TILE_WIDTH * TILE_SIZE; | ||||
| 
 | ||||
| /// screen height in pixels
 | ||||
| pub const PIXEL_HEIGHT: u16 = TILE_HEIGHT * TILE_SIZE; | ||||
| pub const PIXEL_HEIGHT: usize = TILE_HEIGHT * TILE_SIZE; | ||||
| 
 | ||||
| /// pixel count on whole screen
 | ||||
| pub const PIXEL_COUNT: usize = PIXEL_WIDTH as usize * PIXEL_HEIGHT as usize; | ||||
| pub const PIXEL_COUNT: usize = PIXEL_WIDTH * PIXEL_HEIGHT; | ||||
| 
 | ||||
| /// Actual hardware limit is around 28-29ms/frame. Rounded up for less dropped packets.
 | ||||
| pub const FRAME_PACING: Duration = Duration::from_millis(30); | ||||
|  |  | |||
|  | @ -10,23 +10,25 @@ pub struct PixelGrid { | |||
| 
 | ||||
| impl PixelGrid { | ||||
|     /// Creates a new pixel grid with the size of the whole screen.
 | ||||
|     #[must_use] | ||||
|     pub fn max_sized() -> Self { | ||||
|         Self::new(PIXEL_WIDTH as usize, PIXEL_HEIGHT as usize) | ||||
|         Self::new(PIXEL_WIDTH, PIXEL_HEIGHT) | ||||
|     } | ||||
| 
 | ||||
|     /// Loads a pixel grid with the specified dimensions from the provided data.
 | ||||
|     /// Loads a `PixelGrid` with the specified dimensions from the provided data.
 | ||||
|     ///
 | ||||
|     /// # Arguments
 | ||||
|     ///
 | ||||
|     /// * `width`: size in pixels in x-direction
 | ||||
|     /// * `height`: size in pixels in y-direction
 | ||||
|     ///
 | ||||
|     /// returns: PixelGrid that contains a copy of the provided data
 | ||||
|     /// returns: `PixelGrid` that contains a copy of the provided data
 | ||||
|     ///
 | ||||
|     /// # Panics
 | ||||
|     ///
 | ||||
|     /// - when the dimensions and data size do not match exactly.
 | ||||
|     /// - when the width is not dividable by 8
 | ||||
|     #[must_use] | ||||
|     pub fn load(width: usize, height: usize, data: &[u8]) -> Self { | ||||
|         assert_eq!(width % 8, 0); | ||||
|         assert_eq!(data.len(), height * width / 8); | ||||
|  | @ -38,24 +40,28 @@ impl PixelGrid { | |||
|     } | ||||
| 
 | ||||
|     fn check_indexes(&self, x: usize, y: usize) { | ||||
|         if x >= self.width { | ||||
|             panic!("cannot access pixel {x}-{y} because x is outside of bounds 0..{}", self.width) | ||||
|         } | ||||
|         if y >= self.height { | ||||
|             panic!("cannot access pixel {x}-{y} because y is outside of bounds 0..{}", self.height) | ||||
|         } | ||||
|         assert!( | ||||
|             x < self.width, | ||||
|             "cannot access pixel {x}-{y} because x is outside of bounds 0..{}", | ||||
|             self.width | ||||
|         ); | ||||
|         assert!( | ||||
|             y < self.height, | ||||
|             "cannot access pixel {x}-{y} because y is outside of bounds 0..{}", | ||||
|             self.height | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Grid<bool> for PixelGrid { | ||||
|     /// Creates a new pixel grid with the specified dimensions.
 | ||||
|     /// Creates a new `PixelGrid` with the specified dimensions.
 | ||||
|     ///
 | ||||
|     /// # Arguments
 | ||||
|     ///
 | ||||
|     /// * `width`: size in pixels in x-direction
 | ||||
|     /// * `height`: size in pixels in y-direction
 | ||||
|     ///
 | ||||
|     /// returns: PixelGrid initialized to all pixels off
 | ||||
|     /// returns: `PixelGrid` initialized to all pixels off
 | ||||
|     ///
 | ||||
|     /// # Panics
 | ||||
|     ///
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vinzenz Schroeter
						Vinzenz Schroeter