use crate::imports::*;
use crate::prelude::*;
-#[macro_export]
-macro_rules! ensure_eq {
- ($v1:expr, $v2:expr) => {
- ({
- let v1 = &$v1;
- let v2 = &$v2;
- if v1 != v2 {
- Err(anyhow!("ensure_eq failed: {} != {}: {:?} != {:?}",
- stringify!($v1), stringify!($v2),
- v1, v2))
- } else {
- Ok(())
- }
- }?)
+/*
+put trait OptionExt {
+ type Output;
+ fn get_or_try_insert_with<
+ E: Error,
+ F: FnOnce() -> Result<Output,E>,
+ >(&mut self, f: F) -> Result<&mut Output, E>;
+}
+
+impl<T> OptionExt for Option<T> {
+ type Output = T;
+ fn get_or_try_insert_with<E,F>
+ (&mut self, f: F) -> Result<&mut Output, E>
+ where E: Error, F: FnOnce() -> Result<Output,E>,
+ {
+ if self.is_none() {
+ *self = Some(f()?);
+ }
+ Ok(self.as_mut().unwrap())
}
}
+*/
+
+//========== miscellany ==========
+// (roughly in order of implementation length)
+
+pub fn is_default<T: ConstDefault + Eq>(t: &T) -> bool { t == &T::DEFAULT }
+
+// TODO: this is not used anywhere!
+#[derive(Error,Clone,Copy,Debug,Eq,PartialEq,Serialize,Deserialize)]
+#[error("error parsing Z coordinate")]
+pub struct FooParseError;
+
+#[ext(pub, name=SeekExt)]
+impl<T: io::Seek> T {
+ #[throws(io::Error)]
+ fn rewind(&mut self) { self.seek(io::SeekFrom::Start(0))? }
+}
#[ext(pub, name=OrdExt)]
impl<T: Ord + Sized + Clone> T {
}
}
+#[derive(Debug,Clone)]
+pub struct JsonString<T:Serialize>(pub T);
+impl<T> Serialize for JsonString<T> where T:Serialize {
+ #[throws(S::Error)]
+ fn serialize<S>(&self, s: S) -> S::Ok where S:Serializer {
+ let json = serde_json::to_string(&self.0)
+ .map_err(|e| <S::Error as serde::ser::Error>::custom(e))?;
+ Serialize::serialize(&json, s)?
+ }
+}
+
+#[throws(Either<io::Error, io::Error>)]
+pub fn io_copy_interactive<R,W>(read: &mut BufReader<R>, write: &mut W)
+where R: Read, W: Write {
+ loop {
+ let buf = read.fill_buf().map_err(Either::Left)?;
+ if buf.len() == 0 { break }
+
+ let did = (||{
+ let did = write.write(buf)?;
+ if did == 0 { throw!(ErrorKind::WriteZero) }
+ Ok::<_,io::Error>(did)
+ })().map_err(Either::Right)?;
+
+ read.consume(did);
+ write.flush().map_err(Either::Right)?;
+ }
+}
+
+/// Allows the use of serde for a compat struct
+///
+/// Ideally we would have
+/// ```rust ignore
+/// #[derive(Deserialize)]
+/// #[serde(try_from=Compat)]
+/// struct Main { /* new definition */ }
+///
+/// #[derive(Deserialize)]
+/// #[serde(untagged)]
+/// enum Compat { V1(Main), V2(Old) }
+///
+/// #[derive(Deserialize)]
+/// struct Old { /* old version we still want to read */ }
+///
+/// impl TryFrom<Compat> for Main { /* ... */ }
+/// ```
+///
+/// But the impl for `Compat` ends up honouring the `try_from` on `Main`
+/// so is recursive. We solve that abusing serde's remote feature.
+///
+/// For an example, see `IOccultIlk`.
+///
+/// The name of the main structure must be passed twice, once as an
+/// identifier and once as a literal, because `stringify!` doesn't work
+/// in the serde attribute.
+#[macro_export]
+macro_rules! serde_with_compat { {
+ [ $( #[ $($attrs:meta)* ] )* ] [ $vis:vis ] [ $($intro:tt)* ]
+ $main:ident=$main_s:literal $new:ident $compat_s:literal
+ [ $($body:tt)* ]
+} => {
+ $(#[ $($attrs)* ])*
+ #[serde(try_from=$compat_s)]
+ $vis $($intro)* $main $($body)*
+
+ #[allow(non_camel_case_types)]
+ $(#[ $($attrs)* ])*
+ #[serde(remote=$main_s)]
+ $($intro)* $new $($body)*
+} }
+
+//---------- Timespec (for serde) ----------
+
+pub mod timespec_serde {
+ use super::*;
+
+ #[derive(Serialize, Deserialize)]
+ struct Timespec(i64, u32);
+
+ #[throws(S::Error)]
+ pub fn serialize<S:Serializer>(v: &TimeSpec, s: S) -> S::Ok {
+ let v = Timespec(v.tv_sec(), v.tv_nsec().try_into().unwrap());
+ Serialize::serialize(&v, s)?
+ }
+ #[throws(D::Error)]
+ pub fn deserialize<'de, D:Deserializer<'de>>(d: D) -> TimeSpec {
+ let Timespec(sec, nsec) = Deserialize::deserialize(d)?;
+ libc::timespec { tv_sec: sec, tv_nsec: nsec.into() }.into()
+ }
+}
+
+//---------- emptytype ----------
+
+// TODO: replace with Void
+
+pub trait EmptyType { fn diverge<T>(self) -> T; }
+
+impl EmptyType for Infallible {
+ fn diverge<T>(self) -> T { match self { } }
+}
+
+//---------- IpAddress ----------
+
+pub trait IpAddress: Debug {
+ fn with_port(&self, port: u16) -> SocketAddr;
+}
+
+impl<A> IpAddress for A where A: Into<IpAddr> + Debug + Clone {
+ fn with_port(&self, port: u16) -> SocketAddr {
+ match (self.clone().into(), port)
+ .to_socket_addrs()
+ .map(|i| i.at_most_one()) {
+ Ok(Ok(Some(addr))) => addr,
+ x => panic!("{:?},{} gave {:?}", self, port, x),
+ }
+ }
+}
+
+//---------- get_or_extend_with ----------
+
+
+#[ext(pub)]
+impl<T> Vec<T> {
+ fn get_or_extend_with<F>(&mut self, i: usize, f: F) -> &mut T
+ where F: FnMut() -> T {
+ if self.get(i).is_none() {
+ self.resize_with(i+1, f);
+ }
+ &mut self[i]
+ }
+}
+
+#[ext(pub)]
+impl<I,T> IndexVec<I,T> where I: index_vec::Idx {
+ fn get_or_extend_with<F>(&mut self, i: I, f: F) -> &mut T
+ where F: FnMut() -> T {
+ self.raw.get_or_extend_with(i.index(), f)
+ }
+}
+
+//========== OldNew ==========
+
#[derive(Copy,Clone,Debug,From,Into)]
#[derive(Hash,Eq,PartialEq,Serialize,Deserialize)]
#[serde(transparent)]
fn index(&self, i: OldNewIndex) -> &T { &self.0[i as usize] }
}
-/*
-put trait OptionExt {
- type Output;
- fn get_or_try_insert_with<
- E: Error,
- F: FnOnce() -> Result<Output,E>,
- >(&mut self, f: F) -> Result<&mut Output, E>;
-}
-
-impl<T> OptionExt for Option<T> {
- type Output = T;
- fn get_or_try_insert_with<E,F>
- (&mut self, f: F) -> Result<&mut Output, E>
- where E: Error, F: FnOnce() -> Result<Output,E>,
- {
- if self.is_none() {
- *self = Some(f()?);
- }
- Ok(self.as_mut().unwrap())
- }
-}
-*/
-
-// https://github.com/rust-lang/rust/issues/32255 :-(
-
-#[ext(pub, name=LocalFileExt, supertraits=Sized)]
-impl fs::File {
- #[throws(io::Error)]
- fn close(self) {
- let r = unsafe {
- let fd = self.into_raw_fd();
- libc::close(fd)
- };
- if r == 0 {
- ()
- } else if r == -1 {
- throw!(io::Error::last_os_error())
- } else {
- panic!("close(2) returned {}", r)
- }
- }
-}
-
+//========== Thunk ==========
// todo #[derive(Clone)]
pub struct Thunk<U: Sync, F: Sync + FnOnce() -> U> (
// todo: DerefMut
-#[derive(Error,Clone,Copy,Debug,Eq,PartialEq,Serialize,Deserialize)]
-#[error("error parsing Z coordinate")]
-pub struct FooParseError;
-
-pub mod timespec_serde {
- use super::*;
-
- #[derive(Serialize, Deserialize)]
- struct Timespec(i64, u32);
-
- #[throws(S::Error)]
- pub fn serialize<S:Serializer>(v: &TimeSpec, s: S) -> S::Ok {
- let v = Timespec(v.tv_sec(), v.tv_nsec().try_into().unwrap());
- Serialize::serialize(&v, s)?
- }
- #[throws(D::Error)]
- pub fn deserialize<'de, D:Deserializer<'de>>(d: D) -> TimeSpec {
- let Timespec(sec, nsec) = Deserialize::deserialize(d)?;
- libc::timespec { tv_sec: sec, tv_nsec: nsec.into() }.into()
- }
-}
+//========== toml_merge ====================
pub fn toml_merge<'u,
S: 'u + AsRef<str>,
}
}
-#[derive(Debug,Clone)]
-pub struct JsonString<T:Serialize>(pub T);
-impl<T> Serialize for JsonString<T> where T:Serialize {
- #[throws(S::Error)]
- fn serialize<S>(&self, s: S) -> S::Ok where S:Serializer {
- let json = serde_json::to_string(&self.0)
- .map_err(|e| <S::Error as serde::ser::Error>::custom(e))?;
- Serialize::serialize(&json, s)?
- }
-}
-
-#[macro_export]
-macro_rules! deref_to_field {
- {$({ $($gen:tt)* })? $outer:ty, $inner:ty, $($field:tt)*} => {
- impl $(< $($gen)* >)? Deref for $outer {
- type Target = $inner;
- fn deref(&self) -> &$inner { &self.$($field)* }
- }
- }
-}
-#[macro_export]
-macro_rules! deref_to_field_mut {
- {$({ $($gen:tt)* })? $outer:ty, $inner:ty, $($field:tt)*} => {
- deref_to_field!{ $({ $($gen)* })? $outer, $inner, $($field)*}
- impl $(< $($gen)* >)? DerefMut for $outer {
- fn deref_mut(&mut self) -> &mut $inner { &mut self.$($field)* }
- }
- }
-}
-
-pub trait EmptyType { fn diverge<T>(self) -> T; }
-
-impl EmptyType for Infallible {
- fn diverge<T>(self) -> T { match self { } }
-}
-
-#[macro_export] // <- otherwise bogus warning `unused_macros`
-macro_rules! matches_doesnot_yn2bool {
- (=) => (true);
- (!) => (false);
-}
-
-#[macro_export]
-macro_rules! matches_doesnot {
- ($v:expr,
- $(
- $yn:tt $p:pat
- ),* $(,)?
- ) => {
- match $v {
- $(
- $p => $crate::matches_doesnot_yn2bool!($yn),
- )*
- }
- }
-}
-
-#[test]
-fn matches_doesnot_test() {
- assert!(
- matches_doesnot!(
- Some(42),
- = Some(_),
- ! None
- )
- );
- assert!(
- matches_doesnot!(
- Some(42),
- ! None,
- ! Some(3),
- = Some(_),
- )
- );
- assert!(
- matches_doesnot!(
- Some(1),
- = Some(1) | Some(2),
- ! Some(_) | None
- )
- );
- assert!(
- ! matches_doesnot!(
- Some(1),
- ! Some(1) | Some(2),
- = Some(_) | None
- )
- );
-}
-
-#[macro_export]
-macro_rules! trace_dbg {
- ($msg:expr $(,$val:expr)*) => {
- if log_enabled!(log::Level::Trace) {
- #[allow(unused_mut)]
- let mut buf = format!("{}", &$msg);
- $( write!(&mut buf, " {}={:?}", stringify!($val), &$val).unwrap(); )*
- trace!("{}", buf);
- }
- }
-
-}
-
-#[macro_export]
-macro_rules! want_failed_internal {
- { $variant:ident($binding:pat) = $input:expr, $x:expr, $($d:expr),* } => {
- InternalLogicError::new({
- #[allow(unused_mut)]
- let mut s = format!("wanted {}({}) = {}, but got {:?}",
- stringify!($variant), stringify!($binding),
- stringify!($input), $x);
- $(
- write!(&mut s, " {}={:?}", stringify!($d), &$d).unwrap();
- )*
- s
- }).tolerate()
- }
-}
-
-#[macro_export]
-macro_rules! want {
- { $variant:ident = $input:expr,
- ? $($d:expr),*
- } => (
- match $input {
- $variant(y) => Some(y),
- x => {
- want_failed_internal!{ $variant(_)=$input, x, $($d),* }
- None
- },
- }
- );
- { $variant:ident = $input:expr } => {
- want!( $variant = $input,
- ? )
- };
-}
-
-#[macro_export]
-macro_rules! wants {
- { $($d:tt)* } => { want!(Some = $($d)*) }
-}
-#[macro_export]
-macro_rules! wantok {
- { $($d:tt)* } => { want!(Ok = $($d)*) }
-}
-
-#[macro_export]
-macro_rules! want_let {
- { $($variant:ident)::+($binding:pat) = $input:expr;
- else ? $($d:expr),*; $($otherwise:tt)*
- } => {
- let $binding = match $input {
- $($variant(y))::+ => y,
- x => {
- want_failed_internal!{
- $($variant)::+($binding)=$input, x, $($d),*
- }
- $($otherwise)*
- },
- };
- };
- { $($variant:ident)::+($binding:pat) = $input:expr;
- else $($otherwise:tt)*
- } => {
- want_let!{ $($variant($binding))::+ = $input; else ?; $($otherwise)* }
- };
-}
-
-/// Allows the use of serde for a compat struct
-///
-/// Ideally we would have
-/// ```rust ignore
-/// #[derive(Deserialize)]
-/// #[serde(try_from=Compat)]
-/// struct Main { /* new definition */ }
-///
-/// #[derive(Deserialize)]
-/// #[serde(untagged)]
-/// enum Compat { V1(Main), V2(Old) }
-///
-/// #[derive(Deserialize)]
-/// struct Old { /* old version we still want to read */ }
-///
-/// impl TryFrom<Compat> for Main { /* ... */ }
-/// ```
-///
-/// But the impl for `Compat` ends up honouring the `try_from` on `Main`
-/// so is recursive. We solve that abusing serde's remote feature.
-///
-/// For an example, see `IOccultIlk`.
-///
-/// The name of the main structure must be passed twice, once as an
-/// identifier and once as a literal, because `stringify!` doesn't work
-/// in the serde attribute.
-#[macro_export]
-macro_rules! serde_with_compat { {
- [ $( #[ $($attrs:meta)* ] )* ] [ $vis:vis ] [ $($intro:tt)* ]
- $main:ident=$main_s:literal $new:ident $compat_s:literal
- [ $($body:tt)* ]
-} => {
- $(#[ $($attrs)* ])*
- #[serde(try_from=$compat_s)]
- $vis $($intro)* $main $($body)*
-
- #[allow(non_camel_case_types)]
- $(#[ $($attrs)* ])*
- #[serde(remote=$main_s)]
- $($intro)* $new $($body)*
-} }
+//========== .insert() and .remove() on various Entry ==========
macro_rules! entry_define_insert_remove {
{ $name:ident, $name_mod:ident, $entry:path, $into_key:ident } =>
key
}
-#[derive(Debug,Copy,Clone,Eq,PartialEq,Ord,PartialOrd)]
-#[derive(From,Into)]
-#[derive(Serialize, Deserialize)]
-#[serde(into="Duration", try_from="Duration")]
-pub struct FutureInstant(pub Instant);
-
-impl Into<Duration> for FutureInstant {
- fn into(self) -> Duration {
- let now = config().global_clock.now();
- Instant::from(self).checked_duration_since(now).unwrap_or_default()
- }
-}
-
-#[derive(Error,Debug)]
-#[error("Duration (eg during load) implies out-of-range FutureInstant")]
-pub struct FutureInstantOutOfRange;
-
-impl TryFrom<Duration> for FutureInstant {
- type Error = FutureInstantOutOfRange;
- #[throws(FutureInstantOutOfRange)]
- fn try_from(duration: Duration) -> FutureInstant {
- let now = config().global_clock.now();
- now.checked_add(duration).ok_or(FutureInstantOutOfRange)?.into()
- }
-}
-
-
-#[derive(Debug,Copy,Clone)]
-pub struct DigestRead<D: Digest, R: Read> {
- d: D,
- r: R,
-}
-
-impl<D: Digest, R: Read> DigestRead<D, R> {
- pub fn new(r: R) -> Self { DigestRead { r, d: D::new() } }
- pub fn into_inner(self) -> (D, R) { (self.d, self.r) }
- pub fn finish(self) -> digest::Output<D> {
- self.d.finalize()
- }
-}
-
-impl<D: Digest, R: Read> Read for DigestRead<D, R> {
- #[throws(io::Error)]
- fn read(&mut self, buf: &mut [u8]) -> usize {
- let count = self.r.read(buf)?;
- self.d.update(&buf[0..count]);
- count
- }
-}
-
-#[test]
-#[cfg(not(miri))]
-fn test_digest_read() {
- let ibuffer = b"abc";
- let exp = Sha512_256::digest(&ibuffer[..]);
- let inner = &ibuffer[..];
- let mut dr = DigestRead::<Sha512_256,_>::new(inner);
- let mut obuffer = [0;4];
- assert_eq!( dr.read(&mut obuffer).unwrap(), 3 );
- assert_eq!( &obuffer, b"abc\0" );
- let got = dr.finish();
- assert_eq!( got, exp );
-}
-
-#[derive(Debug,Copy,Clone)]
-pub struct DigestWrite<D: Digest, W: Write> {
- d: D,
- w: W,
-}
-
-impl<D: Digest, W: Write> DigestWrite<D, W> {
- pub fn new(w: W) -> Self { DigestWrite { w, d: D::new() } }
- pub fn into_inner(self) -> (D, W) { (self.d, self.w) }
- pub fn finish(self) -> (digest::Output<D>, W) {
- (self.d.finalize(), self.w)
- }
-}
-impl<D: Digest> DigestWrite<D, io::Sink> {
- pub fn sink() -> Self { DigestWrite::new(io::sink()) }
-
- #[throws(io::Error)]
- pub fn of<R>(r: &mut R) -> digest::Output<D> where R: Read {
- let mut dw = DigestWrite::<D,_>::sink();
- io::copy(r, &mut dw)?;
- dw.finish().0
- }
-}
-
-impl<D: Digest, W: Write> Write for DigestWrite<D, W> {
- #[throws(io::Error)]
- fn write(&mut self, buf: &[u8]) -> usize {
- let count = self.w.write(buf)?;
- self.d.update(&buf[0..count]);
- count
- }
- #[throws(io::Error)]
- fn flush(&mut self) { self.w.flush()? }
-}
-
-#[test]
-#[cfg(not(miri))]
-fn test_digest_write() {
- let ibuffer = b"xyz";
- let exp = Sha512_256::digest(&ibuffer[..]);
- let mut obuffer = [0;4];
- let inner = &mut obuffer[..];
- let mut dw = bundles::DigestWrite::new(inner);
- assert_eq!( dw.write(&ibuffer[..]).unwrap(), 3);
- let (got, recov) = dw.finish();
- assert_eq!( recov, b"\0" );
- assert_eq!( got, exp );
- assert_eq!( &obuffer, b"xyz\0" );
-}
-
-#[ext(pub, name=SeekExt)]
-impl<T: io::Seek> T {
- #[throws(io::Error)]
- fn rewind(&mut self) { self.seek(io::SeekFrom::Start(0))? }
-}
-
-#[ext(pub)]
-impl<T> Vec<T> {
- fn get_or_extend_with<F>(&mut self, i: usize, f: F) -> &mut T
- where F: FnMut() -> T {
- if self.get(i).is_none() {
- self.resize_with(i+1, f);
- }
- &mut self[i]
+//========== FutureInstant ==========
+
+#[derive(Debug,Copy,Clone,Eq,PartialEq,Ord,PartialOrd)]
+#[derive(From,Into)]
+#[derive(Serialize, Deserialize)]
+#[serde(into="Duration", try_from="Duration")]
+pub struct FutureInstant(pub Instant);
+
+impl Into<Duration> for FutureInstant {
+ fn into(self) -> Duration {
+ let now = config().global_clock.now();
+ Instant::from(self).checked_duration_since(now).unwrap_or_default()
}
}
-#[ext(pub)]
-impl<I,T> IndexVec<I,T> where I: index_vec::Idx {
- fn get_or_extend_with<F>(&mut self, i: I, f: F) -> &mut T
- where F: FnMut() -> T {
- self.raw.get_or_extend_with(i.index(), f)
+#[derive(Error,Debug)]
+#[error("Duration (eg during load) implies out-of-range FutureInstant")]
+pub struct FutureInstantOutOfRange;
+
+impl TryFrom<Duration> for FutureInstant {
+ type Error = FutureInstantOutOfRange;
+ #[throws(FutureInstantOutOfRange)]
+ fn try_from(duration: Duration) -> FutureInstant {
+ let now = config().global_clock.now();
+ now.checked_add(duration).ok_or(FutureInstantOutOfRange)?.into()
}
-}
+}
-pub fn is_default<T: ConstDefault + Eq>(t: &T) -> bool { t == &T::DEFAULT }
+//========== Error handling ==========
#[derive(Debug)]
pub struct AnyhowDisplay<'a>(pub &'a anyhow::Error);
}
}
-#[throws(Either<io::Error, io::Error>)]
-pub fn io_copy_interactive<R,W>(read: &mut BufReader<R>, write: &mut W)
-where R: Read, W: Write {
- loop {
- let buf = read.fill_buf().map_err(Either::Left)?;
- if buf.len() == 0 { break }
+//========== IO - File::close ==========
- let did = (||{
- let did = write.write(buf)?;
- if did == 0 { throw!(ErrorKind::WriteZero) }
- Ok::<_,io::Error>(did)
- })().map_err(Either::Right)?;
-
- read.consume(did);
- write.flush().map_err(Either::Right)?;
+// https://github.com/rust-lang/rust/issues/32255 :-(
+
+#[ext(pub, name=LocalFileExt, supertraits=Sized)]
+impl fs::File {
+ #[throws(io::Error)]
+ fn close(self) {
+ let r = unsafe {
+ let fd = self.into_raw_fd();
+ libc::close(fd)
+ };
+ if r == 0 {
+ ()
+ } else if r == -1 {
+ throw!(io::Error::last_os_error())
+ } else {
+ panic!("close(2) returned {}", r)
+ }
}
}
+
+//========== IO - SigPipeWriter and RawStdout/CookedStdout ==========
+
pub struct SigPipeWriter<W>(pub W);
impl<W:Write> SigPipeWriter<W> {
fn drop(&mut self) { self.must_flush() }
}
-pub trait IpAddress: Debug {
- fn with_port(&self, port: u16) -> SocketAddr;
-}
-
-impl<A> IpAddress for A where A: Into<IpAddr> + Debug + Clone {
- fn with_port(&self, port: u16) -> SocketAddr {
- match (self.clone().into(), port)
- .to_socket_addrs()
- .map(|i| i.at_most_one()) {
- Ok(Ok(Some(addr))) => addr,
- x => panic!("{:?},{} gave {:?}", self, port, x),
- }
- }
-}
+//========== hex ==========
#[throws(fmt::Error)]
pub fn fmt_hex(f: &mut Formatter, buf: &[u8]) {
assert_eq!( parse_fixed_hex("1" ), None::<[_;1]> );
assert_eq!( parse_fixed_hex("xy" ), None::<[_;1]> );
}
+
+//========== matches_doesnot ==========
+
+#[macro_export] // <- otherwise bogus warning `unused_macros`
+macro_rules! matches_doesnot_yn2bool {
+ (=) => (true);
+ (!) => (false);
+}
+
+#[macro_export]
+macro_rules! matches_doesnot {
+ ($v:expr,
+ $(
+ $yn:tt $p:pat
+ ),* $(,)?
+ ) => {
+ match $v {
+ $(
+ $p => $crate::matches_doesnot_yn2bool!($yn),
+ )*
+ }
+ }
+}
+
+#[test]
+fn matches_doesnot_test() {
+ assert!(
+ matches_doesnot!(
+ Some(42),
+ = Some(_),
+ ! None
+ )
+ );
+ assert!(
+ matches_doesnot!(
+ Some(42),
+ ! None,
+ ! Some(3),
+ = Some(_),
+ )
+ );
+ assert!(
+ matches_doesnot!(
+ Some(1),
+ = Some(1) | Some(2),
+ ! Some(_) | None
+ )
+ );
+ assert!(
+ ! matches_doesnot!(
+ Some(1),
+ ! Some(1) | Some(2),
+ = Some(_) | None
+ )
+ );
+}
+
+//========== want* macros ==========
+
+#[macro_export]
+macro_rules! want_failed_internal {
+ { $variant:ident($binding:pat) = $input:expr, $x:expr, $($d:expr),* } => {
+ InternalLogicError::new({
+ #[allow(unused_mut)]
+ let mut s = format!("wanted {}({}) = {}, but got {:?}",
+ stringify!($variant), stringify!($binding),
+ stringify!($input), $x);
+ $(
+ write!(&mut s, " {}={:?}", stringify!($d), &$d).unwrap();
+ )*
+ s
+ }).tolerate()
+ }
+}
+
+#[macro_export]
+macro_rules! want {
+ { $variant:ident = $input:expr,
+ ? $($d:expr),*
+ } => (
+ match $input {
+ $variant(y) => Some(y),
+ x => {
+ want_failed_internal!{ $variant(_)=$input, x, $($d),* }
+ None
+ },
+ }
+ );
+ { $variant:ident = $input:expr } => {
+ want!( $variant = $input,
+ ? )
+ };
+}
+
+#[macro_export]
+macro_rules! wants {
+ { $($d:tt)* } => { want!(Some = $($d)*) }
+}
+#[macro_export]
+macro_rules! wantok {
+ { $($d:tt)* } => { want!(Ok = $($d)*) }
+}
+
+#[macro_export]
+macro_rules! want_let {
+ { $($variant:ident)::+($binding:pat) = $input:expr;
+ else ? $($d:expr),*; $($otherwise:tt)*
+ } => {
+ let $binding = match $input {
+ $($variant(y))::+ => y,
+ x => {
+ want_failed_internal!{
+ $($variant)::+($binding)=$input, x, $($d),*
+ }
+ $($otherwise)*
+ },
+ };
+ };
+ { $($variant:ident)::+($binding:pat) = $input:expr;
+ else $($otherwise:tt)*
+ } => {
+ want_let!{ $($variant($binding))::+ = $input; else ?; $($otherwise)* }
+ };
+}
+
+//========== miscellaneous macros ==========
+
+#[macro_export]
+macro_rules! trace_dbg {
+ ($msg:expr $(,$val:expr)*) => {
+ if log_enabled!(log::Level::Trace) {
+ #[allow(unused_mut)]
+ let mut buf = format!("{}", &$msg);
+ $( write!(&mut buf, " {}={:?}", stringify!($val), &$val).unwrap(); )*
+ trace!("{}", buf);
+ }
+ }
+
+}
+
+#[macro_export]
+macro_rules! ensure_eq {
+ ($v1:expr, $v2:expr) => {
+ ({
+ let v1 = &$v1;
+ let v2 = &$v2;
+ if v1 != v2 {
+ Err(anyhow!("ensure_eq failed: {} != {}: {:?} != {:?}",
+ stringify!($v1), stringify!($v2),
+ v1, v2))
+ } else {
+ Ok(())
+ }
+ }?)
+ }
+}
+
+#[macro_export]
+macro_rules! deref_to_field {
+ {$({ $($gen:tt)* })? $outer:ty, $inner:ty, $($field:tt)*} => {
+ impl $(< $($gen)* >)? Deref for $outer {
+ type Target = $inner;
+ fn deref(&self) -> &$inner { &self.$($field)* }
+ }
+ }
+}
+#[macro_export]
+macro_rules! deref_to_field_mut {
+ {$({ $($gen:tt)* })? $outer:ty, $inner:ty, $($field:tt)*} => {
+ deref_to_field!{ $({ $($gen)* })? $outer, $inner, $($field)*}
+ impl $(< $($gen)* >)? DerefMut for $outer {
+ fn deref_mut(&mut self) -> &mut $inner { &mut self.$($field)* }
+ }
+ }
+}