Kestrel 3 місяців тому
батько
коміт
34851859dc

+ 13 - 6
Cargo.toml

@@ -1,20 +1,27 @@
 [package]
+# important information
 name = "kahlo"
-version = "0.1.0"
 edition = "2021"
+version = "0.0.1"
 
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+# package metadata
+authors = ["Kestrel <kestrel@flying-kestrel.ca"]
+repository = "https://git.flying-kestrel.ca/kestrel/kahlo-rs"
+description = "Optimized software rendering library."
+keywords = ["raster", "render", "paint", "graphics"]
+license = "BSD or MIT"
+
+# features specification for docs.rs
+[package.metadata.docs.rs]
+features = []
+all-features = true
 
 [dependencies]
 euclid = { version = "0.22" }
-enum-map = { version = "2.7" }
 lazy_static = { version = "1.4" }
-bitvec = { version = "1" }
-tuples = "1.15"
 
 [dev-dependencies]
 image = { version = "0.25.1", default-features = false, features = ["png", "jpeg"] }
-# bencher = { version = "0.1.5" }
 criterion = { version = "0.5" }
 rand = { version = "0.8" }
 hex = "0.4.0"

+ 12 - 2
src/bitmap.rs

@@ -176,11 +176,21 @@ impl<Format: PixelFormatSpec> Bitmap<Format> {
     }
 
     pub fn as_ref(&self) -> BitmapRef<Format> {
-        BitmapRef::new_with_stride(&self.data.data, self.data.width, self.data.height, self.data.stride)
+        BitmapRef::new_with_stride(
+            &self.data.data,
+            self.data.width,
+            self.data.height,
+            self.data.stride,
+        )
     }
 
     pub fn as_mut(&mut self) -> BitmapMut<Format> {
-        BitmapMut::new_with_stride(&mut self.data.data, self.data.width, self.data.height, self.data.stride)
+        BitmapMut::new_with_stride(
+            &mut self.data.data,
+            self.data.width,
+            self.data.height,
+            self.data.stride,
+        )
     }
 }
 

+ 4 - 8
src/colour.rs

@@ -24,20 +24,16 @@ impl Colour {
     pub fn hex_rgb(hex: &str) -> Option<Self> {
         // acceptable lengths: 6, 7
         let toparse = match (hex.len(), hex.chars().next()) {
-            (6, _) => {
-                hex
-            },
-            (7, Some('#')) => {
-                &hex[1..]
-            },
-            _ => return None
+            (6, _) => hex,
+            (7, Some('#')) => &hex[1..],
+            _ => return None,
         };
 
         Some(Self([
             u8::from_str_radix(&toparse[0..2], 16).ok()?,
             u8::from_str_radix(&toparse[2..4], 16).ok()?,
             u8::from_str_radix(&toparse[4..6], 16).ok()?,
-            255
+            255,
         ]))
     }
 

+ 2 - 2
src/op.rs

@@ -19,13 +19,13 @@ mod rectangle;
 #[cfg(test)]
 mod generate;
 
-pub trait UnaryOpSpec : GenericUnary<Self::Params<'static>> {
+pub trait UnaryOpSpec: GenericUnary<Self::Params<'static>> {
     type Params<'l>;
 
     fn build<'l>() -> UnaryDispatch<Self::Params<'l>>;
 }
 
-pub trait BinaryOpSpec : GenericBinary<Self::Params<'static>> {
+pub trait BinaryOpSpec: GenericBinary<Self::Params<'static>> {
     type Params<'l>;
 
     fn build<'l>() -> BinaryDispatch<Self::Params<'l>>;

+ 1 - 0
src/op/benchmark.rs

@@ -0,0 +1 @@
+

+ 17 - 7
src/op/copy_from.rs

@@ -1,7 +1,7 @@
 use crate::{
     bitmap::{BitmapData, BitmapDataMut},
     colour::Colour,
-    formats::{PixelFormatSpec, Bgr32, Rgba32, A8, Bgr24, Rgb24, Rgb32, Abgr32},
+    formats::{Abgr32, Bgr24, Bgr32, PixelFormatSpec, Rgb24, Rgb32, Rgba32, A8},
     math::{clip_to, PixelBox, PixelPoint},
 };
 
@@ -10,7 +10,7 @@ use super::{dispatch::BinaryDispatch, BinaryOpSpec, GenericBinary};
 pub struct CopyFromOp;
 
 #[cfg(test)]
-const _ : () = {
+const _: () = {
     use super::generate;
     impl generate::BinaryInputSpec for CopyFromOp {
         fn gen<'l>() -> impl generate::ValueGeneratorList<'l, OutputTuple = Self::Params<'l>> {
@@ -36,7 +36,11 @@ impl BinaryOpSpec for CopyFromOp {
 }
 
 /// read rgba32 and write bgr32
-fn copy_bgr32_rgba32(write_data: &mut dyn BitmapDataMut, read_data: &dyn BitmapData, params: &(PixelBox, PixelPoint)) {
+fn copy_bgr32_rgba32(
+    write_data: &mut dyn BitmapDataMut,
+    read_data: &dyn BitmapData,
+    params: &(PixelBox, PixelPoint),
+) {
     let read_box = params.0;
     let write_box = PixelBox::from_origin_and_size(params.1, read_box.size());
     let Some((read_box, write_box)) = clip_to(
@@ -69,12 +73,16 @@ fn copy_bgr32_rgba32(write_data: &mut dyn BitmapDataMut, read_data: &dyn BitmapD
         do_copy(
             &mut write_data[(y_offset_w + write_box.min.x as usize * Bgr32::PIXEL_WIDTH)..],
             &read_data[(y_offset_r + read_box.min.x as usize * Rgba32::PIXEL_WIDTH)..],
-            read_box.width() as usize
+            read_box.width() as usize,
         );
     }
 }
 
-fn copy_same_fmt<const WIDTH: usize>(write_data: &mut dyn BitmapDataMut, read_data: &dyn BitmapData, params: &(PixelBox, PixelPoint)) {
+fn copy_same_fmt<const WIDTH: usize>(
+    write_data: &mut dyn BitmapDataMut,
+    read_data: &dyn BitmapData,
+    params: &(PixelBox, PixelPoint),
+) {
     let read_box = params.0;
     let write_box = PixelBox::from_origin_and_size(params.1, read_box.size());
     let Some((read_box, write_box)) = clip_to(
@@ -97,8 +105,10 @@ fn copy_same_fmt<const WIDTH: usize>(write_data: &mut dyn BitmapDataMut, read_da
     let line_width = read_box.width() as usize * WIDTH;
 
     for y in 0..read_box.height() {
-        let write_slice = &mut write_data[(y + write_box.min.y) as usize * write_stride + write_line_offset..];
-        let read_slice = &read_data[(y + read_box.min.y) as usize * read_stride + read_line_offset..];
+        let write_slice =
+            &mut write_data[(y + write_box.min.y) as usize * write_stride + write_line_offset..];
+        let read_slice =
+            &read_data[(y + read_box.min.y) as usize * read_stride + read_line_offset..];
         (&mut write_slice[..line_width]).copy_from_slice(&read_slice[..line_width]);
     }
 }

+ 2 - 1
src/op/dispatch.rs

@@ -71,7 +71,8 @@ impl<Params> BinaryDispatch<Params> {
         if is_x86_feature_detected!("avx") {
             self.op_array[WriteFormat::FORMAT_ENUM as usize][ReadFormat::FORMAT_ENUM as usize] =
                 avx_imp;
-            self.changed[WriteFormat::FORMAT_ENUM as usize][ReadFormat::FORMAT_ENUM as usize] = true;
+            self.changed[WriteFormat::FORMAT_ENUM as usize][ReadFormat::FORMAT_ENUM as usize] =
+                true;
             self
         } else {
             self

+ 1 - 1
src/op/fill.rs

@@ -9,7 +9,7 @@ use super::{GenericUnary, UnaryDispatch, UnaryOpSpec};
 pub struct FillOp;
 
 #[cfg(test)]
-const _ : () = {
+const _: () = {
     use super::generate;
     impl generate::UnaryInputSpec for FillOp {
         fn gen<'l>() -> impl generate::ValueGeneratorList<'l, OutputTuple = Self::Params<'l>> {

+ 2 - 2
src/op/fill_region.rs

@@ -13,11 +13,11 @@ use super::{
 pub struct FillRegionOp;
 
 #[cfg(test)]
-const _ : () = {
+const _: () = {
     use super::generate;
     impl generate::UnaryInputSpec for FillRegionOp {
         fn gen<'l>() -> impl generate::ValueGeneratorList<'l, OutputTuple = Self::Params<'l>> {
-            (generate::dst_area, generate::random_colour,)
+            (generate::dst_area, generate::random_colour)
         }
     }
 };

+ 17 - 10
src/op/fill_region_masked.rs

@@ -12,25 +12,32 @@ use super::{
 
 pub struct FillRegionMaskedOp;
 
-type OpParams<'l> = (&'l dyn BitmapAccess<A8>, PixelBox, PixelPoint, Colour, BlendMode);
+type OpParams<'l> = (
+    &'l dyn BitmapAccess<A8>,
+    PixelBox,
+    PixelPoint,
+    Colour,
+    BlendMode,
+);
 
 #[cfg(test)]
-const _ : () = {
+const _: () = {
     use super::generate;
     impl generate::UnaryInputSpec for FillRegionMaskedOp {
         fn gen<'l>() -> impl generate::ValueGeneratorList<'l, OutputTuple = Self::Params<'l>> {
-            (generate::alphamap, generate::alphamap_area, generate::dst_point, generate::random_colour,generate::constant(BlendMode::Simple))
+            (
+                generate::alphamap,
+                generate::alphamap_area,
+                generate::dst_point,
+                generate::random_colour,
+                generate::constant(BlendMode::Simple),
+            )
         }
     }
 };
 
-
-impl<'l> GenericUnary<OpParams<'l>> for FillRegionMaskedOp
-{
-    fn perform<Format: PixelFormatSpec>(
-        write_data: &mut dyn BitmapDataMut,
-        params: &OpParams<'l>,
-    ) {
+impl<'l> GenericUnary<OpParams<'l>> for FillRegionMaskedOp {
+    fn perform<Format: PixelFormatSpec>(write_data: &mut dyn BitmapDataMut, params: &OpParams<'l>) {
         let (read_alphamap, read_box, dst, colour, blend) = params;
 
         let Some((write_box, read_box)) = clip_to(

+ 74 - 35
src/op/fuzz.rs

@@ -1,12 +1,12 @@
+use crate::bitmap::{BitmapAccess, BitmapMutAccess};
 use crate::formats::{self, PixelFormatSpec};
-use crate::bitmap::{BitmapAccess,BitmapMutAccess};
 
 use super::copy_from::CopyFromOp;
 use super::fill::FillOp;
 use super::fill_region::FillRegionOp;
 use super::fill_region_masked::FillRegionMaskedOp;
-use super::{GenericUnary,GenericBinary,UnaryOpSpec,BinaryOpSpec};
-use super::generate::{UnaryInputSpec,BinaryInputSpec,ValueGeneratorList, self};
+use super::generate::{self, BinaryInputSpec, UnaryInputSpec, ValueGeneratorList};
+use super::{BinaryOpSpec, GenericBinary, GenericUnary, UnaryOpSpec};
 
 fn test_unary_format<UIS: UnaryInputSpec, Format: PixelFormatSpec>(n: usize) {
     let gen = UIS::gen();
@@ -15,22 +15,27 @@ fn test_unary_format<UIS: UnaryInputSpec, Format: PixelFormatSpec>(n: usize) {
     let op = UIS::build();
     if op.is_generic::<Format>() {
         // println!("Skipping generic implementation {}", Format::NAME);
-        return
+        return;
     } else {
         println!("Testing specific implementation {}", Format::NAME);
     }
 
     for _ in 0..n {
-        let mut specific_img = generate::dst_image_generator::<Format>(&mut ctx).expect("could not generate image");
-        let params = gen.generate(&mut ctx).expect("could not generate parameters");
+        let mut specific_img =
+            generate::dst_image_generator::<Format>(&mut ctx).expect("could not generate image");
+        let params = gen
+            .generate(&mut ctx)
+            .expect("could not generate parameters");
         let mut generic_img = specific_img.clone();
 
         op.select::<Format>()(specific_img.data_mut(), &params);
-        <UIS as GenericUnary<UIS::Params::<'static>>>::perform::<Format>(generic_img.data_mut(), &params);
+        <UIS as GenericUnary<UIS::Params<'static>>>::perform::<Format>(
+            generic_img.data_mut(),
+            &params,
+        );
 
         assert_eq!(specific_img, generic_img);
     }
-
 }
 
 fn test_unary<UIS: UnaryInputSpec>(n: usize) {
@@ -43,58 +48,92 @@ fn test_unary<UIS: UnaryInputSpec>(n: usize) {
     test_unary_format::<UIS, formats::Rgba32>(n);
 }
 
-fn test_binary_format<BIS: BinaryInputSpec, DstFormat: PixelFormatSpec, SrcFormat: PixelFormatSpec>(n: usize) {
+fn test_binary_format<
+    BIS: BinaryInputSpec,
+    DstFormat: PixelFormatSpec,
+    SrcFormat: PixelFormatSpec,
+>(
+    n: usize,
+) {
     let gen = BIS::gen();
     let mut ctx = generate::Context::default();
 
     let op = BIS::build();
     if op.is_generic::<DstFormat, SrcFormat>() {
-        println!("Skipping generic implementation ({},{})", DstFormat::NAME, SrcFormat::NAME);
-        return
+        println!(
+            "Skipping generic implementation ({},{})",
+            DstFormat::NAME,
+            SrcFormat::NAME
+        );
+        return;
     } else {
-        println!("Testing specific implementation ({},{})", DstFormat::NAME, SrcFormat::NAME);
+        println!(
+            "Testing specific implementation ({},{})",
+            DstFormat::NAME,
+            SrcFormat::NAME
+        );
     }
 
     for _ in 0..n {
-        let dst_img = generate::dst_image_generator::<DstFormat>(&mut ctx).expect("could not generate image");
-        let src_img = generate::src_image_generator::<SrcFormat>(&mut ctx).expect("could not generate image");
+        let dst_img =
+            generate::dst_image_generator::<DstFormat>(&mut ctx).expect("could not generate image");
+        let src_img =
+            generate::src_image_generator::<SrcFormat>(&mut ctx).expect("could not generate image");
         let mut specific_dst_img = dst_img.clone();
         let mut generic_dst_img = dst_img.clone();
 
-        let params = gen.generate(&mut ctx).expect("could not generate parameters");
+        let params = gen
+            .generate(&mut ctx)
+            .expect("could not generate parameters");
 
         op.select::<DstFormat, SrcFormat>()(specific_dst_img.data_mut(), src_img.data(), &params);
-        <BIS as GenericBinary<BIS::Params::<'static>>>::perform::<DstFormat, SrcFormat>(generic_dst_img.data_mut(), src_img.data(), &params);
+        <BIS as GenericBinary<BIS::Params<'static>>>::perform::<DstFormat, SrcFormat>(
+            generic_dst_img.data_mut(),
+            src_img.data(),
+            &params,
+        );
 
         if specific_dst_img != generic_dst_img {
             let mut path = std::path::PathBuf::new();
             path.push(env!("CARGO_MANIFEST_DIR"));
             path.push("test_failure");
             println!("path: {:?}", path.as_path().to_str());
-            std::fs::write(path, format!(
-                concat!(
-                    "dst: {dst_img:?}\n",
-                    "src: {src_img:?}\n",
-                    "dst data: ({dst_fmt}) {dst_data}\n",
-                    "src data: ({src_fmt}) {src_data}\n",
-                    "generic output: {generic_data}\n",
-                    "specific output: {specific_data}\n",
-                ),
-                dst_img = dst_img,
-                src_img = src_img,
-                dst_fmt = DstFormat::NAME,
-                src_fmt = SrcFormat::NAME,
-                dst_data = hex::encode(dst_img.data().data()),
-                src_data = hex::encode(src_img.data().data()),
-                generic_data = hex::encode(generic_dst_img.data().data()),
-                specific_data = hex::encode(specific_dst_img.data().data())).as_str()).unwrap();
+            std::fs::write(
+                path,
+                format!(
+                    concat!(
+                        "dst: {dst_img:?}\n",
+                        "src: {src_img:?}\n",
+                        "dst data: ({dst_fmt}) {dst_data}\n",
+                        "src data: ({src_fmt}) {src_data}\n",
+                        "generic output: {generic_data}\n",
+                        "specific output: {specific_data}\n",
+                    ),
+                    dst_img = dst_img,
+                    src_img = src_img,
+                    dst_fmt = DstFormat::NAME,
+                    src_fmt = SrcFormat::NAME,
+                    dst_data = hex::encode(dst_img.data().data()),
+                    src_data = hex::encode(src_img.data().data()),
+                    generic_data = hex::encode(generic_dst_img.data().data()),
+                    specific_data = hex::encode(specific_dst_img.data().data())
+                )
+                .as_str(),
+            )
+            .unwrap();
             println!("image mismatch");
             println!("dst parameters: {:?}", dst_img);
             println!("src parameters: {:?}", src_img);
             println!("dst data: {}", hex::encode(dst_img.data().data()));
             println!("src data: {}", hex::encode(src_img.data().data()));
-            println!("specific output: {}", hex::encode(specific_dst_img.data().data()));
-            println!("generic output: {}", hex::encode(generic_dst_img.data().data()));
+            println!(
+                "specific output: {}",
+                hex::encode(specific_dst_img.data().data())
+            );
+            println!(
+                "generic output: {}",
+                hex::encode(generic_dst_img.data().data())
+            );
         }
 
         assert_eq!(specific_dst_img, generic_dst_img);

+ 41 - 15
src/op/generate.rs

@@ -12,7 +12,10 @@ pub struct Context {
 
 impl Context {
     pub fn insert<CVT: ContextValueTag>(&mut self, value: CVT::Value) {
-        self.values.insert(std::any::TypeId::of::<CVT>(), Box::new(value) as Box<dyn std::any::Any>);
+        self.values.insert(
+            std::any::TypeId::of::<CVT>(),
+            Box::new(value) as Box<dyn std::any::Any>,
+        );
     }
     pub fn lookup<CVT: ContextValueTag>(&self) -> Option<&CVT::Value> {
         let stored = self.values.get(&std::any::TypeId::of::<CVT>())?;
@@ -54,39 +57,62 @@ impl<'l, V0: ValueGenerator<'l>> ValueGeneratorList<'l> for (V0,) {
         Some((self.0(ctx)?,))
     }
 }
-impl<'l, V0: ValueGenerator<'l>, V1: ValueGenerator<'l>> ValueGeneratorList<'l> for (V0,V1) {
-    type OutputTuple = (V0::Value,V1::Value);
+impl<'l, V0: ValueGenerator<'l>, V1: ValueGenerator<'l>> ValueGeneratorList<'l> for (V0, V1) {
+    type OutputTuple = (V0::Value, V1::Value);
 
     fn generate(&self, ctx: &mut Context) -> Option<Self::OutputTuple> {
-        Some((self.0(ctx)?,self.1(ctx)?))
+        Some((self.0(ctx)?, self.1(ctx)?))
     }
 }
-impl<'l, V0: ValueGenerator<'l>, V1: ValueGenerator<'l>, V2: ValueGenerator<'l>> ValueGeneratorList<'l> for (V0,V1,V2) {
-    type OutputTuple = (V0::Value,V1::Value,V2::Value);
+impl<'l, V0: ValueGenerator<'l>, V1: ValueGenerator<'l>, V2: ValueGenerator<'l>>
+    ValueGeneratorList<'l> for (V0, V1, V2)
+{
+    type OutputTuple = (V0::Value, V1::Value, V2::Value);
 
     fn generate(&self, ctx: &mut Context) -> Option<Self::OutputTuple> {
-        Some((self.0(ctx)?,self.1(ctx)?,self.2(ctx)?))
+        Some((self.0(ctx)?, self.1(ctx)?, self.2(ctx)?))
     }
 }
-impl<'l, V0: ValueGenerator<'l>, V1: ValueGenerator<'l>, V2: ValueGenerator<'l>, V3: ValueGenerator<'l>> ValueGeneratorList<'l> for (V0,V1,V2,V3) {
-    type OutputTuple = (V0::Value,V1::Value,V2::Value,V3::Value);
+impl<
+        'l,
+        V0: ValueGenerator<'l>,
+        V1: ValueGenerator<'l>,
+        V2: ValueGenerator<'l>,
+        V3: ValueGenerator<'l>,
+    > ValueGeneratorList<'l> for (V0, V1, V2, V3)
+{
+    type OutputTuple = (V0::Value, V1::Value, V2::Value, V3::Value);
 
     fn generate(&self, ctx: &mut Context) -> Option<Self::OutputTuple> {
-        Some((self.0(ctx)?,self.1(ctx)?,self.2(ctx)?,self.3(ctx)?))
+        Some((self.0(ctx)?, self.1(ctx)?, self.2(ctx)?, self.3(ctx)?))
     }
 }
-impl<'l, V0: ValueGenerator<'l>, V1: ValueGenerator<'l>, V2: ValueGenerator<'l>, V3: ValueGenerator<'l>, V4: ValueGenerator<'l>> ValueGeneratorList<'l> for (V0,V1,V2,V3,V4) {
-    type OutputTuple = (V0::Value,V1::Value,V2::Value,V3::Value,V4::Value);
+impl<
+        'l,
+        V0: ValueGenerator<'l>,
+        V1: ValueGenerator<'l>,
+        V2: ValueGenerator<'l>,
+        V3: ValueGenerator<'l>,
+        V4: ValueGenerator<'l>,
+    > ValueGeneratorList<'l> for (V0, V1, V2, V3, V4)
+{
+    type OutputTuple = (V0::Value, V1::Value, V2::Value, V3::Value, V4::Value);
 
     fn generate(&self, ctx: &mut Context) -> Option<Self::OutputTuple> {
-        Some((self.0(ctx)?,self.1(ctx)?,self.2(ctx)?,self.3(ctx)?,self.4(ctx)?))
+        Some((
+            self.0(ctx)?,
+            self.1(ctx)?,
+            self.2(ctx)?,
+            self.3(ctx)?,
+            self.4(ctx)?,
+        ))
     }
 }
 
-pub trait UnaryInputSpec : super::UnaryOpSpec {
+pub trait UnaryInputSpec: super::UnaryOpSpec {
     fn gen<'l>() -> impl ValueGeneratorList<'l, OutputTuple = Self::Params<'l>>;
 }
 
-pub trait BinaryInputSpec : super::BinaryOpSpec {
+pub trait BinaryInputSpec: super::BinaryOpSpec {
     fn gen<'l>() -> impl ValueGeneratorList<'l, OutputTuple = Self::Params<'l>>;
 }

+ 30 - 12
src/op/generate/impls.rs

@@ -1,7 +1,18 @@
+use rand::{
+    distributions::{uniform::SampleUniform, Distribution, Standard, Uniform},
+    prelude::*,
+    rngs::ThreadRng,
+    thread_rng, Fill,
+};
 use std::ops::Range;
-use rand::{prelude::*, distributions::{Uniform, Distribution, Standard, uniform::SampleUniform}, thread_rng, rngs::ThreadRng, Fill};
 
-use crate::{math::{PixelPoint, PixelSize, PixelBox}, formats::{PixelFormatSpec, self}, Bitmap, prelude::*, colour::Colour};
+use crate::{
+    colour::Colour,
+    formats::{self, PixelFormatSpec},
+    math::{PixelBox, PixelPoint, PixelSize},
+    prelude::*,
+    Bitmap,
+};
 
 use super::{Context, ContextValueTag};
 
@@ -24,10 +35,7 @@ impl ContextValueTag for SrcSize {
 fn point_in_size(rng: &mut ThreadRng, sz: &PixelSize) -> PixelPoint {
     let xdist = Uniform::new(0, sz.width);
     let ydist = Uniform::new(0, sz.height);
-    PixelPoint::new(
-        xdist.sample(rng),
-        ydist.sample(rng)
-    )
+    PixelPoint::new(xdist.sample(rng), ydist.sample(rng))
 }
 
 pub fn constant<V: Clone>(v: V) -> impl Fn(&mut Context) -> Option<V> {
@@ -47,18 +55,28 @@ pub fn random_colour(ctx: &mut Context) -> Option<Colour> {
 }
 
 pub fn dst_image_generator<Format: PixelFormatSpec>(ctx: &mut Context) -> Option<Bitmap<Format>> {
-    let size_bounds = ctx.lookup::<ImageSizeBounds>().unwrap_or(&DEFAULT_SIZE_BOUNDS);
+    let size_bounds = ctx
+        .lookup::<ImageSizeBounds>()
+        .unwrap_or(&DEFAULT_SIZE_BOUNDS);
     let size_dist = Uniform::new(size_bounds.start, size_bounds.end);
-    let mut bitmap = Bitmap::new(size_dist.sample(ctx.rng()) as usize, size_dist.sample(ctx.rng()) as usize);
+    let mut bitmap = Bitmap::new(
+        size_dist.sample(ctx.rng()) as usize,
+        size_dist.sample(ctx.rng()) as usize,
+    );
     bitmap.data_mut().data_mut().try_fill(ctx.rng()).ok()?;
     ctx.insert::<DstSize>(bitmap.size());
     Some(bitmap)
 }
 
 pub fn src_image_generator<Format: PixelFormatSpec>(ctx: &mut Context) -> Option<Bitmap<Format>> {
-    let size_bounds = ctx.lookup::<ImageSizeBounds>().unwrap_or(&DEFAULT_SIZE_BOUNDS);
+    let size_bounds = ctx
+        .lookup::<ImageSizeBounds>()
+        .unwrap_or(&DEFAULT_SIZE_BOUNDS);
     let size_dist = Uniform::new(size_bounds.start, size_bounds.end);
-    let mut bitmap = Bitmap::new(size_dist.sample(ctx.rng()) as usize, size_dist.sample(ctx.rng()) as usize);
+    let mut bitmap = Bitmap::new(
+        size_dist.sample(ctx.rng()) as usize,
+        size_dist.sample(ctx.rng()) as usize,
+    );
     bitmap.data_mut().data_mut().try_fill(ctx.rng()).ok()?;
     ctx.insert::<SrcSize>(bitmap.size());
     Some(bitmap)
@@ -82,7 +100,7 @@ pub fn dst_area(ctx: &mut Context) -> Option<PixelBox> {
     let src_size = ctx.lookup::<DstSize>()?;
     Some(PixelBox::new(
         point_in_size(&mut rng, src_size),
-        point_in_size(&mut rng, src_size)
+        point_in_size(&mut rng, src_size),
     ))
 }
 
@@ -91,6 +109,6 @@ pub fn src_area(ctx: &mut Context) -> Option<PixelBox> {
     let src_size = ctx.lookup::<SrcSize>()?;
     Some(PixelBox::new(
         point_in_size(&mut rng, src_size),
-        point_in_size(&mut rng, src_size)
+        point_in_size(&mut rng, src_size),
     ))
 }

+ 37 - 21
src/op/rectangle.rs

@@ -4,18 +4,22 @@ use crate::{
     math::{PixelBox, PixelPoint, PixelSideOffsets},
 };
 
-use super::{GenericUnary, UnaryDispatch, UnaryOpSpec, KahloOps};
+use super::{GenericUnary, KahloOps, UnaryDispatch, UnaryOpSpec};
 
 pub struct RectangleOp;
 
 type Params<'l> = (PixelBox, usize, Colour);
 
 #[cfg(test)]
-const _ : () = {
+const _: () = {
     use super::generate;
     impl generate::UnaryInputSpec for RectangleOp {
         fn gen<'l>() -> impl generate::ValueGeneratorList<'l, OutputTuple = Self::Params<'l>> {
-            (generate::dst_area, generate::uniform(1,5), generate::random_colour,)
+            (
+                generate::dst_area,
+                generate::uniform(1, 5),
+                generate::random_colour,
+            )
         }
     }
 };
@@ -33,7 +37,8 @@ impl<'l> GenericUnary<Params<'l>> for RectangleOp {
         params: &Params<'l>,
     ) {
         // get a KahloOps for the image
-        let mut subregion = write_data.make_view_mut::<Format>(PixelBox::from_size(write_data.size()));
+        let mut subregion =
+            write_data.make_view_mut::<Format>(PixelBox::from_size(write_data.size()));
         let (area, width, colour) = params;
 
         let maxmin = PixelPoint::new(area.max.x, area.min.y);
@@ -42,26 +47,37 @@ impl<'l> GenericUnary<Params<'l>> for RectangleOp {
         let width = (*width as i32) - 1;
 
         // top side
-        subregion.fill_region(PixelBox::from_points([area.min, maxmin]).outer_box(PixelSideOffsets {
-            bottom: width,
-            ..Default::default()
-        }), *colour);
+        subregion.fill_region(
+            PixelBox::from_points([area.min, maxmin]).outer_box(PixelSideOffsets {
+                bottom: width,
+                ..Default::default()
+            }),
+            *colour,
+        );
         // bottom side
-        subregion.fill_region(PixelBox::from_points([minmax, area.max]).outer_box(PixelSideOffsets {
-            top: width,
-            ..Default::default()
-        }), *colour);
+        subregion.fill_region(
+            PixelBox::from_points([minmax, area.max]).outer_box(PixelSideOffsets {
+                top: width,
+                ..Default::default()
+            }),
+            *colour,
+        );
 
         // left side
-        subregion.fill_region(PixelBox::from_points([area.min, minmax]).outer_box(PixelSideOffsets {
-            right: width,
-            ..Default::default()
-        }), *colour);
+        subregion.fill_region(
+            PixelBox::from_points([area.min, minmax]).outer_box(PixelSideOffsets {
+                right: width,
+                ..Default::default()
+            }),
+            *colour,
+        );
         // right side
-        subregion.fill_region(PixelBox::from_points([maxmin, area.max]).outer_box(PixelSideOffsets {
-            left: width,
-            ..Default::default()
-        }), *colour);
+        subregion.fill_region(
+            PixelBox::from_points([maxmin, area.max]).outer_box(PixelSideOffsets {
+                left: width,
+                ..Default::default()
+            }),
+            *colour,
+        );
     }
 }
-