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
				
			
		| 
						 | 
				
			
			@ -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