1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
//! Zigzag encoding is an alternative way of encoding negative numbers.
//! 
//! In zigzag encoding, the least-significant bit is used to represent the sign.
//! Counting up alternates between non-negative and negative numbers as the LSB
//! switches between `0` and `1`.
//! 
//! ## Example
//! ```
//! // to allow the use of the `Zigzag::zigzag` function
//! use varint_rs::zigzag::Zigzag;
//! 
//! // create an i32 set to `300`
//! let number: i32 = 300;
//! // encode the i32 into a u32
//! let encoded: u32 = number.zigzag();
//! // decode the u32 into an i32
//! let decoded: i32 = encoded.zigzag();
//! ```

/// The `Zigzag` trait enables zigzag encoding for a type.
/// 
/// This is pre-implemented on the primitive signed and unsigned integer types.
pub trait Zigzag<T> {
  fn zigzag(&self) -> T;
}

impl Zigzag<u8> for i8 {
  /// Encodes an i8 as a zigzagged u8.
  fn zigzag(&self) -> u8 {
    ((self << 1) ^ (self >> 7)) as u8
  }
}

impl Zigzag<i8> for u8 {
  /// Encodes a u8 as a zigzagged i8.
  fn zigzag(&self) -> i8 {
    ((self >> 1) as i8) ^ (-((self & 1) as i8))
  }
}

impl Zigzag<u16> for i16 {
  /// Encodes an i16 as a zigzagged u16.
  fn zigzag(&self) -> u16 {
    ((self << 1) ^ (self >> 15)) as u16
  }
}

impl Zigzag<i16> for u16 {
  /// Encodes a u16 as a zigzagged i16.
  fn zigzag(&self) -> i16 {
    ((self >> 1) as i16) ^ (-((self & 1) as i16))
  }
}

impl Zigzag<u32> for i32 {
  /// Encodes an i32 as a zigzagged u32.
  fn zigzag(&self) -> u32 {
    ((self << 1) ^ (self >> 31)) as u32
  }
}

impl Zigzag<i32> for u32 {
  /// Encodes a u32 as a zigzagged i32.
  fn zigzag(&self) -> i32 {
    ((self >> 1) as i32) ^ (-((self & 1) as i32))
  }
}

impl Zigzag<u64> for i64 {
  /// Encodes an i64 as a zigzagged u64.
  fn zigzag(&self) -> u64 {
    ((self << 1) ^ (self >> 63)) as u64
  }
}

impl Zigzag<i64> for u64 {
  /// Encodes a u64 as a zigzagged i64.
  fn zigzag(&self) -> i64 {
    ((self >> 1) as i64) ^ (-((self & 1) as i64))
  }
}

impl Zigzag<u128> for i128 {
  /// Encodes an i128 as a zigzagged u128.
  fn zigzag(&self) -> u128 {
    ((self << 1) ^ (self >> 127)) as u128
  }
}

impl Zigzag<i128> for u128 {
  /// Encodes a u128 as a zigzagged i128.
  fn zigzag(&self) -> i128 {
    ((self >> 1) as i128) ^ (-((self & 1) as i128))
  }
}

impl Zigzag<usize> for isize {
  /// Encodes an isize as a zigzagged usize.
  fn zigzag(&self) -> usize {
    ((self << 1) ^ (self >> std::mem::size_of::<usize>()-1)) as usize
  }
}

impl Zigzag<isize> for usize {
  /// Encodes a usize as a zigzagged isize.
  fn zigzag(&self) -> isize {
    ((self >> 1) as isize) ^ (-((self & 1) as isize))
  }
}