diff --git a/source/durandal/bin.rs b/source/durandal/bin.rs index a243090..7a2e4d2 100644 --- a/source/durandal/bin.rs +++ b/source/durandal/bin.rs @@ -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(b: &[u8], read: F) -> ResultS> where T: Sized, F: Fn(&[u8]) -> ResultS<(T, usize)> @@ -198,6 +306,15 @@ pub fn rd_array(b: &[u8], read: F) -> ResultS> /// 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(b: &[u8], mut p: usize, num: usize, @@ -225,6 +342,14 @@ pub fn rd_ofstable(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 { 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); // EOF diff --git a/source/durandal/cenum.rs b/source/durandal/cenum.rs index 001c2da..f3c7ed2 100644 --- a/source/durandal/cenum.rs +++ b/source/durandal/cenum.rs @@ -8,6 +8,29 @@ /// /// This will generate an `enum E` as well as a function `E::from_repr` which /// will return `Result`. +/// +/// # 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 { diff --git a/source/durandal/crc.rs b/source/durandal/crc.rs index 1b6c4ce..01d7d66 100644 --- a/source/durandal/crc.rs +++ b/source/durandal/crc.rs @@ -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 diff --git a/source/durandal/err.rs b/source/durandal/err.rs index 5159b16..da9241b 100644 --- a/source/durandal/err.rs +++ b/source/durandal/err.rs @@ -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(n: T) -> Self where T: Into {Self(n.into())} } diff --git a/source/durandal/fixed.rs b/source/durandal/fixed.rs index b70a258..85eb964 100644 --- a/source/durandal/fixed.rs +++ b/source/durandal/fixed.rs @@ -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 diff --git a/source/durandal/image.rs b/source/durandal/image.rs index 6d80f3f..f782da0 100644 --- a/source/durandal/image.rs +++ b/source/durandal/image.rs @@ -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 diff --git a/source/durandal/sound.rs b/source/durandal/sound.rs index f0ffd19..7de0b23 100644 --- a/source/durandal/sound.rs +++ b/source/durandal/sound.rs @@ -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()); diff --git a/source/durandal/text.rs b/source/durandal/text.rs index 57c224e..82553a0 100644 --- a/source/durandal/text.rs +++ b/source/durandal/text.rs @@ -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 } /// 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"), "I’ve"); +/// ``` 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(), "I’ve awaken"); +/// ``` pub fn mac_roman_cstr(s: &[u8]) -> ResultS { 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"), "I’ve"); -} - -#[test] -fn mac_roman_cstr_tests() -{ - assert_eq!(mac_roman_cstr(b"I\xd5ve awaken\0ed").unwrap(), "I’ve awaken"); -} // EOF diff --git a/source/rozinante/draw.rs b/source/rozinante/draw.rs index 71d01a6..6e6cf7e 100644 --- a/source/rozinante/draw.rs +++ b/source/rozinante/draw.rs @@ -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 {