Maraiah/src/durandal/bin.rs

168 lines
3.7 KiB
Rust

//! Binary data conversion utilities.
use crate::durandal::err::*;
use std::{fmt,
num::NonZeroU16,
slice::SliceIndex};
pub fn c_data<I>(b: &[u8], i: I) -> ResultS<&<I as SliceIndex<[u8]>>::Output>
where I: SliceIndex<[u8]>
{
ok!(b.get(i), "not enough data")
}
pub trait BinUtil
{
/// Returns a byte from `self` at `i`.
fn c_byte(&self, i: usize) -> ResultS<u8>;
/// Returns a four-character-code identifier from `self` at `i`.
fn c_iden(&self, i: usize) -> ResultS<Ident>
{
ok!(self.o_iden(i), "not enough data")
}
/// Returns a big-endian `u32` from `self` at `i`.
fn c_u32b(&self, i: usize) -> ResultS<u32>
{
ok!(self.o_u32b(i), "not enough data")
}
/// Returns a big-endian `u16` from `self` at `i`.
fn c_u16b(&self, i: usize) -> ResultS<u16>
{
ok!(self.o_u16b(i), "not enough data")
}
/// Returns a big-endian `i32` from `self` at `i`.
fn c_i32b(&self, i: usize) -> ResultS<i32>
{
ok!(self.o_i32b(i), "not enough data")
}
/// Returns a big-endian `i16` from `self` at `i`.
fn c_i16b(&self, i: usize) -> ResultS<i16>
{
ok!(self.o_i16b(i), "not enough data")
}
/// Returns a four-character-code identifier from `self` at `i`.
fn o_iden(&self, i: usize) -> Option<Ident>;
/// Returns a big-endian `u32` from `self` at `i`.
fn o_u32b(&self, i: usize) -> Option<u32>;
/// Returns a big-endian `u16` from `self` at `i`.
fn o_u16b(&self, i: usize) -> Option<u16>;
/// Returns a big-endian `i32` from `self` at `i`.
fn o_i32b(&self, i: usize) -> Option<i32>
{
match self.o_u32b(i) {
Some(n) => Some(n as i32),
None => None,
}
}
/// Returns a big-endian `i16` from `self` at `i`.
fn o_i16b(&self, i: usize) -> Option<i16>
{
match self.o_u16b(i) {
Some(n) => Some(n as i16),
None => None,
}
}
}
impl BinUtil for [u8]
{
fn c_byte(&self, i: usize) -> ResultS<u8>
{
match self.get(i) {
Some(&v) => Ok(v),
None => Err(err_msg("not enough data")),
}
}
fn o_iden(&self, i: usize) -> Option<Ident>
{
if i + 3 < self.len() {
Some([self[i], self[i + 1], self[i + 2], self[i + 3]])
} else {
None
}
}
fn o_u32b(&self, i: usize) -> Option<u32>
{
if i + 3 < self.len() {
Some(u32::from_be_bytes([self[i],
self[i + 1],
self[i + 2],
self[i + 3]]))
} else {
None
}
}
fn o_u16b(&self, i: usize) -> Option<u16>
{
if i + 1 < self.len() {
Some(u16::from_be_bytes([self[i], self[i + 1]]))
} else {
None
}
}
}
impl ObjID
{
/// Creates an `ObjID` from a `u16`.
pub fn from_repr(n: u16) -> ObjID
{
if n == u16::max_value() {
ObjID(None)
} else {
ObjID(NonZeroU16::new(n + 1))
}
}
/// Returns the `u16` representation of an `ObjID`.
pub fn get_repr(&self) -> u16
{
match self.0 {
None => u16::max_value(),
Some(n) => n.get() - 1,
}
}
/// Returns the `Option` representation of an `ObjID`.
pub fn get(&self) -> Option<u16>
{
match self.0 {
None => None,
Some(n) => Some(n.get()),
}
}
}
impl fmt::Debug for ObjID
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
match self.0 {
None => write!(f, "ObjID(None)"),
Some(n) => write!(f, "ObjID({})", n.get()),
}
}
}
/// A four-character-code identifier.
pub type Ident = [u8; 4];
/// An object identified by a `u16` which may be `u16::max_value()` to
/// represent None.
pub struct ObjID(Option<NonZeroU16>);
// EOF