doc everything

png-branch
an 2019-03-04 21:14:09 -05:00
parent 6e4c7512e8
commit 1d6aa0c14e
9 changed files with 365 additions and 103 deletions

View File

@ -22,16 +22,16 @@ macro_rules! _durandal_read_impl {
// little endian
(LE $b:ident $nam:ident u16 $n:expr) => {
_durandal_read_impl!($b u16::from_le_bytes $nam 2 $n);
_durandal_read_impl!($b u16::from_le_bytes, $nam 2 $n);
};
(LE $b:ident $nam:ident i16 $n:expr) => {
_durandal_read_impl!($b i16::from_le_bytes $nam 2 $n);
_durandal_read_impl!($b i16::from_le_bytes, $nam 2 $n);
};
(LE $b:ident $nam:ident u32 $n:expr) => {
_durandal_read_impl!($b u32::from_le_bytes $nam 4 $n);
_durandal_read_impl!($b u32::from_le_bytes, $nam 4 $n);
};
(LE $b:ident $nam:ident i32 $n:expr) => {
_durandal_read_impl!($b i32::from_le_bytes $nam 4 $n);
_durandal_read_impl!($b i32::from_le_bytes, $nam 4 $n);
};
// either endianness
@ -87,6 +87,8 @@ macro_rules! _durandal_read_impl {
/// Reads structured data from a byte slice.
///
/// # Syntax
///
/// First start by specifying the endianness, size and source using the syntax
/// `endian, size in source =>` where:
///
@ -126,14 +128,41 @@ macro_rules! _durandal_read_impl {
/// - `place` is either an integer literal which must be representable as
/// `usize`, or a range, which may only be used when `type` is a function
/// name.
#[macro_export]
///
/// # Panics
///
/// This macro will not panic unless any index expression used exceeds `size`.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate maraiah;
/// # use maraiah::durandal::err::*;
/// # fn main() -> ResultS<()>
/// # {
/// let buffer = &[4, 0, 2, 0, 0, 0, 6];
///
/// read_data! {
/// 7, LE in buffer =>
/// four = u16[0];
/// two = u32[2];
/// six = u8 [6];
/// }
///
/// assert_eq!(four, 4_u16);
/// assert_eq!(two, 2_u32);
/// assert_eq!(six, 6_u8);
/// # Ok(())
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! read_data {
(
$sz:expr , $ty:ident in $b:ident =>
$( $nam:ident = $t:ident [ $n:expr ] $( $ex:ident )* ; )*
) => {
if $b.len() < $sz {
bail!("not enough data");
return Err(err_msg("not enough data"));
}
$($crate::_durandal_read_impl!($ty $b $nam $($ex)* $t $n);)*
@ -141,32 +170,91 @@ macro_rules! read_data {
}
/// Casts a `u32` to a `usize`. For future compatibility.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::bin::usize_from_u32;
///
/// assert_eq!(usize_from_u32(777u32), 777usize);
/// ```
#[inline]
pub const fn usize_from_u32(n: u32) -> usize {n as usize}
/// Creates an `Ident` from a slice.
///
/// `b` must be at least 4 bytes, or a panic will occur.
pub fn ident(b: &[u8]) -> Ident {Ident([b[0], b[1], b[2], b[3]])}
/// # Panics
///
/// A panic will occur if `b.len()` is less than 4.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::bin::{Ident, ident};
///
/// assert_eq!(ident(b"POLY"), Ident([b'P', b'O', b'L', b'Y']));
/// ```
#[inline]
pub const fn ident(b: &[u8]) -> Ident {Ident([b[0], b[1], b[2], b[3]])}
/// Applies `u32::from_be_bytes` to a slice.
///
/// `b` must be at least 4 bytes, or a panic will occur.
/// # Panics
///
/// A panic will occur if `b.len()` is less than 4.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::bin::u32b;
///
/// assert_eq!(u32b(&[0x00, 0x0B, 0xDE, 0x31]), 777_777u32);
/// ```
pub fn u32b(b: &[u8]) -> u32 {u32::from_be_bytes([b[0], b[1], b[2], b[3]])}
/// Applies `u16::from_be_bytes` to a slice.
///
/// `b` must be at least 2 bytes, or a panic will occur.
/// # Panics
///
/// A panic will occur if `b.len()` is less than 2.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::bin::u16b;
///
/// assert_eq!(u16b(&[0x1E, 0x61]), 7_777u16);
/// ```
pub fn u16b(b: &[u8]) -> u16 {u16::from_be_bytes([b[0], b[1]])}
/// Applies `i32::from_be_bytes` to a slice.
///
/// `b` must be at least 4 bytes, or a panic will occur.
/// # Panics
///
/// A panic will occur if `b.len()` is less than 4.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::bin::i32b;
///
/// assert_eq!(i32b(&[0xFF, 0x89, 0x52, 0x0F]), -7_777_777i32);
/// ```
pub fn i32b(b: &[u8]) -> i32 {i32::from_be_bytes([b[0], b[1], b[2], b[3]])}
/// Applies `i16::from_be_bytes` to a slice.
///
/// `b` must be at least 2 bytes, or a panic will occur.
/// # Panics
///
/// A panic will occur if `b.len()` is less than 2.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::bin::i16b;
///
/// assert_eq!(i16b(&[0xE1, 0x9F]), -7_777i16);
/// ```
pub fn i16b(b: &[u8]) -> i16 {i16::from_be_bytes([b[0], b[1]])}
/// Applies a read function over a slice.
@ -175,6 +263,26 @@ pub fn i16b(b: &[u8]) -> i16 {i16::from_be_bytes([b[0], b[1]])}
/// iteration will pass a slice of `b` to `read` for it to read from, and then
/// increments the slice index by the second return value. When there is no
/// data left in `b`, the function returns.
///
/// # Panics
///
/// A panic will occur if the `read` function returns a disjoint index or
/// otherwise panics (by an out of bounds index to `b` or otherwise.)
///
/// # Errors
///
/// Execution will return the result of `read` if `read` returns an error.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::{err::*, bin::{rd_array, u16b}};
///
/// fn read_a_u16(b: &[u8]) -> ResultS<(u16, usize)> {Ok((u16b(b), 2))}
///
/// let inp = &[0x1E, 0x61, 0x03, 0x09];
/// assert_eq!(rd_array(inp, read_a_u16).unwrap(), vec![7_777u16, 777u16]);
/// ```
pub fn rd_array<T, F>(b: &[u8], read: F) -> ResultS<Vec<T>>
where T: Sized,
F: Fn(&[u8]) -> ResultS<(T, usize)>
@ -198,6 +306,15 @@ pub fn rd_array<T, F>(b: &[u8], read: F) -> ResultS<Vec<T>>
/// reads a 32-bit big endian offset from `b`, and then passes a slice of `b`
/// to `read` starting at that offset. When all offsets have been read, the
/// function returns.
///
/// # Panics
///
/// A panic will occur if the `read` function returns a disjoint index or
/// otherwise panics (by an out of bounds index to `b` or otherwise.)
///
/// # Errors
///
/// Execution will return the result of `read` if `read` returns an error.
pub fn rd_ofstable<T, F>(b: &[u8],
mut p: usize,
num: usize,
@ -225,6 +342,14 @@ pub fn rd_ofstable<T, F>(b: &[u8],
impl OptU16
{
/// Creates an `OptU16` representing `None`.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::bin::OptU16;
///
/// assert_eq!(OptU16::none(), OptU16::from_repr(u16::max_value()));
/// ```
pub const fn none() -> Self {OptU16(None)}
/// Creates an `OptU16` from a `u16`.
@ -238,6 +363,18 @@ impl OptU16
}
/// Returns the `u16` representation.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::bin::OptU16;
///
/// let u16max = u16::max_value();
///
/// assert_eq!(OptU16::from_repr(500u16).get_repr(), 500u16);
/// assert_eq!(OptU16::from_repr(u16max).get_repr(), u16max);
/// assert_eq!(OptU16::from_repr(0u16).get_repr(), 0u16);
/// ```
pub fn get_repr(&self) -> u16
{
match self.0 {
@ -247,6 +384,16 @@ impl OptU16
}
/// Returns the `Option` representation.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::bin::OptU16;
///
/// assert_eq!(OptU16::from_repr(500u16).get(), Some(500u16));
/// assert_eq!(OptU16::from_repr(u16::max_value()).get(), None);
/// assert_eq!(OptU16::from_repr(0u16).get(), Some(0u16));
/// ```
pub fn get(&self) -> Option<u16>
{
match self.0 {
@ -276,12 +423,22 @@ impl fmt::Debug for Ident
}
/// A four-character-code identifier.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::bin::Ident;
///
/// assert_eq!(Ident(*b"POLY").0, *b"POLY");
/// ```
#[derive(Clone, Copy, Default, PartialEq)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Ident(pub [u8; 4]);
/// An object identified by a `u16` which may be `u16::max_value()` to
/// represent a nulled value.
#[derive(Default, serde::Serialize, serde::Deserialize)]
#[derive(Clone, Copy, Default, PartialEq)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct OptU16(Option<NonZeroU16>);
// EOF

View File

@ -8,6 +8,29 @@
///
/// This will generate an `enum E` as well as a function `E::from_repr` which
/// will return `Result<E, ReprError>`.
///
/// # Examples
///
/// ```
/// use maraiah::{c_enum, durandal::err::ReprError};
///
/// c_enum! {
/// #[derive(Debug, PartialEq)]
/// enum MyEnum: u16
/// {
/// 0 => Zero,
/// 1 => One,
/// 2 => Two,
/// }
/// }
///
/// assert_eq!(MyEnum::from_repr(0), Ok(MyEnum::Zero));
/// assert_eq!(MyEnum::from_repr(1), Ok(MyEnum::One));
/// assert_eq!(MyEnum::from_repr(2), Ok(MyEnum::Two));
/// assert_eq!(MyEnum::from_repr(3), Err(ReprError::new(3)));
/// assert_eq!(MyEnum::from_repr(4), Err(ReprError::new(4)));
/// assert_eq!(MyEnum::from_repr(5), Err(ReprError::new(5)));
/// ```
#[macro_export]
macro_rules! c_enum
{

View File

@ -19,6 +19,14 @@ fn crc_init() -> [u32; 256]
}
/// Creates a CRC-32 of all bytes in `b` with the starting sum `s`.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::crc::crc32;
///
/// assert_eq!(crc32(b"Lorem ipsum dolor sit amet", !0), 0x5F29_D461);
/// ```
pub fn crc32(b: &[u8], s: u32) -> u32
{
let t = crc_init();
@ -26,10 +34,4 @@ pub fn crc32(b: &[u8], s: u32) -> u32
.fold(s, |a, &o| a >> 8 ^ t[usize::from(a as u8 ^ o)])
}
#[test]
fn crc32_lorem_ipsum()
{
assert_eq!(crc32(b"Lorem ipsum dolor sit amet", !0), 0x5F29_D461);
}
// EOF

View File

@ -29,10 +29,29 @@ macro_rules! bail {
}
/// Returns an `Error` with a static string.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::err::err_msg;
///
/// assert_eq!(format!("{}", err_msg("oh no not things")), "oh no not things");
/// ```
pub fn err_msg(msg: &'static str) -> Error {Error::from(ErrMsg(msg))}
impl ReprError
{
/// Creates a new `ReprError`.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::err::ReprError;
///
/// let err = ReprError::new(7);
///
/// assert_eq!(format!("{}", err), "representation error (got 7)");
/// ```
#[inline]
pub fn new<T>(n: T) -> Self where T: Into<i64> {Self(n.into())}
}

View File

@ -63,8 +63,11 @@ macro_rules! fixed_ref_op_assign {
macro_rules! define_fixed_types {
(
$($(#[$outer:meta])*
struct $t:ident ($ti:ident, $bytes:expr) : $tu:ident, $frac_bits:expr;)*
$(
$(#[$outer:meta])*
struct $t:ident ( $ti:ident, $bytes:expr ) :
$tu:ident, $frac_bits:expr; $test:ident
)*
) => {$(
$(#[$outer])*
#[derive(Copy, Clone, Default, PartialEq, PartialOrd, serde::Serialize)]
@ -230,6 +233,43 @@ macro_rules! define_fixed_types {
}
}
#[cfg(test)]
mod $test {
use super::$t;
#[test]
fn basic_ops()
{
let one = $t::one();
let two = 2 << $t::frac_bits();
let twelve = 12 << $t::frac_bits();
assert_eq!(($t::from(1) + $t::from(1)).to_bits(), two);
assert_eq!(($t::from(2) - $t::from(1)).to_bits(), one);
assert_eq!(($t::from(6) * $t::from(2)).to_bits(), twelve);
assert_eq!(($t::from(6) * 2) .to_bits(), twelve);
}
#[test]
fn fractions()
{
let three_pt_5 = 3 << $t::frac_bits() | $t::one() / 2;
let one_pt_2 = 1 << $t::frac_bits() | $t::one() / 5;
let two_pt_4 = one_pt_2 * 2;
assert_eq!(($t::from(7) / $t::from(2)) .to_bits(), three_pt_5);
assert_eq!(($t::from(7) / 2) .to_bits(), three_pt_5);
assert_eq!(($t::from_bits(one_pt_2) * 2).to_bits(), two_pt_4);
}
#[test]
fn printing()
{
assert_eq!(format!("{}", $t::from(6)), "6.0");
assert_eq!(format!("{:2.3}", $t::from(7) / 2), " 3.500");
}
}
impl From<$ti> for $t
{
#[inline]
@ -388,42 +428,17 @@ define_fixed_types! {
///
/// The format of this type is `0.9s`, but because of the implementation,
/// the real format is `7.9s`.
struct Angle(i16, 2) : u16, 9;
struct Angle(i16, 2) : u16, 9; angle_tests
/// A fixed point type representing a world unit.
///
/// The format of this type is `5.10s`. This has caused eternal suffering.
struct Unit(i16, 2) : u16, 10;
struct Unit(i16, 2) : u16, 10; unit_tests
/// A generic fixed point type.
///
/// The format of this type is `15.16s`.
struct Fixed(i32, 4) : u32, 16;
}
#[test]
fn fixed_basic_ops()
{
let one = Fixed::one();
let two = 2 << Fixed::frac_bits();
let twelve = 12 << Fixed::frac_bits();
assert_eq!((Fixed::from(1) + Fixed::from(1)).to_bits(), two);
assert_eq!((Fixed::from(2) - Fixed::from(1)).to_bits(), one);
assert_eq!((Fixed::from(6) * Fixed::from(2)).to_bits(), twelve);
assert_eq!((Fixed::from(6) * 2) .to_bits(), twelve);
}
#[test]
fn fixed_fractions()
{
let three_pt_5 = 3 << Fixed::frac_bits() | Fixed::one() / 2;
let one_pt_2 = 1 << Fixed::frac_bits() | Fixed::one() / 5;
let two_pt_4 = 157_286;
assert_eq!((Fixed::from(7) / Fixed::from(2)).to_bits(), three_pt_5);
assert_eq!((Fixed::from(7) / 2) .to_bits(), three_pt_5);
assert_eq!((Fixed::from_bits(one_pt_2) * 2) .to_bits(), two_pt_4);
struct Fixed(i32, 4) : u32, 16; fixed_tests
}
#[test]
@ -431,13 +446,4 @@ fn fixed_fractions()
#[allow(unused_must_use)]
fn fixed_overflow() {Fixed::from(i16::max_value() as i32) + Fixed::from(1);}
#[test]
fn fixed_printing()
{
assert_eq!(format!("{}", Fixed::from(6)), "6.0");
assert_eq!(format!("{}", Fixed::from(7) / 2), "3.5");
assert_eq!(format!("{:7.7}", Fixed::from_bits(0xDEAD_BEEF)),
" -8531.7458343");
}
// EOF

View File

@ -4,17 +4,31 @@ use crate::durandal::err::*;
use std::io;
/// Creates a RGB8 color from a R5G5B5 format color.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::image::{Color8, r5g5b5_to_rgb8};
///
/// assert_eq!(r5g5b5_to_rgb8(0x2345), Color8::new(64, 208, 40));
/// ```
pub fn r5g5b5_to_rgb8(rgb: u16) -> Color8
{
let r = rgb >> 10 & 0x1f;
let g = rgb >> 5 & 0x1f;
let b = rgb & 0x1f;
Color8::new((r << 3 | r >> 2) as u8,
(g << 3 | g >> 2) as u8,
(b << 3 | b >> 2) as u8)
let r = (rgb >> 10) as u8 & 0x1f;
let g = (rgb >> 5) as u8 & 0x1f;
let b = rgb as u8 & 0x1f;
Color8::new(r << 3, g << 3, b << 3)
}
/// Creates a RGB16 color from a R5G5B5 format color.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::image::{Color16, r5g5b5_to_rgb16};
///
/// assert_eq!(r5g5b5_to_rgb16(0x2345), Color16::new(0x4000, 0xD000, 0x2800));
/// ```
pub fn r5g5b5_to_rgb16(rgb: u16) -> Color16
{
let r = rgb >> 10 & 0x1f;
@ -24,14 +38,27 @@ pub fn r5g5b5_to_rgb16(rgb: u16) -> Color16
}
/// Creates a RGB16 color from a RGB8 format color.
pub fn rgb8_to_rgb16(r: u8, g: u8, b: u8) -> Color16
///
/// # Examples
///
/// ```
/// use maraiah::durandal::image;
///
/// let inpl = image::r5g5b5_to_rgb8(0x2345);
/// let inph = image::r5g5b5_to_rgb16(0x2345);
///
/// assert_eq!(inph, image::rgb8_to_rgb16(inpl));
/// ```
pub fn rgb8_to_rgb16(cr: Color8) -> Color16
{
Color16::new(u16::from(r) << 8,
u16::from(g) << 8,
u16::from(b) << 8)
Color16::new(cr.r(), cr.g(), cr.b())
}
/// Writes a PPM file from an image.
///
/// # Errors
///
/// Errors if `out` cannot be written to.
pub fn write_ppm(out: &mut impl io::Write, im: &impl Image) -> ResultS<()>
{
write!(out, "P3\n{} {}\n{}\n", im.w(), im.h(), u16::max_value())?;
@ -49,6 +76,10 @@ pub fn write_ppm(out: &mut impl io::Write, im: &impl Image) -> ResultS<()>
}
/// Writes a TGA file from an image.
///
/// # Errors
///
/// Errors if `out` cannot be written to.
pub fn write_tga(out: &mut impl io::Write, im: &impl Image) -> ResultS<()>
{
// id len, color map type, image type

View File

@ -4,6 +4,10 @@ use crate::durandal::err::*;
use std::io;
/// Writes a WAVE file from a sound.
///
/// # Errors
///
/// Errors if `out` cannot be written to.
pub fn write_wav(out: &mut impl io::Write, snd: &impl Sound) -> ResultS<()>
{
let smp_rate = u32::from(snd.rate());

View File

@ -2,30 +2,15 @@
use crate::durandal::err::*;
/// Dumps a slice of memory as text to stderr.
pub fn dump_mem(b: &[u8])
{
let mut p = 0;
for &c in b {
if p + 3 > 79 {
eprintln!("");
p = 0;
}
if c.is_ascii_graphic() {
eprint!(" {} ", c as char);
} else {
eprint!("{:02X} ", c);
}
p += 3;
}
eprintln!("");
}
/// Formats a binary size string for any given number.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::text::to_binsize;
///
/// assert_eq!(to_binsize(5000), "5kB".to_string());
/// ```
pub fn to_binsize(n: u64) -> String
{
const NAMES: [&str; 4] = ["kB", "MB", "GB", "TB"];
@ -70,6 +55,16 @@ pub fn fuck_string(s: &[u8]) -> Vec<u8>
}
/// Reads a Pascal-style byte string with bounds checking.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::text::pascal_str;
///
/// assert_eq!(pascal_str(b"\x0bhello world"), b"hello world"[..].into());
/// assert_eq!(pascal_str(b"\x0chello world"), None);
/// assert_eq!(pascal_str(&[]), None);
/// ```
pub fn pascal_str(b: &[u8]) -> Option<&[u8]>
{
let s = usize::from(*b.get(0)?);
@ -77,6 +72,15 @@ pub fn pascal_str(b: &[u8]) -> Option<&[u8]>
}
/// Converts input from Mac Roman to a Unicode string.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::text::mac_roman_conv;
///
/// assert_eq!(mac_roman_conv(b"p\x8cth"), "påth");
/// assert_eq!(mac_roman_conv(b"I\xd5ve"), "Ive");
/// ```
pub fn mac_roman_conv(s: &[u8]) -> String
{
let mut v = String::with_capacity(s.len());
@ -93,6 +97,14 @@ pub fn mac_roman_conv(s: &[u8]) -> String
}
/// Converts a C-style string from Mac Roman to Unicode.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::text::mac_roman_cstr;
///
/// assert_eq!(mac_roman_cstr(b"I\xd5ve awaken\0ed").unwrap(), "Ive awaken");
/// ```
pub fn mac_roman_cstr(s: &[u8]) -> ResultS<String>
{
if let Some(s) = s.split(|&n| n == 0).nth(0) {
@ -143,17 +155,5 @@ fn to_binsize_integrals()
assert_eq!(to_binsize(1000 * 1000 * 1000 * 1000 * 7), "7TB");
}
#[test]
fn mac_roman_conv_basic_marathon_stuff()
{
assert_eq!(mac_roman_conv(b"p\x8cth"), "påth");
assert_eq!(mac_roman_conv(b"I\xd5ve"), "Ive");
}
#[test]
fn mac_roman_cstr_tests()
{
assert_eq!(mac_roman_cstr(b"I\xd5ve awaken\0ed").unwrap(), "Ive awaken");
}
// EOF

View File

@ -2,28 +2,48 @@
use crate::durandal::image::Color;
/// An image possibly cached into a native driver's memory.
pub trait CacheImage
{
/// The width of the image.
fn w(&self) -> Coord;
/// The width of the image.
fn h(&self) -> Coord;
}
/// A native vector drawing area.
pub trait DrawArea
{
/// The native `CacheImage` type for this `DrawArea`.
type NativeImage: CacheImage;
/// The width of the entire area.
fn w(&self) -> Coord;
/// The height of the entire area.
fn h(&self) -> Coord;
/// Fills the entire screen with `cr`.
fn clear(&self, cr: impl Color);
/// Draws a rectangle `rect` of color `cr`.
fn rect(&self, rect: Rect, cr: impl Color);
/// Draws the Unicode `text` at `pos` stroked with color `cr`.
fn text(&self, pos: Point, text: &str, cr: impl Color);
/// Draws `im` at `pos`, starting from the top left column.
fn image(&self, pos: Point, im: &Self::NativeImage);
}
/// A type capable of representing any coordinate on any axis.
pub type Coord = i32;
/// A 2-dimensional point.
pub type Point = (Coord, Coord);
/// A 2-dimensional rectangle.
#[derive(Copy, Clone, Debug)]
pub struct Rect
{