Prototyping
This is just my prototyping library. It serves as an incubator for modules I think are convenient but not necessarily worth breaking out into their own crate yet.
wyz::fmt
Rust has a rich formatting system, but unfortunately it only uses the Debug
trait in certain interfaces such as printing an error bubbled out of main, or dynamically assembling a debug-print of aggregate types.
This module provides transparent wrapper types that all implement Debug
by forwarding to a different core::fmt
trait, and a blanket extension trait that places methods to create those types on all types that implement the core formatters.
#[repr(transparent)]
pub struct FmtDisplay<T: Display> {
inner: T,
}
impl<T: Display> Debug for FmtDisplay<T> {
#[inline(always)]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
Display::fmt(&self.inner, fmt)
}
}
pub trait FmtForward: Sized {
fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display {
FmtDisplay { inner: self }
}
}
impl<T: Sized> FmtForward for T {}
The types and trait methods repeat for Binary
, Octal
, LowerHex
, and UpperHex
as well.
To use, import the wyz::FmtForward
trait and call .fmt_some_trait()
on any object to gain a Debug
implementation that prints what you actually want.
wyz::bidi
This is an iterator adapter that allows you to write the following:
let iter = some_reversible_iterator();
let iter = if some_condition() {
iter.rev()
} else {
iter
};
That block is, of course, illegal, because .rev()
produces a Rev<T>
and if you don’t call it, you just have a T
, and those are different types.
Instead, iter.bidi(some_condition())
produces a Bidi<T>
whose implementation of Iterator
and DoubleEndedIterator
remembers the provided condition and dispatches accordingly: when true
, Bidi::next()
forwards to T::next_back()
and Bidi::next_back()
forwards to T::next()
; when false
, it behaves normally.
In order to cut down on branches, each Bidi
value stores four function pointers next to the wrapped iterator: next
, next_back
, nth
, and nth_back
. These pointers are initialized to the appropriate delegated function when the Bidi
is constructed, so calling Bidi
’s own iterator functions just immediately jumps to the corresponding function pointer, and does not have to branch. This makes Bidi
much larger than it would be if it just stored the single bool
, but prevents branching inside each iteration and reduces the load on the processor’s branch predictor (especially useful if you have other branches in the loop body).
You’ll need to use wyz::BidiIterator;
to gain access to the .bidi()
adapter, which is provided for all DoubleEndedIterator
types.
wyz::range
This provides some range normalization and convenience methods I use in bitvec
to cut down on how many nearly-identical blocks of code I need to deal with Rust’s various range (-inclusive, -from, -to, -to-inclusive, -full) types.
wyz::exit
The exit!
macro functions like panic!
except that it calls std::process::exit
instead of kicking off an unwind, and optionally returns a status code to the operating system.
It is superseded by the fact that fn main() -> Result<(), impl Termination>
has been allowed since Rust 1.26. There’s no point in its existence anymore, I don’t think anybody uses it, and I just haven’t gotten around to deleting it yet.