15 releases (7 stable)
1.2.0 | Mar 18, 2023 |
---|---|
1.1.2 | Sep 2, 2021 |
1.1.1 | Jul 12, 2021 |
1.0.1 | Feb 14, 2021 |
0.1.0 | Nov 26, 2019 |
#183 in Rust patterns
105,028 downloads per month
Used in 572 crates
(36 directly)
23KB
432 lines
extend
Create extensions for types you don't own with extension traits but without the boilerplate.
Example:
use extend::ext;
#[ext]
impl<T: Ord> Vec<T> {
fn sorted(mut self) -> Self {
self.sort();
self
}
}
fn main() {
assert_eq!(
vec![1, 2, 3],
vec![2, 3, 1].sorted(),
);
}
lib.rs
:
Create extensions for types you don't own with extension traits but without the boilerplate.
Example:
use extend::ext;
#[ext]
impl<T: Ord> Vec<T> {
fn sorted(mut self) -> Self {
self.sort();
self
}
}
assert_eq!(
vec![1, 2, 3],
vec![2, 3, 1].sorted(),
);
How does it work?
Under the hood it generates a trait with methods in your impl
and implements those for the
type you specify. The code shown above expands roughly to:
trait VecExt<T: Ord> {
fn sorted(self) -> Self;
}
impl<T: Ord> VecExt<T> for Vec<T> {
fn sorted(mut self) -> Self {
self.sort();
self
}
}
Supported items
Extensions can contain methods or associated constants:
use extend::ext;
#[ext]
impl String {
const CONSTANT: &'static str = "FOO";
fn method() {
// ...
# todo!()
}
}
Configuration
You can configure:
- The visibility of the trait. Use
pub impl ...
to generatepub trait ...
. The default visibility is private. - The name of the generated extension trait. Example:
#[ext(name = MyExt)]
. By default we generate a name based on what you extend. - Which supertraits the generated extension trait should have. Default is no supertraits.
Example:
#[ext(supertraits = Default + Clone)]
.
More examples:
use extend::ext;
#[ext(name = SortedVecExt)]
impl<T: Ord> Vec<T> {
fn sorted(mut self) -> Self {
self.sort();
self
}
}
#[ext]
pub(crate) impl i32 {
fn double(self) -> i32 {
self * 2
}
}
#[ext(name = ResultSafeUnwrapExt)]
pub impl<T> Result<T, std::convert::Infallible> {
fn safe_unwrap(self) -> T {
match self {
Ok(t) => t,
Err(_) => unreachable!(),
}
}
}
#[ext(supertraits = Default + Clone)]
impl String {
fn my_length(self) -> usize {
self.len()
}
}
For backwards compatibility you can also declare the visibility as the first argument to #[ext]
:
use extend::ext;
#[ext(pub)]
impl i32 {
fn double(self) -> i32 {
self * 2
}
}
async-trait compatibility
Async extensions are supported via async-trait.
Be aware that you need to add #[async_trait]
below #[ext]
. Otherwise the ext
macro
cannot see the #[async_trait]
attribute and pass it along in the generated code.
Example:
use extend::ext;
use async_trait::async_trait;
#[ext]
#[async_trait]
impl String {
async fn read_file() -> String {
// ...
# todo!()
}
}
Other attributes
Other attributes provided below #[ext]
will be passed along to both the generated trait and
the implementation. See async-trait compatibility above for an
example.
Dependencies
~255–700KB
~17K SLoC