Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add lightweight wasm support to rust-decimal #650

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ rocket = { default-features = false, optional = true, version = "0.5.0-rc.3" }
serde = { default-features = false, optional = true, version = "1.0" }
serde_json = { default-features = false, optional = true, version = "1.0" }
tokio-postgres = { default-features = false, optional = true, version = "0.7" }
wasm-bindgen = { default-features = false, optional = true, version = "0.2" }
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just looking through how some other libraries introduce this and I think it needs to be done as a target as opposed to a simple feature. It could technically still be a feature however it'd need to be a no-op for std/core.

e.g.

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = { default-features = false, version = "0.2" }

There may be a requirement to also exclude some other libraries that aren't supported on wasm of course. However that'd require some investigation (e.g. what features are supported in combination with wasm)


[dev-dependencies]
bincode = { default-features = false, version = "1.0" }
Expand Down Expand Up @@ -87,6 +88,7 @@ serde-with-float = ["serde"]
serde-with-str = ["serde"]
std = ["arrayvec/std", "borsh?/std", "bytes?/std", "rand?/std", "rkyv?/std", "serde?/std", "serde_json?/std"]
tokio-pg = ["db-tokio-postgres"] # Backwards compatability
wasm = ["dep:wasm-bindgen"]

[[bench]]
harness = false
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ assert_eq!(total, dec!(27.26));
* [rocket-traits](#rocket-traits)
* [rust-fuzz](#rust-fuzz)
* [std](#std)
* [wasm](#wasm)

**Database**

Expand Down Expand Up @@ -331,6 +332,12 @@ Please see the `examples` directory for more information regarding `serde_json`
Enable `std` library support. This is enabled by default, however in the future will be opt in. For now, to support `no_std`
libraries, this crate can be compiled with `--no-default-features`.

### `wasm`

Enable [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) support which makes `Decimal` compatible with the
`wasm_bindgen` attribute macro and exposes `fromNumber()` and `toNumber()` methods to convert between `Decimal` and
the primitive `number` type across boundaries.

## Building

Please refer to the [Build document](BUILD.md) for more information on building and testing Rust Decimal.
Expand Down
3 changes: 3 additions & 0 deletions src/decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ use num_traits::float::FloatCore;
use num_traits::{FromPrimitive, Num, One, Signed, ToPrimitive, Zero};
#[cfg(feature = "rkyv")]
use rkyv::{Archive, Deserialize, Serialize};
#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::wasm_bindgen;

/// The smallest value that can be represented by this decimal type.
const MIN: Decimal = Decimal {
Expand Down Expand Up @@ -121,6 +123,7 @@ pub struct UnpackedDecimal {
archive_attr(derive(Clone, Copy, Debug))
)]
#[cfg_attr(feature = "rkyv-safe", archive(check_bytes))]
#[cfg_attr(feature = "wasm", wasm_bindgen)]
pub struct Decimal {
// Bits 0-15: unused
// Bits 16-23: Contains "e", a value between 0-28 that indicates the scale
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ mod serde;
)
))]
pub mod serde;
#[cfg(feature = "wasm")]
pub mod wasm;

pub use decimal::{Decimal, RoundingStrategy};
pub use error::Error;
Expand Down
26 changes: 26 additions & 0 deletions src/wasm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use num_traits::{FromPrimitive, ToPrimitive};
use wasm_bindgen::prelude::wasm_bindgen;

use crate::Decimal;

#[wasm_bindgen]
impl Decimal {
/// Returns a new `Decimal` object instance by converting a primitive number.
#[wasm_bindgen(js_name = fromNumber)]
#[must_use]
pub fn from_number(value: f64) -> Option<Decimal> {
Decimal::from_f64(value)
}

/// Returns the value of this `Decimal` converted to a primitive number.
///
/// # Caution
/// At the time of writing this implementation the conversion from `Decimal` to `f64` cannot
/// fail. To prevent undefined behavior in case the underlying implementation changes `f64::NAN`
/// is returned as a stable fallback value.
#[wasm_bindgen(js_name = toNumber)]
#[must_use]
pub fn to_number(&self) -> f64 {
self.to_f64().unwrap_or(f64::NAN)
}
}
Loading