structom 0.2.5

efficient data format for all needs
Documentation
use num_bigint::BigInt;

use crate::encoding::encode_u8_arr;

#[inline]
pub fn encode_u8(data: &mut Vec<u8>, value: u8) {
	data.push(value);
}
#[inline]
pub fn encode_u16(data: &mut Vec<u8>, value: u16) {
	data.extend_from_slice(&value.to_le_bytes());
}
#[inline]
pub fn encode_u32(data: &mut Vec<u8>, value: u32) {
	data.extend_from_slice(&value.to_le_bytes());
}
#[inline]
pub fn encode_u64(data: &mut Vec<u8>, value: u64) {
	data.extend_from_slice(&value.to_le_bytes());
}

#[inline]
pub fn encode_i8(data: &mut Vec<u8>, value: i8) {
	data.push(value.to_le_bytes()[0]);
}
#[inline]
pub fn encode_i16(data: &mut Vec<u8>, value: i16) {
	data.extend_from_slice(&value.to_le_bytes());
}
#[inline]
pub fn encode_i32(data: &mut Vec<u8>, value: i32) {
	data.extend_from_slice(&value.to_le_bytes());
}
#[inline]
pub fn encode_i64(data: &mut Vec<u8>, value: i64) {
	data.extend_from_slice(&value.to_le_bytes());
}

#[inline]
pub fn decode_u8(data: &[u8], ind: &mut usize) -> Option<u8> {
	let value = data.get(*ind)?;
	*ind += 1;
	Some(*value)
}
#[inline]
pub fn decode_u16(data: &[u8], ind: &mut usize) -> Option<u16> {
	let value = u16::from_le_bytes(data.get(*ind..*ind + 2)?.try_into().ok()?);
	*ind += 2;
	Some(value)
}
#[inline]
pub fn decode_u32(data: &[u8], ind: &mut usize) -> Option<u32> {
	let value = u32::from_le_bytes(data.get(*ind..*ind + 4)?.try_into().ok()?);
	*ind += 4;
	Some(value)
}
#[inline]
pub fn decode_u64(data: &[u8], ind: &mut usize) -> Option<u64> {
	let value = u64::from_le_bytes(data.get(*ind..*ind + 8)?.try_into().ok()?);
	*ind += 8;
	Some(value)
}

#[inline]
pub fn decode_i8(data: &[u8], ind: &mut usize) -> Option<i8> {
	let value = i8::from_le_bytes([*data.get(*ind)?]);
	*ind += 1;
	Some(value)
}
#[inline]
pub fn decode_i16(data: &[u8], ind: &mut usize) -> Option<i16> {
	let value = i16::from_le_bytes(data.get(*ind..*ind + 2)?.try_into().ok()?);
	*ind += 2;
	Some(value)
}
#[inline]
pub fn decode_i32(data: &[u8], ind: &mut usize) -> Option<i32> {
	let value = i32::from_le_bytes(data.get(*ind..*ind + 4)?.try_into().ok()?);
	*ind += 4;
	Some(value)
}
#[inline]
pub fn decode_i64(data: &[u8], ind: &mut usize) -> Option<i64> {
	let value = i64::from_le_bytes(data.get(*ind..*ind + 8)?.try_into().ok()?);
	*ind += 8;
	Some(value)
}

#[inline]
pub fn encode_f32(data: &mut Vec<u8>, value: f32) {
	data.extend_from_slice(&value.to_le_bytes());
}
#[inline]
pub fn encode_f64(data: &mut Vec<u8>, value: f64) {
	data.extend_from_slice(&value.to_le_bytes());
}

#[inline]
pub fn decode_f32(data: &[u8], ind: &mut usize) -> Option<f32> {
	let value = f32::from_le_bytes(data.get(*ind..*ind + 4)?.try_into().ok()?);
	*ind += 4;
	Some(value)
}
#[inline]
pub fn decode_f64(data: &[u8], ind: &mut usize) -> Option<f64> {
	let value = f64::from_le_bytes(data.get(*ind..*ind + 8)?.try_into().ok()?);
	*ind += 8;
	Some(value)
}

/// encode a LEB128 vuint
pub fn encode_vuint(data: &mut Vec<u8>, mut value: u64) {
	let mut buf = [0u8; 10];
	let mut there_input = true;
	let mut ind = 0;

	while there_input {
		// extract least significant 7 bits
		let byte = value as u8 & 0b0111_1111;
		// shift to next section
		value >>= 7;
		// add continuation bit
		buf[ind] = if value == 0 { byte } else { byte | 0b1000_0000 };

		there_input = value != 0;
		ind += 1;
	}

	data.extend_from_slice(&buf[0..ind]);
}
/// encode a LEB128, vuint into a pre allocated space, expanding it if needed
pub fn encode_vuint_pre_aloc(
	data: &mut Vec<u8>, mut value: u64, start_ind: usize, pre_aloc: usize,
) {
	let mut buf = [0u8; 10];
	let mut size = 0;
	let mut there_input = true;

	while there_input {
		// extract least significant 7 bits
		let byte = value as u8 & 0b0111_1111;
		// shift to next section
		value >>= 7;
		// add continuation bit
		buf[size] = if value == 0 { byte } else { byte | 0b1000_0000 };

		there_input = value != 0;
		size += 1;
	}

	// if preallocated space is small, expand it
	if size > pre_aloc {
		let len = data.len();
		data.resize(len + size - pre_aloc, 0);
		data.copy_within(start_ind + pre_aloc..len, start_ind + size);
	}

	// set continuation bits in all pre allocated area, even if not used, making it padding
	if size < pre_aloc {
		for i in size - 1..pre_aloc - 1 {
			buf[i] |= 0b1000_0000
		}
		size = pre_aloc;
	}

	data[start_ind..start_ind + size].copy_from_slice(&buf[..size]);
}
pub fn encode_vint(data: &mut Vec<u8>, mut value: i64) {
	let mut buf = [0u8; 10];
	let mut ind = 0;
	let mut there_input = true;
	while there_input {
		// extract least significant 7 bits
		let mut byte = (value & 0b0111_1111) as u8;
		// shift to next section
		value >>= 7;
		// ensure at least 1 sign bit is encoded
		let sign_bit = byte & 0b0100_0000;
		if (value == 0 && sign_bit == 0) || (value == -1 && sign_bit != 0) {
			there_input = false;
		} else {
			// add continuation bit
			byte |= 0b1000_0000;
		}
		buf[ind] = byte;
		ind += 1;
	}

	data.extend_from_slice(&buf[0..ind]);
}

pub fn decode_vuint(data: &[u8], ind: &mut usize) -> Option<u64> {
	let mut there_input = true;
	let mut res = 0u64;
	let mut shift = 0;

	while there_input {
		let byte = *data.get(*ind)? as u64;
		// add the least significant 7 bits to the next section of the result
		res |= (byte & 0b0111_1111) << shift;
		// next section
		shift += 7;
		*ind += 1;
		// if the continuation bit is set, continue
		there_input = byte & 0b1000_0000 != 0;
	}

	Some(res)
}
pub fn decode_vint(data: &[u8], ind: &mut usize) -> Option<i64> {
	let mut there_input = true;
	let mut res = 0i64;
	let mut shift = 0u64;
	let mut byte = 0i64;

	while there_input {
		// add the least significant 7 bits to the next section of the result
		byte = *data.get(*ind)? as i64;
		res |= (byte & 0b0111_1111) << shift;
		// next section
		shift += 7;
		*ind += 1;
		// if the continuation bit is set, continue
		there_input = byte & 0b1000_0000 != 0;
	}

	// sign extend if needed
	if (shift < 64) && (byte & 0b0100_0000 != 0) {
		res |= !0 << shift;
	}

	Some(res)
}

#[inline]
pub fn encode_bint(data: &mut Vec<u8>, value: &BigInt) {
	encode_u8_arr(data, &value.to_signed_bytes_le());
}
#[inline]
pub fn decode_bint(data: &[u8], ind: &mut usize) -> Option<BigInt> {
	let len = decode_vuint(data, ind)? as usize;
	let value = BigInt::from_signed_bytes_le(data.get(*ind..*ind + len)?);
	*ind += len;
	Some(value)
}