qubit-io 0.2.0

Small stream I/O trait utilities for Rust
Documentation
/*******************************************************************************
 *
 *    Copyright (c) 2026 Haixing Hu.
 *
 *    SPDX-License-Identifier: Apache-2.0
 *
 *    Licensed under the Apache License, Version 2.0.
 *
 ******************************************************************************/
use std::io::{
    Result,
    Write,
};

use crate::Leb128WriteExt;

/// Extension methods for writing ZigZag encoded signed integers.
///
/// ZigZag maps signed integers to unsigned integers so small negative values
/// still have short varint encodings. The mapped unsigned value is written with
/// unsigned LEB128. The ZigZag mapping follows the Protocol Buffers encoding
/// guide:
/// <https://protobuf.dev/programming-guides/encoding/#signed-integers>.
pub trait ZigZagWriteExt: Write {
    /// Writes a ZigZag encoded `i8`.
    ///
    /// # Parameters
    /// - `value`: Value to encode.
    ///
    /// # Errors
    /// Returns an I/O error from the underlying writer.
    fn write_zigzag_i8(&mut self, value: i8) -> Result<()>;

    /// Writes a ZigZag encoded `i16`.
    ///
    /// # Parameters
    /// - `value`: Value to encode.
    ///
    /// # Errors
    /// Returns an I/O error from the underlying writer.
    fn write_zigzag_i16(&mut self, value: i16) -> Result<()>;

    /// Writes a ZigZag encoded `i32`.
    ///
    /// # Parameters
    /// - `value`: Value to encode.
    ///
    /// # Errors
    /// Returns an I/O error from the underlying writer.
    fn write_zigzag_i32(&mut self, value: i32) -> Result<()>;

    /// Writes a ZigZag encoded `i64`.
    ///
    /// # Parameters
    /// - `value`: Value to encode.
    ///
    /// # Errors
    /// Returns an I/O error from the underlying writer.
    fn write_zigzag_i64(&mut self, value: i64) -> Result<()>;

    /// Writes a ZigZag encoded `i128`.
    ///
    /// # Parameters
    /// - `value`: Value to encode.
    ///
    /// # Errors
    /// Returns an I/O error from the underlying writer.
    fn write_zigzag_i128(&mut self, value: i128) -> Result<()>;

    /// Writes a ZigZag encoded `isize`.
    ///
    /// # Parameters
    /// - `value`: Value to encode.
    ///
    /// # Errors
    /// Returns an I/O error from the underlying writer.
    fn write_zigzag_isize(&mut self, value: isize) -> Result<()>;
}

impl<T> ZigZagWriteExt for T
where
    T: Write + ?Sized,
{
    #[inline]
    fn write_zigzag_i8(&mut self, value: i8) -> Result<()> {
        self.write_uleb_u8(encode_zigzag_i8(value))
    }

    #[inline]
    fn write_zigzag_i16(&mut self, value: i16) -> Result<()> {
        self.write_uleb_u16(encode_zigzag_i16(value))
    }

    #[inline]
    fn write_zigzag_i32(&mut self, value: i32) -> Result<()> {
        self.write_uleb_u32(encode_zigzag_i32(value))
    }

    #[inline]
    fn write_zigzag_i64(&mut self, value: i64) -> Result<()> {
        self.write_uleb_u64(encode_zigzag_i64(value))
    }

    #[inline]
    fn write_zigzag_i128(&mut self, value: i128) -> Result<()> {
        self.write_uleb_u128(encode_zigzag_i128(value))
    }

    #[inline]
    fn write_zigzag_isize(&mut self, value: isize) -> Result<()> {
        self.write_uleb_usize(encode_zigzag_isize(value))
    }
}

/// Encodes an `i8` with ZigZag mapping.
///
/// # Parameters
/// - `value`: Signed value to map.
///
/// # Returns
/// ZigZag mapped unsigned value.
fn encode_zigzag_i8(value: i8) -> u8 {
    ((value as u8) << 1) ^ ((value >> 7) as u8)
}

/// Encodes an `i16` with ZigZag mapping.
///
/// # Parameters
/// - `value`: Signed value to map.
///
/// # Returns
/// ZigZag mapped unsigned value.
fn encode_zigzag_i16(value: i16) -> u16 {
    ((value as u16) << 1) ^ ((value >> 15) as u16)
}

/// Encodes an `i32` with ZigZag mapping.
///
/// # Parameters
/// - `value`: Signed value to map.
///
/// # Returns
/// ZigZag mapped unsigned value.
fn encode_zigzag_i32(value: i32) -> u32 {
    ((value as u32) << 1) ^ ((value >> 31) as u32)
}

/// Encodes an `i64` with ZigZag mapping.
///
/// # Parameters
/// - `value`: Signed value to map.
///
/// # Returns
/// ZigZag mapped unsigned value.
fn encode_zigzag_i64(value: i64) -> u64 {
    ((value as u64) << 1) ^ ((value >> 63) as u64)
}

/// Encodes an `i128` with ZigZag mapping.
///
/// # Parameters
/// - `value`: Signed value to map.
///
/// # Returns
/// ZigZag mapped unsigned value.
fn encode_zigzag_i128(value: i128) -> u128 {
    ((value as u128) << 1) ^ ((value >> 127) as u128)
}

/// Encodes an `isize` with ZigZag mapping.
///
/// # Parameters
/// - `value`: Signed value to map.
///
/// # Returns
/// ZigZag mapped unsigned value.
fn encode_zigzag_isize(value: isize) -> usize {
    ((value as usize) << 1) ^ ((value >> (isize::BITS - 1)) as usize)
}