Skip to content

Commit

Permalink
Make crate no_std
Browse files Browse the repository at this point in the history
hashbrown::HashMap is used to replace std::collections::HashMap.
libm is used for float operations.
  • Loading branch information
EHfive committed Sep 19, 2023
1 parent ec97e2e commit 978d00c
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 17 deletions.
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ rust:
- beta
- nightly
script:
- cargo build --no-default-features --features no_std -v
- cargo test --no-default-features --features no_std -v
- cargo doc --no-default-features --features no_std -v
- cargo build -v
- cargo test -v
- cargo doc -v
Expand Down
10 changes: 7 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "resize"
version = "0.8.0"
description = "Simple image resampling library in pure Rust."
authors = ["Kornel <[email protected]>", "Kagami Hiiragi <[email protected]>"]
categories = ["graphics", "multimedia::images"]
categories = ["graphics", "multimedia::images", "no_std"]
keywords = ["resize", "scale", "resample", "image", "graphics"]
documentation = "https://docs.rs/resize"
homepage = "https://github.com/PistonDevelopers/resize"
Expand All @@ -15,13 +15,17 @@ edition = "2021"
rust-version = "1.57"

[features]
default = ["rayon"]
default = ["std"]
std = ["rayon"]
no_std = ["libm", "hashbrown"]

[dev-dependencies]
png = "0.17.7"

[dependencies]
rgb = "0.8.36"
rgb = { version = "0.8.36", default-features = false }
libm = { version = "0.2.7", optional = true }
hashbrown = { version = "0.14.0", optional = true }
rayon = { version = "1.7.0", optional = true }

[package.metadata.docs.rs]
Expand Down
57 changes: 43 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,43 @@
// * https://github.com/sekrit-twc/zimg/tree/master/src/zimg/resize
// * https://github.com/PistonDevelopers/image/blob/master/src/imageops/sample.rs
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(not(any(feature = "std", feature = "no_std")))]
compile_error!("Either the `std` or `no_std` feature must be enabled");

extern crate alloc;

use core::f32;
use core::fmt;
use core::num::NonZeroUsize;

use alloc::boxed::Box;
use alloc::collections::TryReserveError;
use alloc::sync::Arc;
use alloc::vec::Vec;

#[cfg(not(feature = "std"))]
use hashbrown::HashMap;
#[cfg(feature = "std")]
use std::collections::HashMap;
use std::f32;
use std::fmt;
use std::num::NonZeroUsize;
use std::sync::Arc;

#[cfg(feature = "rayon")]
use rayon::prelude::*;

/// See [Error]
pub type Result<T, E = Error> = std::result::Result<T, E>;
pub type Result<T, E = Error> = core::result::Result<T, E>;

/// Pixel format from the [rgb] crate.
pub mod px;
pub use px::PixelFormat;

#[cfg(not(feature = "std"))]
mod no_std_float;
#[cfg(not(feature = "std"))]
#[allow(unused_imports)]
use no_std_float::FloatExt;

/// Resizing type to use.
pub enum Type {
/// Point resizing.
Expand Down Expand Up @@ -152,7 +172,7 @@ fn lanczos(taps: f32, x: f32) -> f32 {
#[allow(non_upper_case_globals)]
pub mod Pixel {
use crate::formats;
use std::marker::PhantomData;
use core::marker::PhantomData;

/// Grayscale, 8-bit.
#[cfg_attr(docsrs, doc(alias = "Grey"))]
Expand Down Expand Up @@ -212,7 +232,7 @@ pub mod Pixel {
/// These structs implement `PixelFormat` trait that allows conversion to and from internal pixel representation.
#[doc(hidden)]
pub mod formats {
use std::marker::PhantomData;
use core::marker::PhantomData;
/// RGB pixels
#[derive(Debug, Copy, Clone)]
pub struct Rgb<InputSubpixel, OutputSubpixel>(
Expand Down Expand Up @@ -441,7 +461,7 @@ impl<Format: PixelFormat> Resizer<Format> {
stride: NonZeroUsize,
dst: &mut [Format::OutputPixel],
) -> Result<()> {
use std::sync::atomic::AtomicPtr;
use core::sync::atomic::AtomicPtr;

let stride = stride.get();
let pix_fmt = &self.pix_fmt;
Expand Down Expand Up @@ -471,7 +491,7 @@ impl<Format: PixelFormat> Resizer<Format> {
.enumerate()
.for_each(|(x, col)| {
// Acquire a safe reference to the current position in the temporary buffer.
let tmp_raw_ptr = tmp_ptr.load(std::sync::atomic::Ordering::Relaxed);
let tmp_raw_ptr = tmp_ptr.load(core::sync::atomic::Ordering::Relaxed);

let mut accum = Format::new();
let in_px = &row[col.start..col.start + col.coeffs.len()];
Expand Down Expand Up @@ -499,7 +519,7 @@ impl<Format: PixelFormat> Resizer<Format> {
// For each pixel in the row, calculate the vertical resampling and store the result directly into the destination buffer.
(0..w2).into_par_iter().for_each(|x| {
// Acquire a safe reference to the current position in the temporary buffer.
let tmp_raw_ptr = tmp_ptr.load(std::sync::atomic::Ordering::Relaxed);
let tmp_raw_ptr = tmp_ptr.load(core::sync::atomic::Ordering::Relaxed);

// Determine the start of the current row in the temporary buffer.
let tmp_row_start = unsafe { tmp_raw_ptr.add(w2 * row.start) };
Expand All @@ -513,7 +533,7 @@ impl<Format: PixelFormat> Resizer<Format> {
}

// Determine the location in the destination buffer to store the result.
let raw_ptr = dst_ptr.load(std::sync::atomic::Ordering::Relaxed);
let raw_ptr = dst_ptr.load(core::sync::atomic::Ordering::Relaxed);
// Write the accumulated value to the destination buffer.
unsafe {
*raw_ptr.add(y * w2 + x) = pix_fmt.into_pixel(accum);
Expand Down Expand Up @@ -625,11 +645,20 @@ pub enum Error {
InvalidParameters,
}

#[cfg(feature = "std")]
impl std::error::Error for Error {}

impl From<std::collections::TryReserveError> for Error {
impl From<TryReserveError> for Error {
#[inline(always)]
fn from(_: TryReserveError) -> Self {
Self::OutOfMemory
}
}

#[cfg(not(feature = "std"))]
impl From<hashbrown::TryReserveError> for Error {
#[inline(always)]
fn from(_: std::collections::TryReserveError) -> Self {
fn from(_: hashbrown::TryReserveError) -> Self {
Self::OutOfMemory
}
}
Expand All @@ -644,7 +673,7 @@ impl fmt::Display for Error {
}
}

#[cfg(test)]
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;

Expand Down
90 changes: 90 additions & 0 deletions src/no_std_float.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/// Alternative basic float operations for no_std
pub(crate) trait FloatExt {
fn floor(self) -> Self;
fn ceil(self) -> Self;
fn sqrt(self) -> Self;
fn round(self) -> Self;
fn abs(self) -> Self;
fn trunc(self) -> Self;
fn fract(self) -> Self;
fn sin(self) -> Self;
fn powi(self, n: i32) -> Self;
}

impl FloatExt for f32 {
#[inline]
fn floor(self) -> Self {
libm::floorf(self)
}
#[inline]
fn ceil(self) -> Self {
libm::ceilf(self)
}
#[inline]
fn sqrt(self) -> Self {
libm::sqrtf(self)
}
#[inline]
fn round(self) -> Self {
libm::roundf(self)
}
#[inline]
fn abs(self) -> Self {
libm::fabsf(self)
}
#[inline]
fn trunc(self) -> Self {
libm::truncf(self)
}
#[inline]
fn fract(self) -> Self {
self - self.trunc()
}
#[inline]
fn sin(self) -> Self {
libm::sinf(self)
}
#[inline]
fn powi(self, n: i32) -> Self {
libm::powf(self, n as _)
}
}

impl FloatExt for f64 {
#[inline]
fn floor(self) -> Self {
libm::floor(self)
}
#[inline]
fn ceil(self) -> Self {
libm::ceil(self)
}
#[inline]
fn sqrt(self) -> Self {
libm::sqrt(self)
}
#[inline]
fn round(self) -> Self {
libm::round(self)
}
#[inline]
fn abs(self) -> Self {
libm::fabs(self)
}
#[inline]
fn trunc(self) -> Self {
libm::trunc(self)
}
#[inline]
fn fract(self) -> Self {
self - self.trunc()
}
#[inline]
fn sin(self) -> Self {
libm::sin(self)
}
#[inline]
fn powi(self, n: i32) -> Self {
libm::pow(self, n as _)
}
}

0 comments on commit 978d00c

Please sign in to comment.