geometry: cut down on <> noise with associated types

This commit is contained in:
Victoria Fischer 2024-11-29 00:10:52 +01:00
parent 5488f85792
commit 2f9b99c2b0
5 changed files with 100 additions and 106 deletions

View File

@ -12,7 +12,7 @@ use std::sync::{Arc, Mutex};
#[derive(Debug)]
pub struct ShaderBinding {
shader: Option<Box<dyn Shader>>,
rect: Rectangle<u8, Virtual>,
rect: Rectangle<Virtual>,
opacity: u8
}
@ -45,7 +45,7 @@ impl Default for BoundSurface<Rc<RefCell<ShaderBinding>>>{
}
impl Surface for BoundSurface<Rc<RefCell<ShaderBinding>>> {
fn rect(&self) -> Rectangle<u8, Virtual> {
fn rect(&self) -> Rectangle<Virtual> {
self.binding.borrow().rect.clone()
}
@ -63,7 +63,7 @@ impl Surface for BoundSurface<Rc<RefCell<ShaderBinding>>> {
self.binding.borrow_mut().shader = None;
}
fn set_rect(&mut self, rect: &Rectangle<u8, Virtual>) {
fn set_rect(&mut self, rect: &Rectangle<Virtual>) {
self.binding.borrow_mut().rect = rect.clone();
}
@ -159,7 +159,7 @@ impl<S: Surface + Default> SurfacePool<S> {
}
impl<S: Surface + Default> Surfaces<S> for SurfacePool<S> {
fn new_surface(&mut self, area: &Rectangle<u8, Virtual>) -> Result<S, io::Error> {
fn new_surface(&mut self, area: &Rectangle<Virtual>) -> Result<S, io::Error> {
let mut surface = S::default();
surface.set_rect(area);
self.surfaces.push(surface.clone());

View File

@ -1,19 +1,26 @@
use std::fmt::{Debug, Formatter};
use std::marker::PhantomData;
use std::ops::{Mul, Sub, Add};
use num::{One, pow, integer::Roots};
use std::cmp::{min, max};
pub trait CoordinateSpace {}
#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
pub struct Coordinates<T: CoordLimits<Data = T>, S: CoordinateSpace> {
pub x: T,
pub y: T,
space: PhantomData<S>,
pub trait CoordinateOp: PartialOrd + PartialEq + Sub + Clone + Mul + Copy + One + Add + Eq + Debug where
Self: Sub<Output=Self> {
const MIN: Self;
const MAX: Self;
fn distance(x1: Self, y1: Self, x2: Self, y2: Self) -> Self;
}
impl<T: CoordLimits<Data = T> + Debug, S: CoordinateSpace> Debug for Coordinates<T, S> {
pub trait CoordinateSpace {
type Data: CoordinateOp;
}
#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
pub struct Coordinates<S: CoordinateSpace> {
pub x: S::Data,
pub y: S::Data,
}
impl<S: CoordinateSpace> Debug for Coordinates<S> where S::Data: Debug {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("@")
.field(&self.x)
@ -22,16 +29,7 @@ impl<T: CoordLimits<Data = T> + Debug, S: CoordinateSpace> Debug for Coordinates
}
}
pub trait CoordLimits: PartialOrd + PartialEq + Sub + Clone + Mul + Copy + One + Add {
type Data: CoordLimits;
const MIN: Self::Data;
const MAX: Self::Data;
fn distance(x1: Self, y1: Self, x2: Self, y2: Self) -> Self;
}
impl CoordLimits for u8 {
type Data = u8;
impl CoordinateOp for u8 {
const MIN: u8 = 0;
const MAX: u8 = 255;
@ -41,8 +39,7 @@ impl CoordLimits for u8 {
}
}
impl CoordLimits for u16 {
type Data = u16;
impl CoordinateOp for u16 {
const MIN: u16 = u16::MIN;
const MAX: u16 = u16::MAX;
@ -51,8 +48,7 @@ impl CoordLimits for u16 {
}
}
impl CoordLimits for usize {
type Data = usize;
impl CoordinateOp for usize {
const MIN: usize = usize::MIN;
const MAX: usize = usize::MAX;
@ -61,57 +57,51 @@ impl CoordLimits for usize {
}
}
impl<T: CoordLimits<Data = T>, S: CoordinateSpace> Coordinates<T, S> {
pub const fn new(x: T, y: T) -> Self {
impl<S: CoordinateSpace> Coordinates<S> {
pub const fn new(x: S::Data, y: S::Data) -> Self {
Self {
x,
y,
space: PhantomData,
y
}
}
fn top_left() -> Self {
Self::new(T::MIN, T::MIN)
Self::new(S::Data::MIN, S::Data::MIN)
}
fn top_right() -> Self {
Self::new(T::MAX, T::MIN)
Self::new(S::Data::MAX, S::Data::MIN)
}
fn bottom_left() -> Self {
Self::new(T::MIN, T::MAX)
Self::new(S::Data::MIN, S::Data::MAX)
}
fn bottom_right() -> Self {
Self::new(T::MAX, T::MAX)
Self::new(S::Data::MAX, S::Data::MAX)
}
pub fn distance_to(&self, other: &Self) -> T {
T::distance(self.x, other.x, self.y, other.y)
pub fn distance_to(&self, other: &Self) -> S::Data {
S::Data::distance(self.x, other.x, self.y, other.y)
}
}
#[derive(PartialEq, Debug, Copy, Clone)]
pub struct Virtual {}
impl CoordinateSpace for Virtual {}
#[derive(PartialEq, Debug, Copy, Clone)]
pub struct Coord8<S: CoordinateSpace> {
x: u8,
y: u8,
space: PhantomData<S>
impl CoordinateSpace for Virtual {
type Data = u8;
}
pub type VirtualCoordinates = Coordinates<u8, Virtual>;
pub type VirtualCoordinates = Coordinates<Virtual>;
#[derive(PartialEq, Eq, Copy, Clone, Debug, PartialOrd)]
pub struct Rectangle<CoordData: CoordLimits<Data = CoordData>, Space: CoordinateSpace> {
pub top_left: Coordinates<CoordData, Space>,
pub bottom_right: Coordinates<CoordData, Space>
pub struct Rectangle<Space: CoordinateSpace> {
pub top_left: Coordinates<Space>,
pub bottom_right: Coordinates<Space>
}
impl<CoordData: CoordLimits<Data = CoordData> + Sub<Output=CoordData>, Space: CoordinateSpace> Rectangle<CoordData, Space> {
pub fn new(top_left: Coordinates<CoordData, Space>, bottom_right: Coordinates<CoordData, Space>) -> Self {
impl<Space: CoordinateSpace> Rectangle<Space> {
pub fn new(top_left: Coordinates<Space>, bottom_right: Coordinates<Space>) -> Self {
debug_assert!(top_left.x <= bottom_right.x);
debug_assert!(top_left.y <= bottom_right.y);
Self {
@ -122,32 +112,32 @@ impl<CoordData: CoordLimits<Data = CoordData> + Sub<Output=CoordData>, Space: Co
pub fn everything() -> Self {
Self {
top_left: Coordinates::<CoordData, Space>::top_left(),
bottom_right: Coordinates::<CoordData, Space>::bottom_right()
top_left: Coordinates::<Space>::top_left(),
bottom_right: Coordinates::<Space>::bottom_right()
}
}
pub fn width(&self) -> CoordData {
pub fn width(&self) -> Space::Data {
self.bottom_right.x.clone() - self.top_left.x.clone()
}
pub fn height(&self) -> CoordData {
pub fn height(&self) -> Space::Data {
self.bottom_right.y.clone() - self.top_left.y.clone()
}
pub const fn left(&self) -> CoordData {
pub const fn left(&self) -> Space::Data {
self.top_left.x
}
pub const fn top(&self) -> CoordData {
pub const fn top(&self) -> Space::Data {
self.top_left.y
}
pub const fn right (&self) -> CoordData {
pub const fn right (&self) -> Space::Data {
self.bottom_right.x
}
pub const fn bottom(&self) -> CoordData {
pub const fn bottom(&self) -> Space::Data {
self.bottom_right.y
}
}

View File

@ -7,20 +7,22 @@ use std::fmt::{Formatter, Debug};
use ansi_term::Color;
use rgb::Rgb;
pub trait CoordinateView<CoordData: CoordLimits<Data = CoordData>, Space: CoordinateSpace>: Debug {
fn next(&mut self) -> Option<(Coordinates<u8, Virtual>, Coordinates<CoordData, Space>)>;
pub trait CoordinateView: Debug {
type Space: CoordinateSpace;
fn next(&mut self) -> Option<(Coordinates<Virtual>, Coordinates<Self::Space>)>;
}
pub trait PixelMapping<CoordData: CoordLimits<Data = CoordData>, Space: CoordinateSpace> {
fn select(&self, rect: &Rectangle<u8, Virtual>) -> impl CoordinateView<CoordData, Space>;
fn to_idx(&self, coords: &Coordinates<CoordData, Space>) -> usize;
pub trait PixelMapping {
type Space: CoordinateSpace;
fn select(&self, rect: &Rectangle<Virtual>) -> impl CoordinateView<Space = Self::Space>;
fn to_idx(&self, coords: &Coordinates<Self::Space>) -> usize;
}
pub trait DisplayDump<T: PixelMapping<CoordData, Space>, CoordData: CoordLimits<Data = CoordData>, Space: CoordinateSpace> {
pub trait DisplayDump<T: PixelMapping> {
fn dump(&self, map: &T);
}
impl<const PIXEL_NUM: usize> DisplayDump<LinearPixelMapping, usize, LinearSpace> for [Rgb<u8>; PIXEL_NUM] {
impl<const PIXEL_NUM: usize> DisplayDump<LinearPixelMapping> for [Rgb<u8>; PIXEL_NUM] {
fn dump(&self, _map: &LinearPixelMapping) {
for ref pixel in self {
print!("{}", Color::RGB(pixel.r, pixel.g, pixel.b).paint(""));
@ -29,7 +31,7 @@ impl<const PIXEL_NUM: usize> DisplayDump<LinearPixelMapping, usize, LinearSpace>
}
}
impl<const PIXEL_NUM: usize> DisplayDump<StrideMapping, u8, StrideSpace> for [Rgb<u8>; PIXEL_NUM] {
impl<const PIXEL_NUM: usize> DisplayDump<StrideMapping> for [Rgb<u8>; PIXEL_NUM] {
fn dump(&self, map: &StrideMapping) {
for y in 0..map.stride_count {
let stride = &map.strides[y];
@ -55,15 +57,19 @@ impl<const PIXEL_NUM: usize> DisplayDump<StrideMapping, u8, StrideSpace> for [Rg
#[derive(Debug)]
struct LinearCoordView {
rect: Rectangle<u8, Virtual>,
rect: Rectangle<Virtual>,
idx: usize,
}
pub struct LinearSpace {}
impl CoordinateSpace for LinearSpace {}
pub type LinearCoords = Coordinates<usize, LinearSpace>;
impl CoordinateSpace for LinearSpace {
type Data = usize;
}
impl CoordinateView<usize, LinearSpace> for LinearCoordView {
pub type LinearCoords = Coordinates<LinearSpace>;
impl CoordinateView for LinearCoordView {
type Space = LinearSpace;
fn next(&mut self) -> Option<(VirtualCoordinates, LinearCoords)> {
if self.idx as u8 == self.rect.bottom_right.x {
None
@ -88,15 +94,16 @@ impl LinearPixelMapping {
}
}
impl PixelMapping<usize, LinearSpace> for LinearPixelMapping {
fn select(&self, rect: &Rectangle<u8, Virtual>) -> impl CoordinateView<usize, LinearSpace> {
impl PixelMapping for LinearPixelMapping {
type Space = LinearSpace;
fn select(&self, rect: &Rectangle<Virtual>) -> impl CoordinateView<Space = Self::Space> {
LinearCoordView {
rect: rect.clone(),
idx: 0,
}
}
fn to_idx(&self, coords: &Coordinates<usize, LinearSpace>) -> usize {
fn to_idx(&self, coords: &Coordinates<LinearSpace>) -> usize {
coords.x
}
}
@ -125,7 +132,7 @@ pub struct StrideMapping<const STRIDE_NUM: usize = 24> {
pub strides: [Stride; STRIDE_NUM],
pub stride_count: usize,
pub pixel_count: usize,
pub size: Rectangle<usize, StrideSpace>
pub size: Rectangle<StrideSpace>
}
impl<const STRIDE_NUM: usize> StrideMapping<STRIDE_NUM> {
@ -183,7 +190,7 @@ impl<const STRIDE_NUM: usize> StrideMapping<STRIDE_NUM> {
let mut strides = [Stride::default(); STRIDE_NUM];
let stride_count = stride_json.len();
let mut physical_idx = 0;
let mut size: Option<Rectangle<usize, StrideSpace>> = None;//Rectangle::new(Coordinates::new(usize::MAX, usize::MAX), Coordinates::new(0, 0));
let mut size: Option<Rectangle<StrideSpace>> = None;//Rectangle::new(Coordinates::new(usize::MAX, usize::MAX), Coordinates::new(0, 0));
for stride_idx in 0..stride_count {
let json_data = stride_json[stride_idx];
let x = json_data.0;
@ -230,24 +237,27 @@ impl<const STRIDE_NUM: usize> StrideMapping<STRIDE_NUM> {
}
}
impl PixelMapping<u8, StrideSpace> for StrideMapping {
fn select(&self, rect: &Rectangle<u8, Virtual>) -> impl CoordinateView<u8, StrideSpace> {
impl PixelMapping for StrideMapping {
type Space = StrideSpace;
fn select(&self, rect: &Rectangle<Virtual>) -> impl CoordinateView<Space = StrideSpace> {
StrideView::new(self, rect)
}
fn to_idx(&self, coords: &Coordinates<u8, StrideSpace>) -> usize {
fn to_idx(&self, coords: &Coordinates<StrideSpace>) -> usize {
self.strides[coords.x as usize].pixel_idx_for_offset(coords.y)
}
}
#[derive(Debug, Clone, Copy)]
pub struct StrideSpace {}
impl CoordinateSpace for StrideSpace {}
pub type StrideCoords = Coordinates<u8, StrideSpace>;
impl CoordinateSpace for StrideSpace {
type Data = u8;
}
pub type StrideCoords = Coordinates<StrideSpace>;
struct StrideView<'a> {
map: &'a StrideMapping,
range: Rectangle<u8, StrideSpace>,
range: Rectangle<StrideSpace>,
cur: StrideCoords,
step_size: VirtualCoordinates
}
@ -262,9 +272,9 @@ impl<'a> Debug for StrideView<'a> {
}
impl<'a> StrideView<'a> {
fn new(map: &'a StrideMapping, rect: &Rectangle<u8, Virtual>) -> Self {
fn new(map: &'a StrideMapping, rect: &Rectangle<Virtual>) -> Self {
// Zero-index shape of the pixel picking area
let range: Rectangle<u8, StrideSpace> = Rectangle::new(
let range: Rectangle<StrideSpace> = Rectangle::new(
Coordinates::new(
scale8(map.size.width() as u8, rect.top_left.x) + map.size.left() as u8,
scale8(map.size.height() as u8, rect.top_left.y) + map.size.top() as u8
@ -300,7 +310,8 @@ impl<'a> StrideView<'a> {
}
}
impl<'a> CoordinateView<u8, StrideSpace> for StrideView<'a> {
impl<'a> CoordinateView for StrideView<'a> {
type Space = StrideSpace;
fn next(&mut self) -> Option<(VirtualCoordinates, StrideCoords)> {
// Keep scanning until we reach the far right of the range
while self.cur.x <= self.range.bottom_right.x {

View File

@ -17,13 +17,15 @@ use std::ops::IndexMut;
pub trait HardwarePixel: Send + Sync + Rgb8Blend + Copy + AsMilliwatts + Default + From<Rgb<u8>> + Fract8Ops {}
impl<T> HardwarePixel for T where T: Send + Sync + Rgb8Blend + Copy + AsMilliwatts + Default + From<Rgb<u8>> + Fract8Ops {}
pub trait Pixbuf<T: HardwarePixel>: AsMilliwatts + IndexMut<usize, Output=T> {
pub trait Pixbuf: AsMilliwatts + IndexMut<usize, Output=Self::Pixel> {
type Pixel: HardwarePixel;
fn new() -> Self;
fn blank(&mut self);
fn iter_with_brightness(&self, brightness: u8) -> impl Iterator<Item = T> + Send;
fn iter_with_brightness(&self, brightness: u8) -> impl Iterator<Item = Self::Pixel> + Send;
}
impl<T: HardwarePixel, const PIXEL_NUM: usize> Pixbuf<T> for [T; PIXEL_NUM] {
impl<T: HardwarePixel, const PIXEL_NUM: usize> Pixbuf for [T; PIXEL_NUM] {
type Pixel = T;
fn new() -> Self {
[T::default(); PIXEL_NUM]
}
@ -37,7 +39,7 @@ impl<T: HardwarePixel, const PIXEL_NUM: usize> Pixbuf<T> for [T; PIXEL_NUM] {
}
}
struct SmartLedDisplay<T: FastWrite, S: Surface, P: Pixbuf<T::Color>> {
struct SmartLedDisplay<T: FastWrite, S: Surface, P: Pixbuf<Pixel = T::Color>> {
surfaces : Option<SurfacePool<S>>,
pixmap: StrideMapping,
target: T,
@ -46,7 +48,7 @@ struct SmartLedDisplay<T: FastWrite, S: Surface, P: Pixbuf<T::Color>> {
frame: usize
}
impl<T: FastWrite, S: Surface, P: Pixbuf<T::Color>> Debug for SmartLedDisplay<T, S, P> {
impl<T: FastWrite, S: Surface, P: Pixbuf<Pixel = T::Color>> Debug for SmartLedDisplay<T, S, P> {
fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
f.debug_struct("SmartLedDisplay")
.field("total_mw", &self.pixbuf.as_milliwatts())
@ -55,7 +57,7 @@ impl<T: FastWrite, S: Surface, P: Pixbuf<T::Color>> Debug for SmartLedDisplay<T,
}
}
impl<T: FastWrite, S: Surface, P: Pixbuf<T::Color>> SmartLedDisplay<T, S, P> {
impl<T: FastWrite, S: Surface, P: Pixbuf<Pixel = T::Color>> SmartLedDisplay<T, S, P> {
fn new(target: T, max_mw: u32, pixmap: StrideMapping, pixbuf: P) -> Self {
SmartLedDisplay {
pixbuf,
@ -68,20 +70,11 @@ impl<T: FastWrite, S: Surface, P: Pixbuf<T::Color>> SmartLedDisplay<T, S, P> {
}
}
impl<T, S, P> AsMilliwatts for SmartLedDisplay<T, S, P> where
T: FastWrite,
S: Surface,
P: Pixbuf<T::Color> {
fn as_milliwatts(&self) -> u32 {
self.pixbuf.as_milliwatts()
}
}
impl<T, S, P> Surfaces<S> for SmartLedDisplay<T, S, P> where
T: FastWrite,
S: Surface,
P: Pixbuf<T::Color> {
fn new_surface(&mut self, area: &Rectangle<u8, Virtual>) -> Result<S, io::Error> {
P: Pixbuf<Pixel = T::Color> {
fn new_surface(&mut self, area: &Rectangle<Virtual>) -> Result<S, io::Error> {
if let Some(ref mut s) = self.surfaces {
s.new_surface(area)
} else {
@ -93,7 +86,7 @@ P: Pixbuf<T::Color> {
impl<T, S, P> Display<S> for SmartLedDisplay<T, S, P> where
T: FastWrite,
S: Surface,
P: Pixbuf<T::Color> {
P: Pixbuf<Pixel = T::Color> {
fn render_frame(&mut self) {
let surfaces = self.surfaces.take().unwrap();
for surface in surfaces.iter() {
@ -126,7 +119,7 @@ trait FastWrite {
impl<T, S, P> Framed for SmartLedDisplay<T, S, P> where
T: FastWrite,
S: Surface,
P: Pixbuf<T::Color> {
P: Pixbuf<Pixel = T::Color> {
fn start_frame(&mut self) {
self.pixbuf.blank();

View File

@ -13,7 +13,7 @@ pub trait Shader: Send + Debug {
}
pub trait Surfaces<T: Surface>: Debug {
fn new_surface(&mut self, area: &Rectangle<u8, Virtual>) -> Result<T, io::Error>;
fn new_surface(&mut self, area: &Rectangle<Virtual>) -> Result<T, io::Error>;
}
pub trait Surface: Default + Clone + Debug {
@ -21,8 +21,8 @@ pub trait Surface: Default + Clone + Debug {
fn set_shader(&mut self, shader: Box<dyn Shader>);
fn clear_shader(&mut self);
fn rect(&self) -> Rectangle<u8, Virtual>;
fn set_rect(&mut self, rect: &Rectangle<u8, Virtual>);
fn rect(&self) -> Rectangle<Virtual>;
fn set_rect(&mut self, rect: &Rectangle<Virtual>);
fn opacity(&self) -> u8;
fn set_opacity(&mut self, opacity: u8);
}