gat-std-0.1.1/.cargo_vcs_info.json0000644000000001360000000000100123760ustar { "git": { "sha1": "8b410b59c365fa65a0d19d7a6d7b46b1e4ff27ff" }, "path_in_vcs": "" }gat-std-0.1.1/.gitignore000064400000000000000000000000321046102023000131510ustar 00000000000000/target Cargo.lock .idea/ gat-std-0.1.1/Cargo.lock0000644000000024770000000000100103630ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "gat-std" version = "0.1.1" dependencies = [ "gat-std-proc", ] [[package]] name = "gat-std-proc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c20aeb660d16a16f6611d5be552a02b68edd5c046574d03d2e791e7446a262f" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "proc-macro2" version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] [[package]] name = "syn" version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "unicode-ident" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" gat-std-0.1.1/Cargo.toml0000644000000015260000000000100104000ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "gat-std" version = "0.1.1" description = "Variants of Rust std traits that use GATs" readme = "README.md" keywords = [ "GAT", "lending_iterator", ] categories = ["no-std"] license = "MIT OR Apache-2.0" repository = "https://github.com/CraftSpider/gat-std" [dependencies.gat-std-proc] version = "0.1" [features] alloc = [] default = ["alloc"] gat-std-0.1.1/Cargo.toml.orig000064400000000000000000000007421046102023000140600ustar 00000000000000[package] name = "gat-std" version = "0.1.1" edition = "2021" description = "Variants of Rust std traits that use GATs" license = "MIT OR Apache-2.0" repository = "https://github.com/CraftSpider/gat-std" keywords = ["GAT", "lending_iterator"] categories = ["no-std"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] gat-std-proc = { version = "0.1", path = "gat-std-proc" } [features] default = ["alloc"] alloc = [] gat-std-0.1.1/README.md000064400000000000000000000006721046102023000124520ustar 00000000000000 # GAT std A variant of Rust `std` traits that use GATs, as well as a macro to allow rewriting code to use these traits instead of the `std` equivalents. ## Why? 1) These traits provide a common base so crates can all use the same definitions, like with `num-traits` 2) `std` likely won't be able to change to use these traits for quite a while, if ever. This allows users to take advantage of GATs in their code smoothly despite that. gat-std-0.1.1/examples/iter.rs000064400000000000000000000015251046102023000143200ustar 00000000000000use gat_std::iter::Iterator; use gat_std_proc::gatify; struct Custom(i32, i32); impl Custom { fn new() -> Custom { Custom(10, 0) } } impl Iterator for Custom { type Item<'a> = &'a mut i32 where Self: 'a; fn next(&mut self) -> Option> { if self.0 > 0 { self.0 -= 1; Some(&mut self.1) } else { None } } } fn main() { let iter: Custom = Custom::new(); iter.touch(|val| { **val += 1; }) .for_each(|val| println!("{}", *val)); } #[gatify] fn _foo() { // STD iterator for _ in 0..10 {} // Lending iterator for _ in Custom::new() {} } #[gatify] fn _bar(val: T) { for _ in val {} } #[gatify] fn _baz(val: T) { for _ in val {} } gat-std-0.1.1/examples/rewrite.rs000064400000000000000000000003611046102023000150330ustar 00000000000000use gat_std::gatify; #[gatify] fn main() { for a in 0..10 { println!("{a}"); } let mut b = vec![0, 1, 2]; println!("{}", &b[0]); b[1] = 2; let first = &mut b[0]; *first = 1; println!("{:?}", b); } gat-std-0.1.1/src/iter/adapters.rs000064400000000000000000000202261046102023000150730ustar 00000000000000use super::{change_lifetime, Iterator}; /// See [`IntoLending::into_lending`] pub struct FromCore(pub(crate) I); impl Iterator for FromCore where I: core::iter::Iterator, { type Item<'a> = I::Item where Self: 'a; fn next(&mut self) -> Option> { self.0.next() } } /// See [`Iterator::map`] pub struct Map { iter: I, func: F, } impl Map { pub(crate) fn new(iter: I, func: F) -> Map { Map { iter, func } } } impl core::iter::Iterator for Map where I: Iterator, F: FnMut(I::Item<'_>) -> O, { type Item = O; fn next(&mut self) -> Option { Some((self.func)(self.iter.next()?)) } } /// See [`Iterator::touch`] pub struct Touch { iter: I, func: F, } impl Touch { pub(crate) fn new(iter: I, func: F) -> Touch { Touch { iter, func } } } impl Iterator for Touch where I: Iterator, F: FnMut(&mut I::Item<'_>), { type Item<'a> = I::Item<'a> where Self: 'a; fn next(&mut self) -> Option> { let mut out = self.iter.next()?; (self.func)(&mut out); Some(out) } } /// See [`Iterator::filter`] pub struct Filter { iter: I, func: F, } impl Filter { pub(crate) fn new(iter: I, func: F) -> Filter { Filter { iter, func } } } impl Iterator for Filter where I: Iterator, F: FnMut(&I::Item<'_>) -> bool, { type Item<'a> = I::Item<'a> where Self: 'a; fn next(&mut self) -> Option> { while let Some(val) = self.iter.next() { if (self.func)(&val) { // SAFETY: This is the polonius case return Some(unsafe { change_lifetime::(val) }); } } None } } /// See [`Iterator::step_by`] pub struct StepBy { iter: I, step: usize, first: bool, } impl StepBy { pub(crate) fn new(iter: I, step: usize) -> StepBy { StepBy { iter, step, first: true, } } } impl Iterator for StepBy where I: Iterator, { type Item<'a> = I::Item<'a> where Self: 'a; fn next(&mut self) -> Option> { if self.first { self.first = false; self.iter.next() } else { self.nth(self.step - 1) } } } /// See [`Iterator::chain`] pub struct Chain { first: Option, second: Option, } impl Chain { pub(crate) fn new(first: I1, second: I2) -> Chain { Chain { first: Some(first), second: Some(second), } } } impl<'b, I1, I2> Iterator for Chain where I1: Iterator + 'b, I2: Iterator = I1::Item<'b>> + 'b, { type Item<'a> = I1::Item<'a> where Self: 'a; fn next(&mut self) -> Option> { if let Some(iter) = &mut self.first { if let Some(val) = iter.next() { // SAFETY: This is the polonius case return Some(unsafe { change_lifetime::(val) }); } self.first = None; } if let Some(iter) = &mut self.second { // SAFETY: Due to our lie in the where bounds, we need to convince Rust // that we actually borrow iter for a different length of time than it // thinks let iter = unsafe { core::mem::transmute::<&mut I2, &mut I2>(iter) }; if let Some(val) = iter.next() { // SAFETY: This is the polonius case return Some(unsafe { change_lifetime::(val) }); } self.second = None; } None } } /// See [`Iterator::zip`] pub struct Zip { left: I1, right: I2, } impl Zip { pub(crate) fn new(left: I1, right: I2) -> Zip { Zip { left, right } } } impl Iterator for Zip where I1: Iterator, I2: Iterator, { type Item<'a> = (I1::Item<'a>, I2::Item<'a>) where Self: 'a; fn next(&mut self) -> Option> { let left = self.left.next()?; let right = self.right.next()?; Some((left, right)) } } /// See [`Iterator::enumerate`] pub struct Enumerate { iter: I, pos: usize, } impl Enumerate { pub(crate) fn new(iter: I) -> Enumerate { Enumerate { iter, pos: 0 } } } impl Iterator for Enumerate where I: Iterator, { type Item<'a> = (usize, I::Item<'a>) where Self: 'a; fn next(&mut self) -> Option> { let out = (self.pos, self.iter.next()?); self.pos += 1; Some(out) } } /// See [`Iterator::skip_while`] pub struct SkipWhile { iter: I, func: Option, } impl SkipWhile { pub(crate) fn new(iter: I, func: F) -> SkipWhile { SkipWhile { iter, func: Some(func), } } } impl Iterator for SkipWhile where I: Iterator, F: FnMut(&I::Item<'_>) -> bool, { type Item<'a> = I::Item<'a> where Self: 'a; fn next(&mut self) -> Option> { match self.func.take() { Some(mut f) => { while let Some(val) = self.iter.next() { if !f(&val) { // SAFETY: This is the polonius case return Some(unsafe { change_lifetime::(val) }); } } None } None => self.iter.next(), } } } /// See [`Iterator::take_while`] pub struct TakeWhile { iter: I, func: Option, } impl TakeWhile { pub(crate) fn new(iter: I, func: F) -> TakeWhile { TakeWhile { iter, func: Some(func), } } } impl Iterator for TakeWhile where I: Iterator, F: FnMut(&I::Item<'_>) -> bool, { type Item<'a> = I::Item<'a> where Self: 'a; fn next(&mut self) -> Option> { match &mut self.func { Some(f) => { let next = self.iter.next()?; if !f(&next) { self.func = None; None } else { Some(next) } } None => None, } } } /// See [`Iterator::skip`] pub struct Skip { iter: I, skip: usize, } impl Skip { pub(crate) fn new(iter: I, skip: usize) -> Skip { Skip { iter, skip } } } impl Iterator for Skip where I: Iterator, { type Item<'a> = I::Item<'a> where Self: 'a; fn next(&mut self) -> Option> { while self.skip > 0 { self.skip -= 1; match self.iter.next() { Some(_) => self.skip -= 1, None => { self.skip = 0; return None; } } } self.iter.next() } } /// See [`Iterator::take`] pub struct Take { iter: I, take: usize, } impl Take { pub(crate) fn new(iter: I, take: usize) -> Take { Take { iter, take } } } impl Iterator for Take where I: Iterator, { type Item<'a> = I::Item<'a> where Self: 'a; fn next(&mut self) -> Option> { if self.take > 0 { self.take -= 1; self.iter.next() } else { None } } } /// See [`Iterator::scan`] pub struct Scan { iter: I, state: T, func: F, } impl Scan { pub(crate) fn new(iter: I, state: T, func: F) -> Scan { Scan { iter, state, func } } } impl core::iter::Iterator for Scan where I: Iterator, F: FnMut(&mut T, I::Item<'_>) -> Option, { type Item = O; fn next(&mut self) -> Option { let a = self.iter.next()?; (self.func)(&mut self.state, a) } } gat-std-0.1.1/src/iter/test.rs000064400000000000000000000016531046102023000142520ustar 00000000000000use super::*; struct LendingIter(u8, u8); impl LendingIter { fn new() -> LendingIter { LendingIter(0, 10) } } impl Iterator for LendingIter { type Item<'a> = &'a mut u8; fn next(&mut self) -> Option> { match self.1.checked_sub(1) { Some(new) => { self.1 = new; Some(&mut self.0) } None => None, } } } #[test] fn iter_filter() { let iter = LendingIter::new(); let res = iter .touch(|a| **a += 1) .filter(|a| **a % 2 == 0) .fold(0, |acc, val| { assert!(*val % 2 == 0); acc + 1 }); assert_eq!(res, 5); } #[test] fn iter_chain() { let iter = LendingIter::new(); let res = iter.chain(LendingIter::new()).fold(0, |acc, a| { *a += 1; assert_eq!(*a, (acc % 10) + 1); acc + 1 }); assert_eq!(res, 20); } gat-std-0.1.1/src/iter.rs000064400000000000000000000204711046102023000132720ustar 00000000000000//! GAT equivalent of `std` iterator traits, often referred to as a lending iterator mod adapters; pub use adapters::*; /// # Safety: /// This is only safe to use if the item provided is sound to have a lifetime of `'b`. /// /// This is true in cases such as the polonius borrow case and when the user is sure the value can /// actually live for the desired time. unsafe fn change_lifetime<'a, 'b, I: ?Sized + Iterator>(i: I::Item<'a>) -> I::Item<'b> { // SAFETY: This functions preconditions assure this is sound unsafe { core::mem::transmute::, I::Item<'b>>(i) } } /// A lending iterator, whose items may have their lifetimes tied to the individual borrow of the /// iterator. This allows for things like yielding mutable references that overlap, with the /// trade-off that there's no generic `collect` interface - the items of this iterator cannot /// co-exist. pub trait Iterator { /// The value yielded by each call to `next` on this iterator type Item<'a> where Self: 'a; /// Get the next value of this iterator, or return `None` fn next(&mut self) -> Option>; /// Get a hint as to the size of this iterator - the first value is a lower bound, second /// is an optional upper bound. fn size_hint(&self) -> (usize, Option) { (0, None) } /// Advance the iterator by `n` elements fn advance_by(&mut self, n: usize) -> Result<(), usize> { let mut idx = 0; while idx < n { if self.next().is_none() { return Err(idx); } idx += 1; } Ok(()) } /// Return the `n`th element of the iterator /// /// This does not rewind the iterator after completion, so repeatedly calling `nth(0)` is /// equivalent to calling `next` fn nth(&mut self, mut n: usize) -> Option> { while n > 0 { self.next()?; n -= 1; } self.next() } // Lazy Adaptors /// Take a closure which will take each value from the iterator, and yield a new value computed /// from it. /// /// The result cannot reference the provided data, as such, this returns an iterator which also /// implements the non-lending core iterator fn map(self, f: F) -> Map where Self: Sized, F: FnMut(Self::Item<'_>) -> O, { Map::new(self, f) } /// Gain mutable access to each value in this iterator, then yield it to the next step. /// This allows altering each item without consuming it, preserving the lending nature /// or the iterator fn touch(self, f: F) -> Touch where Self: Sized, F: FnMut(&mut Self::Item<'_>), { Touch::new(self, f) } /// Execute a closure on each item in the iterator, returning true if it should be included, or /// false to skip it fn filter(self, f: F) -> Filter where Self: Sized, F: FnMut(&Self::Item<'_>) -> bool, { Filter::new(self, f) } /// Creates an iterator starting at the same point, but stepping by the given amount at each /// iteration fn step_by(self, step: usize) -> StepBy where Self: Sized, { assert_ne!(step, 0); StepBy::new(self, step) } /// Takes two iterators and creates a new iterator over both in sequence fn chain(self, other: U) -> Chain where Self: Sized, U: IntoIterator, U::IntoIter: for<'a> Iterator = Self::Item<'a>>, { Chain::new(self, other.into_iter()) } /// ‘Zips up’ two iterators into a single iterator of pairs fn zip(self, other: U) -> Zip where Self: Sized, U: IntoIterator, { Zip::new(self, other.into_iter()) } /// Creates an iterator which gives the current iteration count as well as the next value fn enumerate(self) -> Enumerate where Self: Sized, { Enumerate::new(self) } /// Creates an iterator that skips elements based on a predicate fn skip_while(self, f: F) -> SkipWhile where Self: Sized, F: FnMut(&Self::Item<'_>) -> bool, { SkipWhile::new(self, f) } /// Creates an iterator that yields elements based on a predicate fn take_while(self, f: F) -> TakeWhile where Self: Sized, F: FnMut(&Self::Item<'_>) -> bool, { TakeWhile::new(self, f) } /// Creates an iterator that skips the first n elements fn skip(self, n: usize) -> Skip where Self: Sized, { Skip::new(self, n) } /// Creates an iterator that yields the first n elements, or fewer if the underlying iterator /// ends sooner fn take(self, n: usize) -> Take where Self: Sized, { Take::new(self, n) } // Consumers /// Tests if every element of the iterator matches a predicate fn all(&mut self, mut f: F) -> bool where F: FnMut(Self::Item<'_>) -> bool, { while let Some(val) = self.next() { if !f(val) { return false; } } true } /// Tests if any element of the iterator matches a predicate fn any(&mut self, mut f: F) -> bool where F: FnMut(Self::Item<'_>) -> bool, { while let Some(val) = self.next() { if f(val) { return true; } } false } /// Searches for an element of an iterator that satisfies a predicate fn find(&mut self, mut f: F) -> Option> where F: FnMut(&Self::Item<'_>) -> bool, { while let Some(val) = self.next() { if f(&val) { // SAFETY: Polonius case return Some(unsafe { change_lifetime::(val) }); } } None } /// Consume the iterator, counting the number of items and returning it fn count(self) -> usize where Self: Sized, { self.fold(0, |acc, _| acc + 1) } /// Execute a closure on each value of this iterator fn for_each(mut self, mut f: F) where Self: Sized, F: FnMut(Self::Item<'_>), { while let Some(next) = self.next() { f(next) } } /// Execute a closure on each value of this iterator, with an additional 'accumulator' value /// passed to each call. The closure is expected to return the new value of the accumulator. fn fold(mut self, acc: T, mut f: F) -> T where Self: Sized, F: FnMut(T, Self::Item<'_>) -> T, { let mut acc = acc; while let Some(x) = self.next() { acc = f(acc, x); } acc } /// Execute a closure on each value of this iterator, with an additional state value passed /// via mutable reference to each call. The closure is expected to return the new value /// for each step of the iterator, if the returned value is `None` the iterator stops early. /// /// The result cannot reference the provided data, as such, this returns an iterator which also /// implements the non-lending core iterator fn scan(self, acc: T, f: F) -> Scan where Self: Sized, F: FnMut(&mut T, Self::Item<'_>) -> Option, { Scan::new(self, acc, f) } } /// Trait for values which can be converted into an [`Iterator`] pub trait IntoIterator { /// The type of the returned iterator type IntoIter: Iterator; /// Convert this value into an [`Iterator`] fn into_iter(self) -> Self::IntoIter; } impl IntoIterator for T where T: Iterator, { type IntoIter = T; fn into_iter(self) -> Self::IntoIter { self } } /// Trait for converting a normal, non-lending iterator into a lending iterator. /// /// This is useful for methods such as [`Iterator::zip`], where you may want to combine a standard /// iterator onto a lending one. pub trait IntoLending: Sized { /// Convert this iterator into a lending one fn into_lending(self) -> FromCore; } impl IntoLending for I where I: core::iter::Iterator, { fn into_lending(self) -> FromCore { FromCore(self) } } #[cfg(test)] mod test; gat-std-0.1.1/src/lib.rs000064400000000000000000000051431046102023000130740ustar 00000000000000//! GAT implementations of `std` traits //! //! Traits are in the same respective paths as their `std` variants. The `gatify` //! macro changes operators to desugar to the traits in this crate instead of their `std` //! equivalents. #![warn( missing_docs, elided_lifetimes_in_paths, explicit_outlives_requirements, missing_abi, noop_method_call, pointer_structural_match, semicolon_in_expressions_from_macros, unused_import_braces, unused_lifetimes, unsafe_op_in_unsafe_fn, clippy::cargo, clippy::missing_panics_doc, clippy::doc_markdown, clippy::ptr_as_ptr, clippy::cloned_instead_of_copied, clippy::unreadable_literal, clippy::undocumented_unsafe_blocks, clippy::cast_sign_loss, clippy::cast_precision_loss, clippy::cast_possible_truncation, clippy::cast_possible_wrap )] #![no_std] #[cfg(feature = "alloc")] extern crate alloc; /// Rewrites `std` operators to use their GAT equivalents. Can be applied to any item or statement. /// /// ## Index /// /// The `[]` operator is converted to use the [`ops::Index`] or [`ops::IndexMut`] trait. /// This may not always be a perfect drop-in replacement, despite the blanket impl for /// [`core::ops::Index`] - if the macro can't tell which impl is expected from context, it will /// error out, pointing to the operator that caused the error. /// /// ## For Loops /// /// For loops are converted to use either [`core::iter::Iterator`] or [`iter::Iterator`], depending /// on which is implemented. If both are implemented, priority is given to the lending iterator. /// pub use gat_std_proc::gatify; pub mod iter; pub mod ops; #[doc(hidden)] pub mod __impl { pub struct IntoIter(pub T); pub trait ViaLending { type Selector; fn select(&self) -> Self::Selector; } impl ViaLending for &IntoIter { type Selector = Lending; fn select(&self) -> Self::Selector { Lending } } pub trait ViaCore { type Selector; fn select(&self) -> Self::Selector; } impl ViaCore for IntoIter { type Selector = Core; fn select(&self) -> Self::Selector { Core } } pub struct Lending; impl Lending { pub fn into_iter(self, iter: IntoIter) -> T::IntoIter { iter.0.into_iter() } } pub struct Core; impl Core { pub fn into_iter(self, iter: IntoIter) -> T::IntoIter { iter.0.into_iter() } } } gat-std-0.1.1/src/ops.rs000064400000000000000000000027351046102023000131330ustar 00000000000000//! GAT equivalents of `std` operators /// Index operator for immutable contexts. As opposed to `std`, the returned value can be a /// non-reference. This allows custom reference types for things like multi-dimensional matrices. pub trait Index { /// The output type of indexing this value type Output<'a> where Self: 'a; /// Get the value at this index immutably fn index(&self, idx: T) -> Self::Output<'_>; } /// Index operator for mutable contexts. As opposed to `std`, the returned value can be a /// non-reference. This allows custom reference types for things like multi-dimensional matrices. pub trait IndexMut: Index { /// The output type of indexing this value type OutputMut<'a> where Self: 'a; /// Get the value at this index mutably fn index_mut(&mut self, idx: T) -> Self::OutputMut<'_>; } impl Index for T where T: core::ops::Index, T::Output: 'static, { type Output<'a> = &'a >::Output where Self: 'a; fn index(&self, idx: I) -> Self::Output<'_> { >::index(self, idx) } } impl IndexMut for T where T: core::ops::IndexMut, T::Output: 'static, { type OutputMut<'a> = &'a mut >::Output where Self: 'a; fn index_mut(&mut self, idx: I) -> Self::OutputMut<'_> { >::index_mut(self, idx) } }