├── .gitignore ├── .github ├── CODEOWNERS └── workflows │ └── ci.yml ├── src ├── num │ ├── mod.rs │ ├── float_convert.rs │ └── integer.rs ├── sync │ ├── mod.rs │ ├── mutex.rs │ └── rw_lock.rs ├── default.rs ├── str.rs ├── result.rs ├── option.rs ├── vec.rs ├── lib.rs ├── macros.rs └── duration.rs ├── Cargo.toml ├── LICENSE ├── CHANGELOG.md ├── CONTRIBUTING.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Default owners for everything in the repository: 2 | * @popzxc 3 | -------------------------------------------------------------------------------- /src/num/mod.rs: -------------------------------------------------------------------------------- 1 | //! Extensions for the built-in numeric types. 2 | 3 | pub mod float_convert; 4 | pub mod integer; 5 | -------------------------------------------------------------------------------- /src/sync/mod.rs: -------------------------------------------------------------------------------- 1 | //! Extension traits for the standard synchronization primitives. 2 | 3 | pub mod mutex; 4 | pub mod rw_lock; 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stdext" 3 | version = "0.3.3" 4 | authors = ["Igor Aleksanov "] 5 | edition = "2018" 6 | repository = "https://github.com/popzxc/stdext-rs" 7 | documentation = "https://docs.rs/stdext" 8 | readme = "README.md" 9 | license = "MIT" 10 | keywords = ["std", "extensions", "helpers", "utils"] 11 | categories = ["rust-patterns"] 12 | description = "Extensions for the Rust standard library structures." 13 | 14 | [dependencies] 15 | -------------------------------------------------------------------------------- /src/default.rs: -------------------------------------------------------------------------------- 1 | //! Freestanding version of `std::default::Default::default()`. 2 | 3 | /// Freestanding version of `std::default::Default::default()`. 4 | /// 5 | /// Used to be available under `#![feature(default_free_fn)]`, 6 | /// removed in [rust-lang/rust#113469](https://github.com/rust-lang/rust/pull/113469). 7 | /// 8 | /// # Examples 9 | /// 10 | /// ``` 11 | /// use stdext::prelude::*; 12 | /// 13 | /// #[derive(Default, PartialEq, Eq, Debug)] 14 | /// struct StructWithLongName { 15 | /// a: u32, 16 | /// b: u32, 17 | /// } 18 | /// 19 | /// let s = StructWithLongName { 20 | /// a: 12, 21 | /// ..default() // Normally you have to do 22 | /// // `Default::default()`, 23 | /// // `<_>::default()` or 24 | /// // `StructWithLongName::default()` 25 | /// }; 26 | /// 27 | /// assert_eq!(s, StructWithLongName { a: 12, ..<_>::default() }); 28 | /// ``` 29 | pub fn default() -> T { 30 | T::default() 31 | } 32 | -------------------------------------------------------------------------------- /src/sync/mutex.rs: -------------------------------------------------------------------------------- 1 | //! Extension traits for `std::sync::Mutex`. 2 | 3 | use std::sync::{Mutex, MutexGuard}; 4 | 5 | /// Extension trait with useful methods for [`std::sync::Mutex`]. 6 | /// 7 | /// [`std::sync::Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html 8 | pub trait MutexExt { 9 | /// Shorthand for `mutex.lock().unwrap()` with a better panic message. 10 | /// 11 | /// This method is intended to be used in situations where poisoned locks are 12 | /// considered an exceptional situation and should always result in panic. 13 | /// 14 | /// # Examples 15 | /// 16 | /// ``` 17 | /// use std::sync::Mutex; 18 | /// use stdext::prelude::*; 19 | /// 20 | /// let lock = Mutex::new(1); 21 | /// 22 | /// let n = lock.force_lock(); 23 | /// assert_eq!(*n, 1); 24 | /// ``` 25 | fn force_lock(&self) -> MutexGuard; 26 | } 27 | 28 | impl MutexExt for Mutex { 29 | fn force_lock(&self) -> MutexGuard { 30 | self.lock() 31 | .expect("Unable to obtain lock: Mutex is poisoned") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Igor Aleksanov 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `stdext` changelog 2 | 3 | ## [[Unreleased]] 4 | 5 | ## 0.3.3 (18.06.2021) 6 | 7 | - `debug_name` convenience macro [#17]. 8 | - Freestanding `debug` function [#18]. 9 | 10 | [#17]: https://github.com/popzxc/stdext-rs/pull/17 11 | [#18]: https://github.com/popzxc/stdext-rs/pull/18 12 | 13 | ## 0.3.0 (18.06.2021) 14 | 15 | - BREAKING: MSRV got bumped to 1.53. 16 | 17 | - `try_match` and `unwrap_match` macros to get a certain variant from an enum [#11]. 18 | - `return_ok` and `return_some` macros for early return of successful calculation [#11]. 19 | - `Integer` trait that unifies all the built-in integer types under a single interface [#12]. 20 | - `FloatConvert` trait that adds an interface for converting floating point numbers into integers [#12]. 21 | 22 | [#11]: https://github.com/popzxc/stdext-rs/pull/11 23 | [#12]: https://github.com/popzxc/stdext-rs/pull/12 24 | 25 | ## 0.2.1 (09.07.2020) 26 | 27 | - `VecExt::remove_item` method was added [#9]. 28 | 29 | [#9]: https://github.com/popzxc/stdext-rs/pull/9 30 | 31 | ## 0.2.0 (02.07.2020) 32 | 33 | - `compile_warning` and `function_name` macros were added [#4]. 34 | 35 | [#4]: https://github.com/popzxc/stdext-rs/pull/4 36 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing guide 2 | 3 | Thanks for considering contributing to the `stdext`! Here's a banana for you: 🍌 4 | 5 | If you are missing some functionality in the Rust standard library, but don't want 6 | to bother yourself with all the associated routines (writing RFC, defending it, implementing, 7 | waiting for it to be stabilized...), feel free to create a pull request to this repo. 8 | 9 | ## Adding new functionality 10 | 11 | The ideal pull request will satisfy the following criteria: 12 | 13 | - Does not contain any hate (any form of discrimination, politics, offence, etc). 14 | - Has an explanation why this functionality is useful for a generic audience. 15 | - Covers the introduced code with tests and documentation. 16 | - Does not rely on external dependencies (for any kind of complex functionality consider creating your 17 | own library, this crate is for minor improvements only). 18 | 19 | All the rules (except for the first one) are discussible if you can provide a heavy reasoning for it. 20 | 21 | ## Requesting the functionality 22 | 23 | If you don't want to implement the feature, but still feel that is missing in `std`, feel free to open 24 | a feature request issue. I'll try to implement it myself once I have the time. 25 | 26 | ## Other contributions 27 | 28 | Refactoring, improving documentation, adding tests and other kinds of improvements are really appreciated 29 | as well. 30 | -------------------------------------------------------------------------------- /src/sync/rw_lock.rs: -------------------------------------------------------------------------------- 1 | //! Extension traits for `std::sync::RwLock`. 2 | 3 | use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; 4 | 5 | /// Extension trait with useful methods for [`std::sync::RwLock`]. 6 | /// 7 | /// [`std::sync::RwLock`]: https://doc.rust-lang.org/std/sync/struct.RwLock.html 8 | pub trait RwLockExt { 9 | /// Shorthand for `lock.read().unwrap()` with a better panic message. 10 | /// 11 | /// This method is intended to be used in situations where poisoned locks are 12 | /// considered an exceptional situation and should always result in panic. 13 | /// 14 | /// # Examples 15 | /// 16 | /// ``` 17 | /// use std::sync::{Arc, RwLock}; 18 | /// use stdext::prelude::*; 19 | /// 20 | /// let lock = Arc::new(RwLock::new(1)); 21 | /// 22 | /// let n = lock.force_read(); 23 | /// assert_eq!(*n, 1); 24 | /// ``` 25 | fn force_read(&self) -> RwLockReadGuard; 26 | 27 | /// Shorthand for `lock.write().unwrap()` with a better panic message. 28 | /// 29 | /// This method is intended to be used in situations where poisoned locks are 30 | /// considered an exceptional situation and should always result in panic. 31 | /// 32 | /// # Examples 33 | /// 34 | /// ``` 35 | /// use std::sync::{Arc, RwLock}; 36 | /// use stdext::prelude::*; 37 | /// 38 | /// let lock = Arc::new(RwLock::new(1)); 39 | /// 40 | /// { 41 | /// let mut n = lock.force_write(); 42 | /// *n = 2; 43 | /// } 44 | /// 45 | /// let n = lock.force_read(); 46 | /// assert_eq!(*n, 2); 47 | /// ``` 48 | fn force_write(&self) -> RwLockWriteGuard; 49 | } 50 | 51 | impl RwLockExt for RwLock { 52 | fn force_read(&self) -> RwLockReadGuard { 53 | self.read() 54 | .expect("Unable to obtain read lock: RwLock is poisoned") 55 | } 56 | fn force_write(&self) -> RwLockWriteGuard { 57 | self.write() 58 | .expect("Unable to obtain write lock: RwLock is poisoned") 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/str.rs: -------------------------------------------------------------------------------- 1 | //! Extension traits for `str` primitive type. 2 | 3 | /// Alternative for `std::str::pattern::Pattern` that does not require 4 | /// nightly Rust (as `Pattern` is unstable yet). 5 | #[doc(hidden)] 6 | pub enum AltPattern<'a> { 7 | Str(&'a str), 8 | Char(char), 9 | } 10 | 11 | impl<'a> From<&'a str> for AltPattern<'a> { 12 | fn from(data: &'a str) -> Self { 13 | Self::Str(data) 14 | } 15 | } 16 | 17 | impl<'a> From for AltPattern<'a> { 18 | fn from(data: char) -> Self { 19 | Self::Char(data) 20 | } 21 | } 22 | 23 | /// Extension trait with useful methods for primitive type [`str`]. 24 | /// 25 | /// [`str`]: https://doc.rust-lang.org/std/primitive.str.html 26 | pub trait StrExt { 27 | /// Version of [`str::splitn`] which expects the **exact** 28 | /// amount of entries obtained after splitting. This method 29 | /// returns `Vec`, as [`SplitN`] iterator depends on the unstable 30 | /// type [`Pattern`] and cannot be returned on the stable Rust. 31 | /// 32 | /// # Examples 33 | /// 34 | /// ``` 35 | /// use stdext::prelude::*; 36 | /// 37 | /// let data = "Hello world"; 38 | /// let splitted = data.splitn_exact(2, " ").unwrap(); 39 | /// assert_eq!(&splitted, &["Hello", "world"]); 40 | /// 41 | /// let splitted = data.splitn_exact(5, '-'); 42 | /// assert!(splitted.is_none()); 43 | /// ``` 44 | /// 45 | /// [`str::splitn`]: https://doc.rust-lang.org/std/primitive.str.html#method.splitn 46 | /// [`SplitN`]: https://doc.rust-lang.org/std/str/struct.SplitN.html 47 | /// [`Pattern`]: https://doc.rust-lang.org/std/str/pattern/trait.Pattern.html 48 | fn splitn_exact<'a, P: Into>>( 49 | &'a self, 50 | n: usize, 51 | pat: P, 52 | ) -> Option>; 53 | } 54 | 55 | impl StrExt for &str { 56 | fn splitn_exact<'a, P: Into>>( 57 | &'a self, 58 | n: usize, 59 | pat: P, 60 | ) -> Option> { 61 | let pat = pat.into(); 62 | // Overcome for `&str` splitting API: it accepts generic arguments as separators, 63 | // but the `Pattern` trait is unstable, thus it's impossible to just forward arguments 64 | // inside on stable Rust. 65 | let splitted: Vec<_> = match pat { 66 | AltPattern::Str(sep) => self.splitn(n, sep).collect(), 67 | AltPattern::Char(sep) => self.splitn(n, sep).collect(), 68 | }; 69 | 70 | if splitted.len() == n { 71 | Some(splitted) 72 | } else { 73 | None 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - '*' 7 | 8 | jobs: 9 | fmt: 10 | name: Rustfmt 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout sources 15 | uses: actions/checkout@v2 16 | 17 | - name: Install rust 18 | uses: actions-rs/toolchain@v1 19 | with: 20 | toolchain: stable 21 | components: rustfmt 22 | profile: minimal 23 | override: true 24 | 25 | - name: Run rustfmt 26 | uses: actions-rs/cargo@v1 27 | with: 28 | command: fmt 29 | args: --all -- --check 30 | 31 | clippy: 32 | name: Clippy 33 | runs-on: ubuntu-latest 34 | 35 | steps: 36 | - name: Checkout sources 37 | uses: actions/checkout@v2 38 | 39 | - name: Install rust 40 | uses: actions-rs/toolchain@v1 41 | with: 42 | toolchain: stable 43 | components: clippy 44 | profile: minimal 45 | override: true 46 | 47 | - name: Run clippy 48 | uses: actions-rs/clippy-check@v1 49 | with: 50 | token: ${{ secrets.GITHUB_TOKEN }} 51 | args: -- -D warnings 52 | 53 | audit: 54 | name: Security audit 55 | runs-on: ubuntu-latest 56 | 57 | steps: 58 | - uses: actions/checkout@v2 59 | - uses: actions-rs/audit-check@v1 60 | with: 61 | token: ${{ secrets.GITHUB_TOKEN }} 62 | 63 | deadlinks: 64 | name: Deadlinks 65 | runs-on: ubuntu-latest 66 | 67 | steps: 68 | - name: Checkout sources 69 | uses: actions/checkout@v2 70 | 71 | - name: Install rust 72 | uses: actions-rs/toolchain@v1 73 | with: 74 | toolchain: stable 75 | profile: minimal 76 | override: true 77 | 78 | - name: Install deadlinks 79 | run: cargo install cargo-deadlinks 80 | 81 | - name: Run deadlinks 82 | run: | 83 | cargo doc --no-deps 84 | cargo deadlinks --dir target/doc/stdext 85 | 86 | test: 87 | name: Test 88 | runs-on: ubuntu-latest 89 | 90 | steps: 91 | - name: Checkout sources 92 | uses: actions/checkout@v2 93 | 94 | - name: Install rust 95 | uses: actions-rs/toolchain@v1 96 | with: 97 | toolchain: stable 98 | profile: minimal 99 | override: true 100 | 101 | - name: Build 102 | uses: actions-rs/cargo@v1 103 | with: 104 | command: build 105 | args: --examples --all 106 | 107 | - name: Test 108 | uses: actions-rs/cargo@v1 109 | with: 110 | command: test 111 | args: --all 112 | -------------------------------------------------------------------------------- /src/result.rs: -------------------------------------------------------------------------------- 1 | //! Extension traits for `std::Result`. 2 | 3 | /// Extension trait with useful methods for [`std::result::Result`]. 4 | /// 5 | /// [`std::result::Result`]: https://doc.rust-lang.org/std/result/enum.Result.html 6 | pub trait ResultExt { 7 | /// Combines `self` and another `Result`. 8 | /// 9 | /// If `self` is `Ok(s)` and `other` is `Ok(o)`, this method returns `Ok((s, o))`. 10 | /// Otherwise, if the `self` is `Ok(s)` and `other` is `Err(e)`, this method returns `Err(e)`. 11 | /// Otherwise, `self` is `Err(e)` and this method returns `Err(e)` (`other` is not taken into 12 | /// account, as in short circuit calculations). 13 | /// 14 | /// # Examples 15 | /// 16 | /// ``` 17 | /// use stdext::prelude::*; 18 | /// 19 | /// let x = Ok(1); 20 | /// let y = Ok("hi"); 21 | /// let z: Result = Err("error"); 22 | /// let z2: Result = Err("other_error"); 23 | /// 24 | /// assert_eq!(x.combine(y), Ok((1, "hi"))); 25 | /// assert_eq!(x.combine(z), Err("error")); 26 | /// assert_eq!(z.combine(z2), Err("error")); 27 | /// ``` 28 | fn combine(self, other: Result) -> Result<(T, U), E>; 29 | 30 | /// Combines `self` and another `Result` with function `f`. 31 | /// 32 | /// If `self` is `Ok(s)` and `other` is `Ok(o)`, this method returns `Ok(f(s, o))`. 33 | /// Otherwise, if the `self` is `Ok(s)` and `other` is `Err(e)`, this method returns `Err(e)`. 34 | /// Otherwise, `self` is `Err(e)` and this method returns `Err(e)` (`other` is not taken into 35 | /// account, as in short circuit calculations). 36 | /// 37 | /// # Examples 38 | /// 39 | /// ``` 40 | /// use stdext::prelude::*; 41 | /// 42 | /// let x = Ok(1); 43 | /// let y = Ok(2); 44 | /// let z: Result = Err("error"); 45 | /// let z2: Result = Err("other_error"); 46 | /// 47 | /// assert_eq!(x.combine_with(y, |l, r| l + r), Ok(3)); 48 | /// assert_eq!(x.combine_with(z, |l, r| l + r), Err("error")); 49 | /// assert_eq!(z.combine_with(z2, |l, r| l + r), Err("error")); 50 | /// ``` 51 | /// 52 | /// [`zip_with`]: https://doc.rust-lang.org/std/Result/enum.Result.html#method.zip_with 53 | fn combine_with(self, other: Result, f: F) -> Result 54 | where 55 | F: FnOnce(T, U) -> R; 56 | } 57 | 58 | impl ResultExt for Result { 59 | fn combine(self, other: Result) -> Result<(T, U), E> { 60 | match (self, other) { 61 | (Ok(left), Ok(right)) => Ok((left, right)), 62 | (Ok(_), Err(err)) => Err(err), 63 | (Err(err), _) => Err(err), 64 | } 65 | } 66 | 67 | fn combine_with(self, other: Result, f: F) -> Result 68 | where 69 | F: FnOnce(T, U) -> R, 70 | { 71 | self.combine(other).map(|(l, r)| f(l, r)) 72 | } 73 | } 74 | 75 | #[cfg(test)] 76 | mod tests { 77 | use super::*; 78 | 79 | #[test] 80 | fn combine() { 81 | // Test vector of (left, right, expected) values. 82 | let test_vector = vec![ 83 | (Ok(1), Ok(2), Ok((1, 2))), 84 | (Ok(1), Err("right"), Err("right")), 85 | (Err("left"), Ok(2), Err("left")), 86 | (Err("left"), Err("right"), Err("left")), 87 | ]; 88 | 89 | for (left, right, expected) in test_vector { 90 | assert_eq!(left.combine(right), expected); 91 | } 92 | } 93 | 94 | #[test] 95 | fn combine_with() { 96 | fn f(l: i32, r: i32) -> i32 { 97 | l + r 98 | } 99 | 100 | // Test vector of (left, right, expected) values. 101 | let test_vector = vec![ 102 | (Ok(1), Ok(2), Ok(3)), 103 | (Ok(1), Err("right"), Err("right")), 104 | (Err("left"), Ok(2), Err("left")), 105 | (Err("left"), Err("right"), Err("left")), 106 | ]; 107 | 108 | for (left, right, expected) in test_vector { 109 | assert_eq!(left.combine_with(right, f), expected); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/option.rs: -------------------------------------------------------------------------------- 1 | //! Extension traits for `std::Option`. 2 | 3 | /// Extension trait with useful methods for [`std::option::Option`]. 4 | /// 5 | /// [`std::time::Option`]: https://doc.rust-lang.org/std/option/enum.Option.html 6 | pub trait OptionExt { 7 | /// Combines `self` and another `Option`. 8 | /// 9 | /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some((s, o))`. 10 | /// Otherwise, `None` is returned. 11 | /// 12 | /// **Note:** `std::Option` already provides a [`zip`] method which serves exact same purpose, 13 | /// but currently it's unstable. Once it's stabilized, this method will be marked as deprecated 14 | /// with a prompt to use the stanard method instead. 15 | /// 16 | /// # Examples 17 | /// 18 | /// ``` 19 | /// use stdext::prelude::*; 20 | /// 21 | /// let x = Some(1); 22 | /// let y = Some("hi"); 23 | /// let z = None::; 24 | /// 25 | /// assert_eq!(x.combine(y), Some((1, "hi"))); 26 | /// assert_eq!(x.combine(z), None); 27 | /// ``` 28 | /// 29 | /// [`zip`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.zip 30 | fn combine(self, other: Option) -> Option<(T, U)>; 31 | 32 | /// Combines `self` and another `Option` with function `f`. 33 | /// 34 | /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some(f(s, o))`. 35 | /// Otherwise, `None` is returned. 36 | /// 37 | /// **Note:** `std::Option` already provides a [`zip_with`] method which serves exact same purpose, 38 | /// but currently it's unstable. Once it's stabilized, this method will be marked as deprecated 39 | /// with a prompt to use the stanard method instead. 40 | /// 41 | /// # Examples 42 | /// 43 | /// ``` 44 | /// use stdext::prelude::*; 45 | /// 46 | /// #[derive(Debug, PartialEq)] 47 | /// struct Point { 48 | /// x: f64, 49 | /// y: f64, 50 | /// } 51 | /// 52 | /// impl Point { 53 | /// fn new(x: f64, y: f64) -> Self { 54 | /// Self { x, y } 55 | /// } 56 | /// } 57 | /// 58 | /// let x = Some(17.5); 59 | /// let y = Some(42.7); 60 | /// 61 | /// assert_eq!(x.combine_with(y, Point::new), Some(Point { x: 17.5, y: 42.7 })); 62 | /// assert_eq!(x.combine_with(None, Point::new), None); 63 | /// ``` 64 | /// 65 | /// [`zip_with`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.zip_with 66 | fn combine_with(self, other: Option, f: F) -> Option 67 | where 68 | F: FnOnce(T, U) -> R; 69 | } 70 | 71 | impl OptionExt for Option { 72 | fn combine(self, other: Option) -> Option<(T, U)> { 73 | match (self, other) { 74 | (Some(left), Some(right)) => Some((left, right)), 75 | _ => None, 76 | } 77 | } 78 | 79 | fn combine_with(self, other: Option, f: F) -> Option 80 | where 81 | F: FnOnce(T, U) -> R, 82 | { 83 | self.combine(other).map(|(l, r)| f(l, r)) 84 | } 85 | } 86 | 87 | #[cfg(test)] 88 | mod tests { 89 | use super::*; 90 | 91 | #[test] 92 | fn combine() { 93 | // Test vector of (left, right, expected) values. 94 | let test_vector = vec![ 95 | (Some(1), Some(2), Some((1, 2))), 96 | (Some(1), None, None), 97 | (None, Some(2), None), 98 | (None, None, None), 99 | ]; 100 | 101 | for (left, right, expected) in test_vector { 102 | assert_eq!(left.combine(right), expected); 103 | } 104 | } 105 | 106 | #[test] 107 | fn combine_with() { 108 | fn f(l: i32, r: i32) -> i32 { 109 | l + r 110 | } 111 | 112 | // Test vector of (left, right, expected) values. 113 | let test_vector = vec![ 114 | (Some(1), Some(2), Some(3)), 115 | (Some(1), None, None), 116 | (None, Some(2), None), 117 | (None, None, None), 118 | ]; 119 | 120 | for (left, right, expected) in test_vector { 121 | assert_eq!(left.combine_with(right, f), expected); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `std` extensions 2 | 3 | **Status:** 4 | [![CI](https://github.com/popzxc/stdext-rs/workflows/CI/badge.svg)](https://github.com/popzxc/stdext-rs/actions) 5 | 6 | **Project info:** 7 | [![Docs.rs](https://docs.rs/stdext/badge.svg)](https://docs.rs/stdext) 8 | [![Latest Version](https://img.shields.io/crates/v/stdext.svg)](https://crates.io/crates/stdext) 9 | [![License](https://img.shields.io/github/license/popzxc/stdext-rs.svg)](https://github.com/popzxc/stdext-rs) 10 | ![Rust 1.53+ required](https://img.shields.io/badge/rust-1.53+-blue.svg?label=Rust) 11 | 12 | Additional features for the Rust standard library. 13 | 14 | ## Description 15 | 16 | This crate contains enhancements to the Rust standard library structures, useful for 17 | broad audience, but not yet implemented (or stabilized) in `std`. 18 | 19 | Crate is designed to be lightweight (no external dependencies!) and provide essential 20 | functionality which possible can get to the `std` some day. 21 | 22 | The minimal supported Rust version for release 0.3 is 1.53. However, if you need to use 23 | this crate with an older version of the compiler, check out release 0.2; there is a good 24 | chance that it will suit your needs. 25 | 26 | ## Highlights 27 | 28 | - `Integer` super-trait that is implemented for all the built-in integers 29 | and reflects the common part of their interfaces. 30 | 31 | ```rust 32 | use stdext::prelude::*; 33 | 34 | fn accepts_any_integer(a: I, b: I) { 35 | println!("{}", (a + b).count_ones()); 36 | } 37 | ``` 38 | 39 | - Safe conversions from floating numbers to integers. 40 | 41 | ```rust 42 | use stdext::prelude::FloatConvert; 43 | 44 | let valid: Option = 10.5f32.checked_floor(); 45 | let too_big: Option = 256f32.checked_floor(); 46 | let nan: Option = f32::NAN.checked_floor(); 47 | 48 | assert_eq!(valid, Some(10u8)); 49 | assert_eq!(too_big, None); 50 | assert_eq!(nan, None); 51 | ``` 52 | 53 | - Convenient builder methods for **`Duration`**: 54 | 55 | ```rust 56 | use std::time::Duration; 57 | use stdext::prelude::*; 58 | 59 | let duration = Duration::from_minutes(1).add_secs(5).add_micros(100); 60 | assert_eq!(duration, Duration::new(65, 100_000)); 61 | ``` 62 | 63 | - Panicking version for **`RwLock::read`**, **`RwLock::write`** and **`Mutex::lock`** (for 64 | fellows who don't really handle the lock poisoning): 65 | 66 | ```rust 67 | use std::sync::{Arc, RwLock}; 68 | use stdext::prelude::*; 69 | 70 | let lock = Arc::new(RwLock::new(1)); 71 | { 72 | let mut n = lock.force_write(); // Instead of `.write().unwrap()`. 73 | *n = 2; 74 | } 75 | let n = lock.force_read(); 76 | assert_eq!(*n, 2); 77 | ``` 78 | 79 | - **`Result::combine`** and **`Option::combine`** to zip pairs of objects: 80 | 81 | ```rust 82 | use stdext::prelude::*; 83 | 84 | let x = Some(1); 85 | let y = Some("hi"); 86 | let z = None::; 87 | 88 | assert_eq!(x.combine(y), Some((1, "hi"))); 89 | assert_eq!(x.combine(z), None); 90 | 91 | let x = Ok(1); 92 | let y = Ok("hi"); 93 | let z: Result = Err("error"); 94 | let z2: Result = Err("other_error"); 95 | 96 | assert_eq!(x.combine(y), Ok((1, "hi"))); 97 | assert_eq!(x.combine(z), Err("error")); 98 | assert_eq!(z.combine(z2), Err("error")); 99 | ``` 100 | 101 | - New handy macros (mostly for development purposes): 102 | 103 | ```rust 104 | use stdext::{compile_warning, debug_name, function_name}; 105 | 106 | fn sample_function() { 107 | println!("This function is called {}", function_name!()); 108 | println!("You can also found it here:", debug_name!()); 109 | 110 | compile_warning!("This function must do something else..."); 111 | } 112 | ``` 113 | 114 | ...and other features. For a full list, check out the [crate documentation](https://docs.rs/stdext/). 115 | 116 | ## Motivation 117 | 118 | Standard library is great, and it becomes even better through time. However, a time gap between proposing 119 | a new feature and getting it stabilized is way too big. 120 | 121 | This crate, however, can be updated quickly and the feature will be usable on the stable Rust soon after 122 | implementation. 123 | 124 | ## Contributing 125 | 126 | If you want to contribute to this project, please read the [contributing guide](CONTRIBUTING.md). 127 | 128 | ## LICENSE 129 | 130 | `stdext` library is licensed under the MIT License. See [LICENSE](LICENSE) for details. 131 | -------------------------------------------------------------------------------- /src/vec.rs: -------------------------------------------------------------------------------- 1 | //! Extension traits for `std::Vec`. 2 | 3 | /// Extension trait with useful methods for [`std::vec::Vec`]. 4 | /// 5 | /// [`std::vec::Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html 6 | pub trait VecExt { 7 | /// Resizes the `Vec` in-place if the provided `new_len` is **greater** than 8 | /// the current `Vec` length. 9 | /// 10 | /// In simple words, this method only make vector bigger, but not smaller. 11 | /// Calling this method with a length smaller or equal to the current length will 12 | /// do nothing. 13 | /// 14 | /// This method uses a closure to create new values on every push. If 15 | /// you'd rather [`Clone`] a given value, use [`resize_up`]. If you want 16 | /// to use the [`Default`] trait to generate values, you can pass 17 | /// [`Default::default()`] as the second argument. 18 | /// 19 | /// # Examples 20 | /// 21 | /// ``` 22 | /// use stdext::prelude::*; 23 | /// 24 | /// let mut vec = vec![1, 2, 3]; 25 | /// vec.resize_up_with(5, Default::default); 26 | /// assert_eq!(vec, [1, 2, 3, 0, 0]); 27 | /// 28 | /// let mut vec = vec![]; 29 | /// let mut p = 1; 30 | /// vec.resize_up_with(4, || { p *= 2; p }); 31 | /// assert_eq!(vec, [2, 4, 8, 16]); 32 | /// 33 | /// let mut vec = vec![1, 2, 3]; 34 | /// vec.resize_up_with(1, Default::default); 35 | /// assert_eq!(vec, [1, 2, 3]); // Resizing to smaller size does nothing. 36 | /// ``` 37 | /// 38 | /// [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html 39 | /// [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html 40 | /// [`Default::default()`]: https://doc.rust-lang.org/std/default/trait.Default.html#tymethod.default 41 | /// [`resize_up`]: ./trait.VecExtClone.html#tymethod.resize_up 42 | fn resize_up_with(&mut self, new_len: usize, f: F) 43 | where 44 | F: FnMut() -> T; 45 | 46 | /// Removes the first instance of `item` from the vector if the item exists. 47 | /// 48 | /// Based on the unstable vec_remove_item feature, which has been deprecated and will be removed. 49 | /// 50 | /// # Examples 51 | /// 52 | /// ``` 53 | /// use stdext::prelude::*; 54 | /// let mut vec = vec![1, 2, 3, 1]; 55 | /// 56 | /// vec.remove_item(&1); 57 | /// 58 | /// assert_eq!(vec, vec![2, 3, 1]); 59 | /// ``` 60 | fn remove_item(&mut self, item: &V) -> Option 61 | where 62 | T: PartialEq; 63 | } 64 | 65 | /// Extension trait with useful methods for [`std::vec::Vec`]. 66 | /// 67 | /// This trait contains functions that require `T` to implement `Clone` trait. 68 | /// 69 | /// [`std::vec::Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html 70 | pub trait VecExtClone { 71 | /// Resizes the `Vec` in-place if the provided `new_len` is **greater** than 72 | /// the current `Vec` length. 73 | /// 74 | /// In simple words, this method only make vector bigger, but not smaller. 75 | /// Calling this method with a length smaller or equal to the current length will 76 | /// do nothing. 77 | /// 78 | /// This method requires `T` to implement [`Clone`], 79 | /// in order to be able to clone the passed value. 80 | /// If you need more flexibility (or want to rely on [`Default`] instead of 81 | /// [`Clone`]), use [`resize_up_with`]. 82 | /// 83 | /// # Examples 84 | /// 85 | /// ``` 86 | /// use stdext::prelude::*; 87 | /// 88 | /// let mut vec = vec!["hello"]; 89 | /// vec.resize_up(3, "world"); 90 | /// assert_eq!(vec, ["hello", "world", "world"]); 91 | /// 92 | /// let mut vec = vec![1, 2, 3, 4]; 93 | /// vec.resize_up(2, 0); 94 | /// assert_eq!(vec, [1, 2, 3, 4]); // Resizing to smaller size does nothing. 95 | /// ``` 96 | /// 97 | /// [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html 98 | /// [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html 99 | /// [`resize_up_with`]: ./trait.VecExt.html#tymethod.resize_up_with 100 | fn resize_up(&mut self, new_len: usize, value: T); 101 | } 102 | 103 | impl VecExt for Vec { 104 | fn resize_up_with(&mut self, new_len: usize, f: F) 105 | where 106 | F: FnMut() -> T, 107 | { 108 | if self.len() < new_len { 109 | self.resize_with(new_len, f); 110 | } 111 | } 112 | 113 | fn remove_item(&mut self, item: &V) -> Option 114 | where 115 | T: PartialEq, 116 | { 117 | let pos = self.iter().position(|x| *x == *item)?; 118 | Some(self.remove(pos)) 119 | } 120 | } 121 | 122 | impl VecExtClone for Vec { 123 | fn resize_up(&mut self, new_len: usize, value: T) { 124 | if self.len() < new_len { 125 | self.resize(new_len, value); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Additional features for the Rust standard library. 2 | //! 3 | //! ## Description 4 | //! 5 | //! This crate contains enhancements to the Rust standard library types, useful for 6 | //! broad audience, but not yet implemented (or stabilized) in `std`. 7 | //! 8 | //! Crate is designed to be lightweight (no external dependencies!) and provide essential 9 | //! functionality which possible can get to the `std` some day. 10 | //! 11 | //! ## Extension traits 12 | //! 13 | //! All the new functionality the stanard library is added using extension traits. 14 | //! 15 | //! Below you can find the table of all the extension traits introduced by this crate: 16 | //! 17 | //! | `std` structure | extension traits 18 | //! | --- | --- 19 | //! | [`Vec`] | [`VecExt`] and [`VecExtClone`] 20 | //! | [`&str`] | [`StrExt`] 21 | //! | [`Option`] | [`OptionExt`] 22 | //! | [`Result`] | [`ResultExt`] 23 | //! | [`Duration`] | [`DurationExt`] 24 | //! | [`RwLock`] | [`RwLockExt`] 25 | //! | [`Mutex`] | [`MutexExt`] 26 | //! | [`f32`] and [`f64`] | [`FloatConvert`] 27 | //! 28 | //! [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html 29 | //! [`&str`]: https://doc.rust-lang.org/std/primitive.str.html 30 | //! [`Option`]: https://doc.rust-lang.org/std/option/enum.Option.html 31 | //! [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html 32 | //! [`Duration`]: https://doc.rust-lang.org/std/time/struct.Duration.html 33 | //! [`RwLock`]: https://doc.rust-lang.org/std/sync/struct.RwLock.html 34 | //! [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html 35 | //! 36 | //! [`VecExt`]: vec/trait.VecExt.html 37 | //! [`VecExtClone`]: vec/trait.VecExtClone.html 38 | //! [`StrExt`]: str/trait.StrExt.html 39 | //! [`OptionExt`]: option/trait.OptionExt.html 40 | //! [`ResultExt`]: result/trait.ResultExt.html 41 | //! [`DurationExt`]: duration/trait.DurationExt.html 42 | //! [`RwLockExt`]: sync/rw_lock/trait.RwLockExt.html 43 | //! [`MutexExt`]: sync/mutex/trait.MutexExt.html 44 | //! [`FloatConvert`]: num/float_convert/trait.FloatConvert.html 45 | //! 46 | //! ## Integer super-trait 47 | //! 48 | //! While all built-in integer types have mostly the same interface, it's not backed by any trait, 49 | //! which makes it impossible to write a function that will accept any built-in integer. 50 | //! 51 | //! [`Integer`] trait solves that problem by reflecting the common interface of all the built-in integers. 52 | //! 53 | //! [`Integer`]: num/integer/trait.Integer.html 54 | //! 55 | //! ## Macros 56 | //! 57 | //! Another group of extensions in `stdext` is new macros: 58 | //! 59 | //! - [`compile_warning`] for spawning a user-defined compilation warnings. 60 | //! - [`function_name`] for getting an enclosing function name. 61 | //! - [`debug_name`] for getting a helpful string for debug. 62 | //! 63 | //! [`compile_warning`]: ./macro.compile_warning.html 64 | //! [`function_name`]: ./macro.function_name.html 65 | //! [`debug_name`]: ./macro.debug_name.html 66 | //! 67 | //! ## Highlights 68 | //! 69 | //! - Convenient builder methods for **`Duration`**: 70 | //! 71 | //! ```rust 72 | //! use std::time::Duration; 73 | //! use stdext::prelude::*; 74 | //! 75 | //! let duration = Duration::from_minutes(1).add_secs(5).add_micros(100); 76 | //! assert_eq!(duration, Duration::new(65, 100_000)); 77 | //! ``` 78 | //! 79 | //! - Panicking version for **`RwLock::read`**, **`RwLock::write`** and **`Mutex::lock`** (for 80 | //! fellows who don't really handle the lock poisoning): 81 | //! 82 | //! ```rust 83 | //! use std::sync::{Arc, RwLock}; 84 | //! use stdext::prelude::*; 85 | //! 86 | //! let lock = Arc::new(RwLock::new(1)); 87 | //! { 88 | //! let mut n = lock.force_write(); // Instead of `.write().unwrap()`. 89 | //! *n = 2; 90 | //! } 91 | //! let n = lock.force_read(); 92 | //! assert_eq!(*n, 2); 93 | //! ``` 94 | //! 95 | //! - **`Result::combine`** and **`Option::combine`** to zip pairs of objects: 96 | //! 97 | //! ```rust 98 | //! use stdext::prelude::*; 99 | //! 100 | //! let x = Some(1); 101 | //! let y = Some("hi"); 102 | //! let z = None::; 103 | //! 104 | //! assert_eq!(x.combine(y), Some((1, "hi"))); 105 | //! assert_eq!(x.combine(z), None); 106 | //! 107 | //! let x = Ok(1); 108 | //! let y = Ok("hi"); 109 | //! let z: Result = Err("error"); 110 | //! let z2: Result = Err("other_error"); 111 | //! 112 | //! assert_eq!(x.combine(y), Ok((1, "hi"))); 113 | //! assert_eq!(x.combine(z), Err("error")); 114 | //! assert_eq!(z.combine(z2), Err("error")); 115 | //! ``` 116 | //! 117 | //! - New handy macros (mostly for development purposes): 118 | //! 119 | //! ```rust 120 | //! use stdext::{compile_warning, debug_name, function_name}; 121 | //! 122 | //! fn sample_function() { 123 | //! println!("This function is called {}", function_name!()); 124 | //! println!("You can also found it here: {}", debug_name!()); 125 | //! 126 | //! compile_warning!("This function must do something else..."); 127 | //! } 128 | //! ``` 129 | 130 | #![warn(missing_docs, unreachable_pub)] 131 | 132 | pub mod duration; 133 | #[macro_use] 134 | pub mod macros; 135 | pub mod default; 136 | pub mod num; 137 | pub mod option; 138 | pub mod result; 139 | pub mod str; 140 | pub mod sync; 141 | pub mod vec; 142 | 143 | /// A "prelude" module which re-exports all the extension traits for the simple library usage. 144 | pub mod prelude { 145 | pub use crate::{ 146 | default::*, 147 | duration::*, 148 | num::{float_convert::*, integer::*}, 149 | option::*, 150 | result::*, 151 | str::*, 152 | sync::{mutex::*, rw_lock::*}, 153 | vec::*, 154 | }; 155 | } 156 | -------------------------------------------------------------------------------- /src/num/float_convert.rs: -------------------------------------------------------------------------------- 1 | //! Extensions for the built-in floating point types. 2 | 3 | /// Set of methods to safely convert floating number into an integer. 4 | /// 5 | /// Currently, the main way to do so is to use [`as`][as_convert] conversion. 6 | /// However, such an approach may not be suitable if saturating conversion is 7 | /// not desired. 8 | /// 9 | /// However, saturating conversion is also provided as an expicit alternative 10 | /// to `as` conversion (e.g. to avoid warnings when [`clippy::as_conversions`][clippy_as] 11 | /// lint is enabled). 12 | /// 13 | /// [as_convert]: https://doc.rust-lang.org/nomicon/casts.html 14 | /// [clippy_as]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions 15 | /// 16 | /// ## Implementors 17 | /// 18 | /// This trait is implemented for both [`f32`] and [`f64`]. 19 | pub trait FloatConvert: Sized { 20 | /// Floors the floating number and attempts to convert it into an integer. 21 | /// See [`f32::floor`] for description of flooring logic. 22 | /// 23 | /// Returns `None` if the value will not fit into the integer range or value 24 | /// is not a number. 25 | /// 26 | /// ## Examples 27 | /// 28 | /// ```rust 29 | /// # use stdext::prelude::FloatConvert; 30 | /// 31 | /// let valid: Option = 10.5f32.checked_floor(); 32 | /// let too_big: Option = 256f32.checked_floor(); 33 | /// let nan: Option = f32::NAN.checked_floor(); 34 | /// 35 | /// assert_eq!(valid, Some(10u8)); 36 | /// assert_eq!(too_big, None); 37 | /// assert_eq!(nan, None); 38 | /// ``` 39 | #[must_use = "this returns the result of the operation, without modifying the original"] 40 | fn checked_floor(self) -> Option; 41 | 42 | /// Ceils the floating number and attempts to convert it into an integer. 43 | /// See [`f32::ceil`] for description of ceiling logic. 44 | /// 45 | /// Returns `None` if the value will not fit into the integer range or value 46 | /// is not a number. 47 | /// 48 | /// ## Examples 49 | /// 50 | /// ```rust 51 | /// # use stdext::prelude::FloatConvert; 52 | /// 53 | /// let valid: Option = 10.5f32.checked_ceil(); 54 | /// let too_big: Option = 256f32.checked_ceil(); 55 | /// let nan: Option = f32::NAN.checked_ceil(); 56 | /// 57 | /// assert_eq!(valid, Some(11u8)); 58 | /// assert_eq!(too_big, None); 59 | /// assert_eq!(nan, None); 60 | /// ``` 61 | #[must_use = "this returns the result of the operation, without modifying the original"] 62 | fn checked_ceil(self) -> Option; 63 | 64 | /// Rounds the floating number and attempts to convert it into an integer. 65 | /// See [`f32::round`] for description of rounding logic. 66 | /// 67 | /// Returns `None` if the value will not fit into the integer range or value 68 | /// is not a number. 69 | /// 70 | /// ## Examples 71 | /// 72 | /// ```rust 73 | /// # use stdext::prelude::FloatConvert; 74 | /// 75 | /// let valid: Option = 10.51f32.checked_round(); // Will be rounded up. 76 | /// let too_big: Option = 256f32.checked_round(); 77 | /// let nan: Option = f32::NAN.checked_round(); 78 | /// 79 | /// assert_eq!(valid, Some(11u8)); 80 | /// assert_eq!(too_big, None); 81 | /// assert_eq!(nan, None); 82 | /// ``` 83 | #[must_use = "this returns the result of the operation, without modifying the original"] 84 | fn checked_round(self) -> Option; 85 | 86 | /// Behaves the same as `number.floor() as `. 87 | /// See [`f32::floor`] for description of flooring logic. 88 | #[must_use = "this returns the result of the operation, without modifying the original"] 89 | fn saturated_floor(self) -> Int; 90 | 91 | /// Behaves the same as `number.ceil() as `. 92 | /// See [`f32::ceil`] for description of flooring logic. 93 | #[must_use = "this returns the result of the operation, without modifying the original"] 94 | fn saturated_ceil(self) -> Int; 95 | 96 | /// Behaves the same as `number.round() as `. 97 | /// See [`f32::round`] for description of flooring logic. 98 | #[must_use = "this returns the result of the operation, without modifying the original"] 99 | fn saturated_round(self) -> Int; 100 | } 101 | 102 | macro_rules! checked_impl { 103 | ($val:ident.$fn:ident(), $int:ty) => {{ 104 | if $val.is_nan() || $val.is_infinite() { 105 | return None; 106 | } 107 | let converted = $val.$fn(); 108 | if <$int>::MIN as Self <= converted && converted <= <$int>::MAX as Self { 109 | Some(converted as $int) 110 | } else { 111 | None 112 | } 113 | }}; 114 | } 115 | 116 | macro_rules! saturated_impl { 117 | ($val:ident.$fn:ident(), $int:ty) => {{ 118 | $val.$fn() as $int 119 | }}; 120 | } 121 | 122 | macro_rules! impl_float_convert { 123 | ($float:ty, $($int:ty),+) => { 124 | $(impl FloatConvert<$int> for $float { 125 | fn checked_floor(self) -> Option<$int> { 126 | checked_impl!(self.floor(), $int) 127 | } 128 | 129 | fn checked_ceil(self) -> Option<$int> { 130 | checked_impl!(self.ceil(), $int) 131 | } 132 | 133 | fn checked_round(self) -> Option<$int> { 134 | checked_impl!(self.round(), $int) 135 | } 136 | 137 | fn saturated_floor(self) -> $int { 138 | saturated_impl!(self.floor(), $int) 139 | } 140 | 141 | fn saturated_ceil(self) -> $int { 142 | saturated_impl!(self.ceil(), $int) 143 | } 144 | 145 | fn saturated_round(self) -> $int { 146 | saturated_impl!(self.round(), $int) 147 | } 148 | })+ 149 | }; 150 | } 151 | 152 | impl_float_convert!(f32, u8, u16, u32, u64, u128); 153 | impl_float_convert!(f32, i8, i16, i32, i64, i128); 154 | impl_float_convert!(f32, usize, isize); 155 | 156 | impl_float_convert!(f64, u8, u16, u32, u64, u128); 157 | impl_float_convert!(f64, i8, i16, i32, i64, i128); 158 | impl_float_convert!(f64, usize, isize); 159 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | //! Various helper macros. 2 | 3 | /// `compile_warning` macro is a brother of [`std::compile_error`], 4 | /// which emits a compile-time warning with a provided message. 5 | /// 6 | /// This implemented through an existing `dead_code` warning, thus the 7 | /// output for the following example: 8 | /// 9 | /// ```rust 10 | /// # use stdext::compile_warning; 11 | /// compile_warning!("Sample user-defined warning!"); 12 | /// ``` 13 | /// 14 | /// may look as follows: 15 | /// 16 | /// ```text 17 | /// warning: constant item is never used: `WARNING` 18 | /// --> src/lib.rs:7:9 19 | /// | 20 | /// 7 | const WARNING: &str = $expr; 21 | /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 22 | /// ... 23 | /// 11 | compile_warning!("Sample user-defined warning!"); 24 | /// | ------------------------------------------------- in this macro invocation 25 | /// ``` 26 | /// 27 | /// Once [`proc_macro_diagnostics`] feature is stabilized, this macro will be replaced 28 | /// with a proper proc-macro-based implementation. 29 | /// 30 | /// This macro is intended to be used in the development process, as an alternative to the 31 | /// [`unimplemented`] macro which doesn't cause code to panic. 32 | /// 33 | /// [`std::compile_error`]: https://doc.rust-lang.org/std/macro.compile_error.html 34 | /// [`proc_macro_diagnostics`]: https://github.com/rust-lang/rust/issues/54140 35 | /// [`unimplemented`]: https://doc.rust-lang.org/std/macro.unimplemented.html 36 | #[macro_export] 37 | macro_rules! compile_warning { 38 | ($expr:expr) => { 39 | #[warn(dead_code)] 40 | const WARNING: &str = $expr; 41 | }; 42 | } 43 | 44 | /// This macro returns the name of the enclosing function. 45 | /// As the internal implementation is based on the [`std::any::type_name`], this macro derives 46 | /// all the limitations of this function. 47 | /// 48 | /// ## Examples 49 | /// 50 | /// ```rust 51 | /// mod bar { 52 | /// pub fn sample_function() { 53 | /// use stdext::function_name; 54 | /// assert!(function_name!().ends_with("bar::sample_function")); 55 | /// } 56 | /// } 57 | /// 58 | /// bar::sample_function(); 59 | /// ``` 60 | /// 61 | /// [`std::any::type_name`]: https://doc.rust-lang.org/std/any/fn.type_name.html 62 | #[macro_export] 63 | macro_rules! function_name { 64 | () => {{ 65 | // Okay, this is ugly, I get it. However, this is the best we can get on a stable rust. 66 | fn f() {} 67 | fn type_name_of(_: T) -> &'static str { 68 | std::any::type_name::() 69 | } 70 | let name = type_name_of(f); 71 | // `3` is the length of the `::f`. 72 | &name[..name.len() - 3] 73 | }}; 74 | } 75 | 76 | /// This macro returns the name of the enclosing function, line number and also filename. 77 | /// As the internal implementation is based on the [`std::any::type_name`], this macro derives 78 | /// all the limitations of this function. 79 | /// 80 | /// ## Examples 81 | /// 82 | /// ```rust 83 | /// mod bar { 84 | /// pub fn sample_function() { 85 | /// use stdext::debug_name; 86 | /// assert!(debug_name!().starts_with("src/macros.rs:8")); 87 | /// assert!(debug_name!().ends_with("bar::sample_function")); 88 | /// } 89 | /// } 90 | /// 91 | /// bar::sample_function(); 92 | /// ``` 93 | /// 94 | /// [`std::any::type_name`]: https://doc.rust-lang.org/std/any/fn.type_name.html 95 | #[macro_export] 96 | macro_rules! debug_name { 97 | () => {{ 98 | fn f() {} 99 | fn type_name_of(_: T) -> &'static str { 100 | std::any::type_name::() 101 | } 102 | let name = type_name_of(f); 103 | // `3` is the length of the `::f`. 104 | let trimmed_name = &name[..name.len() - 3]; 105 | let file = file!(); 106 | let line = line!(); 107 | format!("{file}:{line} at {trimmed_name}") 108 | }}; 109 | } 110 | 111 | /// Attempts to get variant from the enum variable. 112 | /// 113 | /// ## Examples 114 | /// 115 | /// ```rust 116 | /// # use stdext::try_match; 117 | /// 118 | /// #[derive(Debug, PartialEq)] 119 | /// enum Foo { 120 | /// Left(u16), 121 | /// Right(&'static str), 122 | /// } 123 | /// 124 | /// assert_eq!(try_match!(Foo::Left(18), Foo::Left), Ok(18)); 125 | /// assert_eq!( 126 | /// try_match!(Foo::Right("nope"), Foo::Left), 127 | /// Err(Foo::Right("nope")) 128 | /// ); 129 | /// ``` 130 | #[macro_export] 131 | macro_rules! try_match { 132 | ($var:expr, $variant:path) => { 133 | if let $variant(x) = $var { 134 | Ok(x) 135 | } else { 136 | Err($var) 137 | } 138 | }; 139 | } 140 | 141 | /// Similar to [`try_match`] but additionally unwraps the result. 142 | /// 143 | /// ## Panics 144 | /// 145 | /// Panics if expression didn't match the provided path. 146 | /// 147 | /// ## Examples 148 | /// 149 | /// ```rust 150 | /// # use stdext::unwrap_match; 151 | /// 152 | /// #[derive(Debug, PartialEq)] 153 | /// enum Foo { 154 | /// Left(u16), 155 | /// Right(&'static str), 156 | /// } 157 | /// 158 | /// assert_eq!(unwrap_match!(Foo::Left(18), Foo::Left), 18); 159 | /// ``` 160 | /// 161 | /// The following example will panic: 162 | /// 163 | /// ```should_panic 164 | /// # use stdext::unwrap_match; 165 | /// # #[derive(Debug, PartialEq)] 166 | /// # enum Foo { 167 | /// # Left(u16), 168 | /// # Right(&'static str), 169 | /// # } 170 | /// assert_eq!(unwrap_match!(Foo::Right("nope"), Foo::Left), 18); 171 | /// ``` 172 | #[macro_export] 173 | macro_rules! unwrap_match { 174 | ($var:expr, $variant:path) => { 175 | $crate::try_match!($var, $variant).unwrap() 176 | }; 177 | } 178 | 179 | /// Checks whether supplied [`Result`] variable is `Ok` 180 | /// and if so, returns it. 181 | /// 182 | /// If variant is an `Err`, macro evaluates to the contents of the `Err` 183 | /// variant. 184 | /// 185 | /// This macro supports two forms: 186 | /// - `return_ok!(Ok(42));` - will return `Ok(42)`. 187 | /// - `return_ok!(inner Ok(42));` - will return just `42`. 188 | /// 189 | /// ## Examples 190 | /// 191 | /// ```rust 192 | /// # use stdext::return_ok; 193 | /// 194 | /// fn choose_one(left: Result, right: Result) -> Result { 195 | /// return_ok!(left); 196 | /// return_ok!(right); 197 | /// Err(()) 198 | /// } 199 | /// 200 | /// fn choose_one_inner(left: Result, right: Result) -> u8 { 201 | /// return_ok!(inner left); 202 | /// return_ok!(inner right); 203 | /// panic!("Both variables are bad") 204 | /// } 205 | /// 206 | /// assert_eq!(choose_one(Err(()), Ok(10)), Ok(10)); 207 | /// assert_eq!(choose_one_inner(Ok(1), Err(())), 1); 208 | /// ``` 209 | #[macro_export] 210 | macro_rules! return_ok { 211 | ($var:expr) => { 212 | match $var { 213 | Ok(val) => return Ok(val), 214 | Err(err) => err, 215 | } 216 | }; 217 | (inner $var:expr) => { 218 | match $var { 219 | Ok(val) => return val, 220 | Err(err) => err, 221 | } 222 | }; 223 | } 224 | 225 | /// Checks whether supplied [`Option`] variable is `Some` 226 | /// and if so, returns it. 227 | /// 228 | /// If variant is an `None`, nothing happens. 229 | /// 230 | /// This macro supports two forms: 231 | /// - `return_some!(Some(42));` - will return `Some(42)`. 232 | /// - `return_some!(inner Some(42));` - will return just `42`. 233 | /// 234 | /// ## Examples 235 | /// 236 | /// ```rust 237 | /// # use stdext::return_some; 238 | /// 239 | /// fn choose_one(left: Option, right: Option) -> Option { 240 | /// return_some!(left); 241 | /// return_some!(right); 242 | /// None 243 | /// } 244 | /// 245 | /// fn choose_one_inner(left: Option, right: Option) -> u8 { 246 | /// return_some!(inner left); 247 | /// return_some!(inner right); 248 | /// panic!("Both variables are bad") 249 | /// } 250 | /// 251 | /// assert_eq!(choose_one(None, Some(10)), Some(10)); 252 | /// assert_eq!(choose_one_inner(Some(1), None), 1); 253 | /// ``` 254 | #[macro_export] 255 | macro_rules! return_some { 256 | ($var:expr) => { 257 | match $var { 258 | Some(val) => return Some(val), 259 | None => {} 260 | } 261 | }; 262 | (inner $var:expr) => { 263 | match $var { 264 | Some(val) => return val, 265 | None => {} 266 | } 267 | }; 268 | } 269 | -------------------------------------------------------------------------------- /src/duration.rs: -------------------------------------------------------------------------------- 1 | //! Extension traits for `std::time::Duration`. 2 | 3 | use std::time::Duration; 4 | 5 | const SECS_IN_MIN: u64 = 60; 6 | const SECS_IN_HOUR: u64 = 3600; 7 | const SECS_IN_DAY: u64 = 3600 * 24; 8 | 9 | /// Extension trait with useful methods for [`std::time::Duration`]. 10 | /// 11 | /// [`std::time::Duration`]: https://doc.rust-lang.org/std/time/struct.Duration.html 12 | pub trait DurationExt { 13 | /// Creates a new `Duration` from the specified number of minutes. 14 | /// 15 | /// # Examples 16 | /// 17 | /// ``` 18 | /// use std::time::Duration; 19 | /// use stdext::prelude::*; 20 | /// 21 | /// let duration = Duration::from_minutes(1); 22 | /// 23 | /// assert_eq!(duration, Duration::from_secs(60)); 24 | /// ``` 25 | /// 26 | /// # Panics 27 | /// 28 | /// Panics if the total amount of seconds exceeds the `u64` type range. 29 | fn from_minutes(minutes: u64) -> Duration; 30 | 31 | /// Creates a new `Duration` from the specified number of hours. 32 | /// 33 | /// # Examples 34 | /// 35 | /// ``` 36 | /// use std::time::Duration; 37 | /// use stdext::prelude::*; 38 | /// 39 | /// let duration = Duration::from_hours(1); 40 | /// 41 | /// assert_eq!(duration, Duration::from_secs(3600)); 42 | /// ``` 43 | /// 44 | /// # Panics 45 | /// 46 | /// Panics if the total amount of seconds exceeds the `u64` type range. 47 | fn from_hours(hours: u64) -> Duration; 48 | 49 | /// Creates a new `Duration` from the specified number of hours. 50 | /// 51 | /// # Examples 52 | /// 53 | /// ``` 54 | /// use std::time::Duration; 55 | /// use stdext::prelude::*; 56 | /// 57 | /// let duration = Duration::from_days(1); 58 | /// 59 | /// assert_eq!(duration, Duration::from_secs(3600 * 24)); 60 | /// ``` 61 | /// 62 | /// # Panics 63 | /// 64 | /// Panics if the total amount of seconds exceeds the `u64` type range. 65 | fn from_days(days: u64) -> Duration; 66 | 67 | /// Adds the specified amount of nanoseconds to the `Duration` object. 68 | /// 69 | /// # Examples 70 | /// 71 | /// ``` 72 | /// use std::time::Duration; 73 | /// use stdext::prelude::*; 74 | /// 75 | /// let duration = Duration::default().add_nanos(1); 76 | /// 77 | /// assert_eq!(duration, Duration::default() + Duration::from_nanos(1)); 78 | /// ``` 79 | fn add_nanos(self, nanos: u64) -> Duration; 80 | 81 | /// Adds the specified amount of microseconds to the `Duration` object. 82 | /// 83 | /// # Examples 84 | /// 85 | /// ``` 86 | /// use std::time::Duration; 87 | /// use stdext::prelude::*; 88 | /// 89 | /// let duration = Duration::default().add_micros(1); 90 | /// 91 | /// assert_eq!(duration, Duration::default() + Duration::from_micros(1)); 92 | /// ``` 93 | fn add_micros(self, micros: u64) -> Duration; 94 | 95 | /// Adds the specified amount of milliseconds to the `Duration` object. 96 | /// 97 | /// # Examples 98 | /// 99 | /// ``` 100 | /// use std::time::Duration; 101 | /// use stdext::prelude::*; 102 | /// 103 | /// let duration = Duration::default().add_millis(1); 104 | /// 105 | /// assert_eq!(duration, Duration::default() + Duration::from_millis(1)); 106 | /// ``` 107 | fn add_millis(self, millis: u64) -> Duration; 108 | 109 | /// Adds the specified amount of seconds to the `Duration` object. 110 | /// 111 | /// # Examples 112 | /// 113 | /// ``` 114 | /// use std::time::Duration; 115 | /// use stdext::prelude::*; 116 | /// 117 | /// let duration = Duration::default().add_secs(1); 118 | /// 119 | /// assert_eq!(duration, Duration::default() + Duration::from_secs(1)); 120 | /// ``` 121 | fn add_secs(self, seconds: u64) -> Duration; 122 | 123 | /// Adds the specified amount of minutes to the `Duration` object. 124 | /// 125 | /// # Examples 126 | /// 127 | /// ``` 128 | /// use std::time::Duration; 129 | /// use stdext::prelude::*; 130 | /// 131 | /// let duration = Duration::default().add_minutes(1); 132 | /// 133 | /// assert_eq!(duration, Duration::default() + Duration::from_minutes(1)); 134 | /// ``` 135 | fn add_minutes(self, minutes: u64) -> Duration; 136 | 137 | /// Adds the specified amount of hours to the `Duration` object. 138 | /// 139 | /// # Examples 140 | /// 141 | /// ``` 142 | /// use std::time::Duration; 143 | /// use stdext::prelude::*; 144 | /// 145 | /// let duration = Duration::default().add_hours(1); 146 | /// 147 | /// assert_eq!(duration, Duration::default() + Duration::from_hours(1)); 148 | /// ``` 149 | fn add_hours(self, hours: u64) -> Duration; 150 | 151 | /// Adds the specified amount of days to the `Duration` object. 152 | /// 153 | /// # Examples 154 | /// 155 | /// ``` 156 | /// use std::time::Duration; 157 | /// use stdext::prelude::*; 158 | /// 159 | /// let duration = Duration::default().add_days(1); 160 | /// 161 | /// assert_eq!(duration, Duration::default() + Duration::from_days(1)); 162 | /// ``` 163 | fn add_days(self, days: u64) -> Duration; 164 | 165 | /// Returns the number of _whole_ minutes contained by this `Duration`. 166 | /// 167 | /// # Examples 168 | /// 169 | /// ``` 170 | /// use std::time::Duration; 171 | /// use stdext::prelude::*; 172 | /// 173 | /// let duration = Duration::new(61, 730023852); 174 | /// assert_eq!(duration.as_minutes(), 1); 175 | /// ``` 176 | fn as_minutes(&self) -> u64; 177 | 178 | /// Returns the number of _whole_ hours contained by this `Duration`. 179 | /// 180 | /// # Examples 181 | /// 182 | /// ``` 183 | /// use std::time::Duration; 184 | /// use stdext::prelude::*; 185 | /// 186 | /// let duration = Duration::new(3601, 730023852); 187 | /// assert_eq!(duration.as_hours(), 1); 188 | /// ``` 189 | fn as_hours(&self) -> u64; 190 | 191 | /// Returns the number of _whole_ hours contained by this `Duration`. 192 | /// 193 | /// # Examples 194 | /// 195 | /// ``` 196 | /// use std::time::Duration; 197 | /// use stdext::prelude::*; 198 | /// 199 | /// let duration = Duration::new(61, 730023852).add_days(1); 200 | /// assert_eq!(duration.as_days(), 1); 201 | /// ``` 202 | fn as_days(&self) -> u64; 203 | } 204 | 205 | impl DurationExt for Duration { 206 | fn from_minutes(minutes: u64) -> Self { 207 | let seconds = minutes * SECS_IN_MIN; 208 | Self::from_secs(seconds) 209 | } 210 | 211 | fn from_hours(hours: u64) -> Self { 212 | let seconds: u64 = hours * SECS_IN_HOUR; 213 | Self::from_secs(seconds) 214 | } 215 | 216 | fn from_days(days: u64) -> Self { 217 | let seconds = days * SECS_IN_DAY; 218 | Self::from_secs(seconds) 219 | } 220 | 221 | fn add_nanos(self, nanos: u64) -> Self { 222 | self + Self::from_nanos(nanos) 223 | } 224 | 225 | fn add_micros(self, micros: u64) -> Self { 226 | self + Self::from_micros(micros) 227 | } 228 | 229 | fn add_millis(self, millis: u64) -> Self { 230 | self + Self::from_millis(millis) 231 | } 232 | 233 | fn add_secs(self, seconds: u64) -> Self { 234 | self + Self::from_secs(seconds) 235 | } 236 | 237 | fn add_minutes(self, minutes: u64) -> Self { 238 | self + Self::from_minutes(minutes) 239 | } 240 | 241 | fn add_hours(self, hours: u64) -> Self { 242 | self + Self::from_hours(hours) 243 | } 244 | 245 | fn add_days(self, days: u64) -> Self { 246 | self + Self::from_days(days) 247 | } 248 | 249 | fn as_minutes(&self) -> u64 { 250 | self.as_secs() / SECS_IN_MIN 251 | } 252 | 253 | fn as_hours(&self) -> u64 { 254 | self.as_secs() / SECS_IN_HOUR 255 | } 256 | 257 | fn as_days(&self) -> u64 { 258 | self.as_secs() / SECS_IN_DAY 259 | } 260 | } 261 | 262 | #[cfg(test)] 263 | mod tests { 264 | use super::*; 265 | 266 | #[test] 267 | fn from_methods() { 268 | // Check `from_minutes` 269 | let test_vector = vec![0, 1, u64::max_value() / SECS_IN_MIN]; 270 | for minutes in test_vector { 271 | let seconds = minutes * SECS_IN_MIN; 272 | assert_eq!( 273 | Duration::from_minutes(minutes), 274 | Duration::from_secs(seconds) 275 | ); 276 | } 277 | 278 | // Check `from_hours` 279 | let test_vector = vec![0, 1, u64::max_value() / SECS_IN_HOUR]; 280 | for hours in test_vector { 281 | let seconds = hours * SECS_IN_HOUR; 282 | assert_eq!(Duration::from_hours(hours), Duration::from_secs(seconds)); 283 | } 284 | 285 | // Check `from_days` 286 | let test_vector = vec![0, 1, u64::max_value() / SECS_IN_DAY]; 287 | for days in test_vector { 288 | let seconds = days * SECS_IN_DAY; 289 | assert_eq!(Duration::from_days(days), Duration::from_secs(seconds)); 290 | } 291 | } 292 | 293 | #[test] 294 | fn add_methods() { 295 | let duration = Duration::default() 296 | .add_nanos(1) 297 | .add_micros(1) 298 | .add_millis(1) 299 | .add_secs(1) 300 | .add_minutes(1) 301 | .add_hours(1) 302 | .add_days(1); 303 | 304 | let expected_duration = Duration::new( 305 | SECS_IN_DAY + SECS_IN_HOUR + SECS_IN_MIN + 1, 306 | 1_000_000 + 1_000 + 1, 307 | ); 308 | 309 | assert_eq!(duration, expected_duration); 310 | } 311 | 312 | #[test] 313 | fn as_methods() { 314 | let test_vector = vec![0, SECS_IN_MIN, SECS_IN_HOUR, SECS_IN_DAY]; 315 | 316 | for seconds in test_vector { 317 | for seconds in &[seconds, seconds + 1, seconds * 2, seconds * 2 + 1] { 318 | let duration = Duration::from_secs(*seconds); 319 | 320 | assert_eq!(duration.as_minutes(), duration.as_secs() / SECS_IN_MIN); 321 | assert_eq!(duration.as_hours(), duration.as_secs() / SECS_IN_HOUR); 322 | assert_eq!(duration.as_days(), duration.as_secs() / SECS_IN_DAY); 323 | } 324 | } 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /src/num/integer.rs: -------------------------------------------------------------------------------- 1 | // This interface copies `std` one, thus we must discard clippy complains. 2 | #![allow(clippy::wrong_self_convention)] 3 | 4 | //! Extensions for built-in integer traits. 5 | 6 | use std::num::ParseIntError; 7 | use std::ops::{ 8 | Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, 9 | Mul, MulAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, 10 | }; 11 | 12 | /// Built-in integers interface exposed as a trait. 13 | /// 14 | /// This trait is implemented for all the built-in integer types and copies their interface completely, 15 | /// so it's possible to write generic code that accepts any integer number. 16 | /// 17 | /// Interface includes all the trait implementations as well, such as [`Copy`], [`Add`] or [`BitXorAssign`]. 18 | /// 19 | /// ## Caveats 20 | /// 21 | /// - `__bytes` are not implemented, as the return type (array of generic const length that 22 | /// depends on the trait itself) cannot in be expressed in stable rust. 23 | /// 24 | /// - `is_power_of_two` / `next_power_of_two` / `checked_next_power_of_two` methods are not implemented, 25 | /// as they exist for the unsigned numbers only. 26 | pub trait Integer: 27 | Sized 28 | + Add 29 | + AddAssign 30 | + Sub 31 | + SubAssign 32 | + Shr 33 | + ShrAssign 34 | + Shl 35 | + ShlAssign 36 | + BitAnd 37 | + BitAndAssign 38 | + BitOr 39 | + BitOrAssign 40 | + BitXor 41 | + BitXorAssign 42 | + Div 43 | + DivAssign 44 | + Mul 45 | + MulAssign 46 | + Copy 47 | { 48 | /// The smallest value that can be represented by this integer type. 49 | const MIN: Self; 50 | /// The largest value that can be represented by this integer type. 51 | const MAX: Self; 52 | /// The size of this integer type in bits. 53 | const BITS: u32; 54 | 55 | /// See [`u128::from_str_radix`]. 56 | fn from_str_radix(src: &str, radix: u32) -> Result; 57 | 58 | /// See [`u128::count_ones`]. 59 | #[must_use = "this returns the result of the operation, without modifying the original"] 60 | fn count_ones(self) -> u32; 61 | 62 | /// See [`u128::count_zeros`]. 63 | #[must_use = "this returns the result of the operation, without modifying the original"] 64 | fn count_zeros(self) -> u32; 65 | 66 | /// See [`u128::leading_zeros`]. 67 | #[must_use = "this returns the result of the operation, without modifying the original"] 68 | fn leading_zeros(self) -> u32; 69 | 70 | /// See [`u128::trailing_zeros`]. 71 | #[must_use = "this returns the result of the operation, without modifying the original"] 72 | fn trailing_zeros(self) -> u32; 73 | 74 | /// See [`u128::leading_ones`]. 75 | #[must_use = "this returns the result of the operation, without modifying the original"] 76 | fn leading_ones(self) -> u32; 77 | 78 | /// See [`u128::trailing_ones`]. 79 | #[must_use = "this returns the result of the operation, without modifying the original"] 80 | fn trailing_ones(self) -> u32; 81 | 82 | /// See [`u128::rotate_left`]. 83 | #[must_use = "this returns the result of the operation, without modifying the original"] 84 | fn rotate_left(self, n: u32) -> Self; 85 | 86 | /// See [`u128::rotate_right`]. 87 | #[must_use = "this returns the result of the operation, without modifying the original"] 88 | fn rotate_right(self, n: u32) -> Self; 89 | 90 | /// See [`u128::swap_bytes`]. 91 | #[must_use = "this returns the result of the operation, without modifying the original"] 92 | fn swap_bytes(self) -> Self; 93 | 94 | /// See [`u128::reverse_bits`]. 95 | #[must_use = "this returns the result of the operation, without modifying the original"] 96 | fn reverse_bits(self) -> Self; 97 | 98 | /// See [`u128::from_be`]. 99 | #[must_use = "this returns the result of the operation, without modifying the original"] 100 | fn from_be(x: Self) -> Self; 101 | 102 | /// See [`u128::from_le`]. 103 | #[must_use = "this returns the result of the operation, without modifying the original"] 104 | fn from_le(x: Self) -> Self; 105 | 106 | /// See [`u128::to_be`]. 107 | #[must_use = "this returns the result of the operation, without modifying the original"] 108 | fn to_be(self) -> Self; 109 | 110 | /// See [`u128::to_le`]. 111 | #[must_use = "this returns the result of the operation, without modifying the original"] 112 | fn to_le(self) -> Self; 113 | 114 | /// See [`u128::checked_add`]. 115 | #[must_use = "this returns the result of the operation, without modifying the original"] 116 | fn checked_add(self, rhs: Self) -> Option; 117 | 118 | /// See [`u128::checked_sub`]. 119 | #[must_use = "this returns the result of the operation, without modifying the original"] 120 | fn checked_sub(self, rhs: Self) -> Option; 121 | 122 | /// See [`u128::checked_mul`]. 123 | #[must_use = "this returns the result of the operation, without modifying the original"] 124 | fn checked_mul(self, rhs: Self) -> Option; 125 | 126 | /// See [`u128::checked_div`]. 127 | #[must_use = "this returns the result of the operation, without modifying the original"] 128 | fn checked_div(self, rhs: Self) -> Option; 129 | 130 | /// See [`u128::checked_div_euclid`]. 131 | #[must_use = "this returns the result of the operation, without modifying the original"] 132 | fn checked_div_euclid(self, rhs: Self) -> Option; 133 | 134 | /// See [`u128::checked_rem`]. 135 | #[must_use = "this returns the result of the operation, without modifying the original"] 136 | fn checked_rem(self, rhs: Self) -> Option; 137 | 138 | /// See [`u128::checked_rem_euclid`]. 139 | #[must_use = "this returns the result of the operation, without modifying the original"] 140 | fn checked_rem_euclid(self, rhs: Self) -> Option; 141 | 142 | /// See [`u128::checked_neg`]. 143 | #[must_use = "this returns the result of the operation, without modifying the original"] 144 | fn checked_neg(self) -> Option; 145 | 146 | /// See [`u128::checked_shl`]. 147 | #[must_use = "this returns the result of the operation, without modifying the original"] 148 | fn checked_shl(self, rhs: u32) -> Option; 149 | 150 | /// See [`u128::checked_shr`]. 151 | #[must_use = "this returns the result of the operation, without modifying the original"] 152 | fn checked_shr(self, rhs: u32) -> Option; 153 | 154 | /// See [`u128::checked_pow`]. 155 | #[must_use = "this returns the result of the operation, without modifying the original"] 156 | fn checked_pow(self, exp: u32) -> Option; 157 | 158 | /// See [`u128::saturating_add`]. 159 | #[must_use = "this returns the result of the operation, without modifying the original"] 160 | fn saturating_add(self, rhs: Self) -> Self; 161 | 162 | /// See [`u128::saturating_sub`]. 163 | #[must_use = "this returns the result of the operation, without modifying the original"] 164 | fn saturating_sub(self, rhs: Self) -> Self; 165 | 166 | /// See [`u128::saturating_mul`]. 167 | #[must_use = "this returns the result of the operation, without modifying the original"] 168 | fn saturating_mul(self, rhs: Self) -> Self; 169 | 170 | /// See [`u128::saturating_pow`]. 171 | #[must_use = "this returns the result of the operation, without modifying the original"] 172 | fn saturating_pow(self, exp: u32) -> Self; 173 | 174 | /// See [`u128::wrapping_add`]. 175 | #[must_use = "this returns the result of the operation, without modifying the original"] 176 | fn wrapping_add(self, rhs: Self) -> Self; 177 | 178 | /// See [`u128::wrapping_sub`]. 179 | #[must_use = "this returns the result of the operation, without modifying the original"] 180 | fn wrapping_sub(self, rhs: Self) -> Self; 181 | 182 | /// See [`u128::wrapping_mul`]. 183 | #[must_use = "this returns the result of the operation, without modifying the original"] 184 | fn wrapping_mul(self, rhs: Self) -> Self; 185 | 186 | /// See [`u128::wrapping_div`]. 187 | #[must_use = "this returns the result of the operation, without modifying the original"] 188 | fn wrapping_div(self, rhs: Self) -> Self; 189 | 190 | /// See [`u128::wrapping_div_euclid`]. 191 | #[must_use = "this returns the result of the operation, without modifying the original"] 192 | fn wrapping_div_euclid(self, rhs: Self) -> Self; 193 | 194 | /// See [`u128::wrapping_rem`]. 195 | #[must_use = "this returns the result of the operation, without modifying the original"] 196 | fn wrapping_rem(self, rhs: Self) -> Self; 197 | 198 | /// See [`u128::wrapping_rem_euclid`]. 199 | #[must_use = "this returns the result of the operation, without modifying the original"] 200 | fn wrapping_rem_euclid(self, rhs: Self) -> Self; 201 | 202 | /// See [`u128::wrapping_neg`]. 203 | #[must_use = "this returns the result of the operation, without modifying the original"] 204 | fn wrapping_neg(self) -> Self; 205 | 206 | /// See [`u128::wrapping_shl`]. 207 | #[must_use = "this returns the result of the operation, without modifying the original"] 208 | fn wrapping_shl(self, rhs: u32) -> Self; 209 | 210 | /// See [`u128::wrapping_shr`]. 211 | #[must_use = "this returns the result of the operation, without modifying the original"] 212 | fn wrapping_shr(self, rhs: u32) -> Self; 213 | 214 | /// See [`u128::wrapping_pow`]. 215 | #[must_use = "this returns the result of the operation, without modifying the original"] 216 | fn wrapping_pow(self, exp: u32) -> Self; 217 | 218 | /// See [`u128::overflowing_add`]. 219 | #[must_use = "this returns the result of the operation, without modifying the original"] 220 | fn overflowing_add(self, rhs: Self) -> (Self, bool); 221 | 222 | /// See [`u128::overflowing_sub`]. 223 | #[must_use = "this returns the result of the operation, without modifying the original"] 224 | fn overflowing_sub(self, rhs: Self) -> (Self, bool); 225 | 226 | /// See [`u128::overflowing_mul`]. 227 | #[must_use = "this returns the result of the operation, without modifying the original"] 228 | fn overflowing_mul(self, rhs: Self) -> (Self, bool); 229 | 230 | /// See [`u128::overflowing_div`]. 231 | #[must_use = "this returns the result of the operation, without modifying the original"] 232 | fn overflowing_div(self, rhs: Self) -> (Self, bool); 233 | 234 | /// See [`u128::overflowing_div_euclid`]. 235 | #[must_use = "this returns the result of the operation, without modifying the original"] 236 | fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool); 237 | 238 | /// See [`u128::overflowing_rem`]. 239 | #[must_use = "this returns the result of the operation, without modifying the original"] 240 | fn overflowing_rem(self, rhs: Self) -> (Self, bool); 241 | 242 | /// See [`u128::overflowing_rem_euclid`]. 243 | #[must_use = "this returns the result of the operation, without modifying the original"] 244 | fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool); 245 | 246 | /// See [`u128::overflowing_neg`]. 247 | #[must_use = "this returns the result of the operation, without modifying the original"] 248 | fn overflowing_neg(self) -> (Self, bool); 249 | 250 | /// See [`u128::overflowing_shr`]. 251 | #[must_use = "this returns the result of the operation, without modifying the original"] 252 | fn overflowing_shr(self, rhs: u32) -> (Self, bool); 253 | 254 | /// See [`u128::overflowing_pow`]. 255 | #[must_use = "this returns the result of the operation, without modifying the original"] 256 | fn overflowing_pow(self, exp: u32) -> (Self, bool); 257 | 258 | /// See [`u128::pow`]. 259 | #[must_use = "this returns the result of the operation, without modifying the original"] 260 | fn pow(self, exp: u32) -> Self; 261 | 262 | /// See [`u128::div_euclid`]. 263 | #[must_use = "this returns the result of the operation, without modifying the original"] 264 | fn div_euclid(self, rhs: Self) -> Self; 265 | 266 | /// See [`u128::rem_euclid`]. 267 | #[must_use = "this returns the result of the operation, without modifying the original"] 268 | fn rem_euclid(self, rhs: Self) -> Self; 269 | } 270 | 271 | macro_rules! impl_integer { 272 | ($($int:ty),+) => { 273 | $( 274 | impl Integer for $int { 275 | const MIN: Self = Self::MIN; 276 | const MAX: Self = Self::MAX; 277 | const BITS: u32 = Self::BITS; 278 | fn from_str_radix(src: &str, radix: u32) -> Result { 279 | <$int>::from_str_radix(src, radix) 280 | } 281 | fn count_ones(self) -> u32 { 282 | <$int>::count_ones(self) 283 | } 284 | fn count_zeros(self) -> u32 { 285 | <$int>::count_zeros(self) 286 | } 287 | fn leading_zeros(self) -> u32 { 288 | <$int>::leading_zeros(self) 289 | } 290 | fn trailing_zeros(self) -> u32 { 291 | <$int>::trailing_zeros(self) 292 | } 293 | fn leading_ones(self) -> u32 { 294 | <$int>::leading_ones(self) 295 | } 296 | fn trailing_ones(self) -> u32 { 297 | <$int>::trailing_ones(self) 298 | } 299 | fn rotate_left(self, n: u32) -> Self { 300 | <$int>::rotate_left(self, n) 301 | } 302 | fn rotate_right(self, n: u32) -> Self { 303 | <$int>::rotate_right(self, n) 304 | } 305 | fn swap_bytes(self) -> Self { 306 | <$int>::swap_bytes(self) 307 | } 308 | fn reverse_bits(self) -> Self { 309 | <$int>::reverse_bits(self) 310 | } 311 | fn from_be(x: Self) -> Self { 312 | <$int>::from_be(x) 313 | } 314 | fn from_le(x: Self) -> Self { 315 | <$int>::from_le(x) 316 | } 317 | fn to_be(self) -> Self { 318 | <$int>::to_be(self) 319 | } 320 | fn to_le(self) -> Self { 321 | <$int>::to_le(self) 322 | } 323 | fn checked_add(self, rhs: Self) -> Option { 324 | <$int>::checked_add(self, rhs) 325 | } 326 | fn checked_sub(self, rhs: Self) -> Option { 327 | <$int>::checked_sub(self, rhs) 328 | } 329 | fn checked_mul(self, rhs: Self) -> Option { 330 | <$int>::checked_mul(self, rhs) 331 | } 332 | fn checked_div(self, rhs: Self) -> Option { 333 | <$int>::checked_div(self, rhs) 334 | } 335 | fn checked_div_euclid(self, rhs: Self) -> Option { 336 | <$int>::checked_div_euclid(self, rhs) 337 | } 338 | fn checked_rem(self, rhs: Self) -> Option { 339 | <$int>::checked_rem(self, rhs) 340 | } 341 | fn checked_rem_euclid(self, rhs: Self) -> Option { 342 | <$int>::checked_rem_euclid(self, rhs) 343 | } 344 | fn checked_neg(self) -> Option { 345 | <$int>::checked_neg(self) 346 | } 347 | fn checked_shl(self, rhs: u32) -> Option { 348 | <$int>::checked_shl(self, rhs) 349 | } 350 | fn checked_shr(self, rhs: u32) -> Option { 351 | <$int>::checked_shr(self, rhs) 352 | } 353 | fn checked_pow(self, exp: u32) -> Option { 354 | <$int>::checked_pow(self, exp) 355 | } 356 | fn saturating_add(self, rhs: Self) -> Self { 357 | <$int>::saturating_add(self, rhs) 358 | } 359 | fn saturating_sub(self, rhs: Self) -> Self { 360 | <$int>::saturating_sub(self, rhs) 361 | } 362 | fn saturating_mul(self, rhs: Self) -> Self { 363 | <$int>::saturating_mul(self, rhs) 364 | } 365 | fn saturating_pow(self, exp: u32) -> Self { 366 | <$int>::saturating_pow(self, exp) 367 | } 368 | fn wrapping_add(self, rhs: Self) -> Self { 369 | <$int>::wrapping_add(self, rhs) 370 | } 371 | fn wrapping_sub(self, rhs: Self) -> Self { 372 | <$int>::wrapping_sub(self, rhs) 373 | } 374 | fn wrapping_mul(self, rhs: Self) -> Self { 375 | <$int>::wrapping_mul(self, rhs) 376 | } 377 | fn wrapping_div(self, rhs: Self) -> Self { 378 | <$int>::wrapping_div(self, rhs) 379 | } 380 | fn wrapping_div_euclid(self, rhs: Self) -> Self { 381 | <$int>::wrapping_div_euclid(self, rhs) 382 | } 383 | fn wrapping_rem(self, rhs: Self) -> Self { 384 | <$int>::wrapping_rem(self, rhs) 385 | } 386 | fn wrapping_rem_euclid(self, rhs: Self) -> Self { 387 | <$int>::wrapping_rem_euclid(self, rhs) 388 | } 389 | fn wrapping_neg(self) -> Self { 390 | <$int>::wrapping_neg(self) 391 | } 392 | fn wrapping_shl(self, rhs: u32) -> Self { 393 | <$int>::wrapping_shl(self, rhs) 394 | } 395 | fn wrapping_shr(self, rhs: u32) -> Self { 396 | <$int>::wrapping_shr(self, rhs) 397 | } 398 | fn wrapping_pow(self, exp: u32) -> Self { 399 | <$int>::wrapping_pow(self, exp) 400 | } 401 | fn overflowing_add(self, rhs: Self) -> (Self, bool) { 402 | <$int>::overflowing_add(self, rhs) 403 | } 404 | fn overflowing_sub(self, rhs: Self) -> (Self, bool) { 405 | <$int>::overflowing_sub(self, rhs) 406 | } 407 | fn overflowing_mul(self, rhs: Self) -> (Self, bool) { 408 | <$int>::overflowing_mul(self, rhs) 409 | } 410 | fn overflowing_div(self, rhs: Self) -> (Self, bool) { 411 | <$int>::overflowing_div(self, rhs) 412 | } 413 | fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { 414 | <$int>::overflowing_div_euclid(self, rhs) 415 | } 416 | fn overflowing_rem(self, rhs: Self) -> (Self, bool) { 417 | <$int>::overflowing_rem(self, rhs) 418 | } 419 | fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { 420 | <$int>::overflowing_rem_euclid(self, rhs) 421 | } 422 | fn overflowing_neg(self) -> (Self, bool) { 423 | <$int>::overflowing_neg(self) 424 | } 425 | fn overflowing_shr(self, rhs: u32) -> (Self, bool) { 426 | <$int>::overflowing_shr(self, rhs) 427 | } 428 | fn overflowing_pow(self, exp: u32) -> (Self, bool) { 429 | <$int>::overflowing_pow(self, exp) 430 | } 431 | fn pow(self, exp: u32) -> Self { 432 | <$int>::pow(self, exp) 433 | } 434 | fn div_euclid(self, rhs: Self) -> Self { 435 | <$int>::div_euclid(self, rhs) 436 | } 437 | fn rem_euclid(self, rhs: Self) -> Self { 438 | <$int>::rem_euclid(self, rhs) 439 | } 440 | } 441 | )+ 442 | }; 443 | } 444 | 445 | impl_integer!(u8, u16, u32, u64, u128); 446 | impl_integer!(i8, i16, i32, i64, i128); 447 | impl_integer!(usize, isize); 448 | 449 | #[cfg(test)] 450 | mod tests { 451 | #[test] 452 | fn basic() { 453 | assert_eq!(::BITS, u8::BITS); 454 | assert_eq!( 455 | ::trailing_ones(10u32), 456 | 10u32.trailing_ones() 457 | ); 458 | } 459 | 460 | fn accepts_any_integer(a: I, b: I) -> u32 { 461 | (a + b).count_ones() 462 | } 463 | 464 | #[test] 465 | fn composite() { 466 | assert_eq!(accepts_any_integer(0u8, 0u8), 0); 467 | assert_eq!(accepts_any_integer(1i128, 0i128), 1); 468 | } 469 | } 470 | --------------------------------------------------------------------------------