diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f66a6127..3e917cdad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -185,6 +185,12 @@ jobs: contains(matrix.platform.name, 'Linux 64bit') && matrix.toolchain != '1.73' run: cargo test -p dpi + + - name: Check dpi crate (no_std) + if: > + contains(matrix.platform.name, 'Linux 64bit') && + matrix.toolchain != '1.73' + run: cargo check -p dpi --no-default-features - name: Build tests if: > diff --git a/README.md b/README.md index ffae855f5..185232265 100644 --- a/README.md +++ b/README.md @@ -71,3 +71,9 @@ same MSRV policy. ### Platform-specific usage Check out the [`winit::platform`](https://docs.rs/winit/latest/winit/platform/index.html) module for platform-specific usage. + +### Repository License + +Note that the license in `LICENSE` doesn't apply in full to the DPI package [./dpi](./dpi). +Full details can be found in that folder's README. + diff --git a/dpi/CHANGELOG.md b/dpi/CHANGELOG.md index 6dd72ea3d..90bda8fb6 100644 --- a/dpi/CHANGELOG.md +++ b/dpi/CHANGELOG.md @@ -12,6 +12,7 @@ Unreleased` header. ## Unreleased - Added `Insets`, `LogicalInsets` and `PhysicalInsets` types. +- Make `no_std` compatible. If you use this functionality, DPI's license has changed. ## 0.1.1 diff --git a/dpi/Cargo.toml b/dpi/Cargo.toml index 461028eb8..e2cc20b41 100644 --- a/dpi/Cargo.toml +++ b/dpi/Cargo.toml @@ -3,16 +3,22 @@ categories = ["gui"] description = "Types for handling UI scaling" edition.workspace = true keywords = ["DPI", "HiDPI", "scale-factor"] -license.workspace = true +# N.B. This is "AND", because of the imported libm code. +license = "Apache-2.0 AND MIT" name = "dpi" repository.workspace = true rust-version.workspace = true version = "0.1.1" [features] +default = ["std"] + mint = ["dep:mint"] serde = ["dep:serde"] +# Access mathematical functions using the standard library implementations +std = [] + [dependencies] mint = { workspace = true, optional = true } serde = { workspace = true, optional = true } diff --git a/dpi/LICENSE-LIBM-MIT b/dpi/LICENSE-LIBM-MIT new file mode 100644 index 000000000..d43e0a6c9 --- /dev/null +++ b/dpi/LICENSE-LIBM-MIT @@ -0,0 +1,51 @@ +rust-lang/libm as a whole is available for use under the MIT license: + +------------------------------------------------------------------------------ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ + +This Rust library contains the following copyrights: + + Copyright (c) 2018 Jorge Aparicio + +Portions of this software are derived from third-party works licensed under +terms compatible with the above MIT license: + +* musl libc https://www.musl-libc.org/. This library contains the following + copyright: + + Copyright © 2005-2020 Rich Felker, et al. + +* The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH + routines are available under the MIT license on a per-file basis. + +The musl libc COPYRIGHT file also includes the following notice relevant to +math portions of the library: + +------------------------------------------------------------------------------ +Much of the math library code (src/math/* and src/complex/*) is +Copyright © 1993,2004 Sun Microsystems or +Copyright © 2003-2011 David Schultz or +Copyright © 2003-2009 Steven G. Kargl or +Copyright © 2003-2009 Bruce D. Evans or +Copyright © 2008 Stephen L. Moshier or +Copyright © 2017-2018 Arm Limited +and labelled as such in comments in the individual source files. All +have been licensed under extremely permissive terms. +------------------------------------------------------------------------------ diff --git a/dpi/README.md b/dpi/README.md new file mode 100644 index 000000000..4aa277c0a --- /dev/null +++ b/dpi/README.md @@ -0,0 +1,18 @@ +# DPI + +Full docs can be found on docs.rs. + +## License + +Most of DPI is licensed under the Apache License, Version 2.0 ([LICENSE](LICENSE)). +All files except for `src/libm.rs` (and `LICENSE-LIBM-MIT`) are available solely under that license. + +For its `no_std` support, DPI uses code from the [libm](https://crates.io/crates/libm) crate. +This is in the `libm.rs` file, and is licensed solely under the MIT Licence ([LICENSE-LIBM-MIT](LICENSE-LIBM-MIT)). +That file contains details of all potentially applicable copyright notices. +This is feature gated to only be included if you disable the `std` feature, otherwise it will not be compiled into your final binary +(and so these license terms will not apply). + +Overall, this means that the license for this crate depends on what features you have enabled. +If you enable the `std` feature, then DPI uses only code available under the Apache-2.0 license, and so can be used under the terms of that license. +However, if you disable the `std` feature, then both these licenses must be followed to use the crate as a whole. diff --git a/dpi/src/lib.rs b/dpi/src/lib.rs index 2e6c17f57..1b2367208 100644 --- a/dpi/src/lib.rs +++ b/dpi/src/lib.rs @@ -54,13 +54,25 @@ //! //! * `serde`: Enables serialization/deserialization of certain types with [Serde](https://crates.io/crates/serde). //! * `mint`: Enables mint (math interoperability standard types) conversions. +//! * `std` (enabled by default): Uses the standard library mathematical functions (normally through +//! your target platform's libm). This feature also changes the library's license from `Apache-2.0 +//! AND MIT` to `APACHE-2.0` (only). For full details, see the package README. //! +//! To use this library on a target without the standard library available, you should disable +//! default features (thus disabling the `std` feature, with the license consequences thereof). //! //! [points]: https://en.wikipedia.org/wiki/Point_(typography) //! [picas]: https://en.wikipedia.org/wiki/Pica_(typography) #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg_hide), doc(cfg_hide(doc, docsrs)))] -#![forbid(unsafe_code)] +#![cfg_attr(feature = "std", forbid(unsafe_code))] +#![no_std] + +#[cfg(not(feature = "std"))] +mod libm; + +#[cfg(any(feature = "std", test))] +extern crate std; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -74,32 +86,32 @@ pub trait Pixel: Copy + Into { impl Pixel for u8 { fn from_f64(f: f64) -> Self { - f.round() as u8 + round(f) as u8 } } impl Pixel for u16 { fn from_f64(f: f64) -> Self { - f.round() as u16 + round(f) as u16 } } impl Pixel for u32 { fn from_f64(f: f64) -> Self { - f.round() as u32 + round(f) as u32 } } impl Pixel for i8 { fn from_f64(f: f64) -> Self { - f.round() as i8 + round(f) as i8 } } impl Pixel for i16 { fn from_f64(f: f64) -> Self { - f.round() as i16 + round(f) as i16 } } impl Pixel for i32 { fn from_f64(f: f64) -> Self { - f.round() as i32 + round(f) as i32 } } impl Pixel for f32 { @@ -113,6 +125,15 @@ impl Pixel for f64 { } } +/// Round f to the closest integer, rounding away from `0.0` +#[inline] +fn round(f: f64) -> f64 { + #[cfg(feature = "std")] + return f.round(); + #[cfg(not(feature = "std"))] + return libm::round(f); +} + /// Checks that the scale factor is a normal positive `f64`. /// /// All functions that take a scale factor assert that this will return `true`. If you're sourcing @@ -1270,20 +1291,20 @@ mod tests { // Eat coverage for the Debug impls et al #[test] fn ensure_attrs_do_not_panic() { - let _ = format!("{:?}", LogicalPosition::::default().clone()); + let _ = std::format!("{:?}", LogicalPosition::::default().clone()); HashSet::new().insert(LogicalPosition::::default()); - let _ = format!("{:?}", PhysicalPosition::::default().clone()); + let _ = std::format!("{:?}", PhysicalPosition::::default().clone()); HashSet::new().insert(PhysicalPosition::::default()); - let _ = format!("{:?}", LogicalSize::::default().clone()); + let _ = std::format!("{:?}", LogicalSize::::default().clone()); HashSet::new().insert(LogicalSize::::default()); - let _ = format!("{:?}", PhysicalSize::::default().clone()); + let _ = std::format!("{:?}", PhysicalSize::::default().clone()); HashSet::new().insert(PhysicalSize::::default()); - let _ = format!("{:?}", Size::Physical((1, 2).into()).clone()); - let _ = format!("{:?}", Position::Physical((1, 2).into()).clone()); + let _ = std::format!("{:?}", Size::Physical((1, 2).into()).clone()); + let _ = std::format!("{:?}", Position::Physical((1, 2).into()).clone()); } #[test] diff --git a/dpi/src/libm.rs b/dpi/src/libm.rs new file mode 100644 index 000000000..1785b67f2 --- /dev/null +++ b/dpi/src/libm.rs @@ -0,0 +1,56 @@ +// Copyright (c) 2018 Jorge Aparicio +// Copyright © 2005-2020 Rich Felker, et al. +// Copyright © 1993,2004 Sun Microsystems or +// Copyright © 2003-2011 David Schultz or +// Copyright © 2003-2009 Steven G. Kargl or +// Copyright © 2003-2009 Bruce D. Evans or +// Copyright © 2008 Stephen L. Moshier or +// Copyright © 2017-2018 Arm Limited +// SPDX-License-Identifier: MIT +// This file is licensed solely under the terms discussed in LICENSE-LIBM-MIT at the crate root. +// See the package-level README for full details. + +// Taken from https://github.com/rust-lang/libm/blob/master/src/math/mod.rs#L1 +macro_rules! force_eval { + ($e:expr) => { + unsafe { ::core::ptr::read_volatile(&$e) } + }; +} + +// Taken from https://github.com/rust-lang/libm/blob/libm-v0.2.11/src/math/round.rs +pub(crate) fn round(x: f64) -> f64 { + trunc(x + copysign(0.5 - 0.25 * f64::EPSILON, x)) +} + +// Adapted from: https://github.com/rust-lang/libm/blob/libm-v0.2.11/src/math/trunc.rs#L8-L12 +#[allow(clippy::needless_late_init /*, reason = "The original libm code uses this style" */)] +fn trunc(x: f64) -> f64 { + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 + + let mut i: u64 = x.to_bits(); + let mut e: i64 = ((i >> 52) & 0x7ff) as i64 - 0x3ff + 12; + let m: u64; + + if e >= 52 + 12 { + return x; + } + if e < 12 { + e = 1; + } + m = -1i64 as u64 >> e; + if (i & m) == 0 { + return x; + } + force_eval!(x + x1p120); + i &= !m; + f64::from_bits(i) +} + +// Taken from https://github.com/rust-lang/libm/blob/libm-v0.2.11/src/math/copysign.rs +fn copysign(x: f64, y: f64) -> f64 { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= (!0) >> 1; + ux |= uy & (1 << 63); + f64::from_bits(ux) +}