blob: 7f75e5b35a2047a97d2a10b610c5baa68a6c3b17 [file] [log] [blame]
use smallvec::SmallVec;
use std::fmt::Debug;
use std::hash::Hash;
use crate::{DebugWithInfcx, Mutability};
pub trait Interner: Sized {
type DefId: Clone + Debug + Hash + Ord;
type AdtDef: Clone + Debug + Hash + Ord;
type GenericArgs: Clone
+ DebugWithInfcx<Self>
+ Hash
+ Ord
+ IntoIterator<Item = Self::GenericArg>;
type GenericArg: Clone + DebugWithInfcx<Self> + Hash + Ord;
type Term: Clone + Debug + Hash + Ord;
type Binder<T>;
type TypeAndMut: Clone + Debug + Hash + Ord;
type CanonicalVars: Clone + Debug + Hash + Eq;
// Kinds of tys
type Ty: Clone + DebugWithInfcx<Self> + Hash + Ord;
type Tys: Clone + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>;
type AliasTy: Clone + DebugWithInfcx<Self> + Hash + Ord;
type ParamTy: Clone + Debug + Hash + Ord;
type BoundTy: Clone + Debug + Hash + Ord;
type PlaceholderTy: Clone + Debug + Hash + Ord;
type InferTy: Clone + DebugWithInfcx<Self> + Hash + Ord;
// Things stored inside of tys
type ErrorGuaranteed: Clone + Debug + Hash + Ord;
type BoundExistentialPredicates: Clone + DebugWithInfcx<Self> + Hash + Ord;
type PolyFnSig: Clone + DebugWithInfcx<Self> + Hash + Ord;
type AllocId: Clone + Debug + Hash + Ord;
// Kinds of consts
type Const: Clone + DebugWithInfcx<Self> + Hash + Ord;
type InferConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
type AliasConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
type PlaceholderConst: Clone + Debug + Hash + Ord;
type ParamConst: Clone + Debug + Hash + Ord;
type BoundConst: Clone + Debug + Hash + Ord;
type ValueConst: Clone + Debug + Hash + Ord;
type ExprConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
// Kinds of regions
type Region: Clone + DebugWithInfcx<Self> + Hash + Ord;
type EarlyBoundRegion: Clone + Debug + Hash + Ord;
type BoundRegion: Clone + Debug + Hash + Ord;
type FreeRegion: Clone + Debug + Hash + Ord;
type InferRegion: Clone + DebugWithInfcx<Self> + Hash + Ord;
type PlaceholderRegion: Clone + Debug + Hash + Ord;
// Predicates
type Predicate: Clone + Debug + Hash + Eq;
type TraitPredicate: Clone + Debug + Hash + Eq;
type RegionOutlivesPredicate: Clone + Debug + Hash + Eq;
type TypeOutlivesPredicate: Clone + Debug + Hash + Eq;
type ProjectionPredicate: Clone + Debug + Hash + Eq;
type SubtypePredicate: Clone + Debug + Hash + Eq;
type CoercePredicate: Clone + Debug + Hash + Eq;
type ClosureKind: Clone + Debug + Hash + Eq;
fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Mutability);
}
/// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
/// that produces `T` items. You could combine them with
/// `f(&iter.collect::<Vec<_>>())`, but this requires allocating memory for the
/// `Vec`.
///
/// This trait allows for faster implementations, intended for cases where the
/// number of items produced by the iterator is small. There is a blanket impl
/// for `T` items, but there is also a fallible impl for `Result<T, E>` items.
pub trait CollectAndApply<T, R>: Sized {
type Output;
/// Produce a result of type `Self::Output` from `iter`. The result will
/// typically be produced by applying `f` on the elements produced by
/// `iter`, though this may not happen in some impls, e.g. if an error
/// occurred during iteration.
fn collect_and_apply<I, F>(iter: I, f: F) -> Self::Output
where
I: Iterator<Item = Self>,
F: FnOnce(&[T]) -> R;
}
/// The blanket impl that always collects all elements and applies `f`.
impl<T, R> CollectAndApply<T, R> for T {
type Output = R;
/// Equivalent to `f(&iter.collect::<Vec<_>>())`.
fn collect_and_apply<I, F>(mut iter: I, f: F) -> R
where
I: Iterator<Item = T>,
F: FnOnce(&[T]) -> R,
{
// This code is hot enough that it's worth specializing for the most
// common length lists, to avoid the overhead of `SmallVec` creation.
// Lengths 0, 1, and 2 typically account for ~95% of cases. If
// `size_hint` is incorrect a panic will occur via an `unwrap` or an
// `assert`.
match iter.size_hint() {
(0, Some(0)) => {
assert!(iter.next().is_none());
f(&[])
}
(1, Some(1)) => {
let t0 = iter.next().unwrap();
assert!(iter.next().is_none());
f(&[t0])
}
(2, Some(2)) => {
let t0 = iter.next().unwrap();
let t1 = iter.next().unwrap();
assert!(iter.next().is_none());
f(&[t0, t1])
}
_ => f(&iter.collect::<SmallVec<[_; 8]>>()),
}
}
}
/// A fallible impl that will fail, without calling `f`, if there are any
/// errors during collection.
impl<T, R, E> CollectAndApply<T, R> for Result<T, E> {
type Output = Result<R, E>;
/// Equivalent to `Ok(f(&iter.collect::<Result<Vec<_>>>()?))`.
fn collect_and_apply<I, F>(mut iter: I, f: F) -> Result<R, E>
where
I: Iterator<Item = Result<T, E>>,
F: FnOnce(&[T]) -> R,
{
// This code is hot enough that it's worth specializing for the most
// common length lists, to avoid the overhead of `SmallVec` creation.
// Lengths 0, 1, and 2 typically account for ~95% of cases. If
// `size_hint` is incorrect a panic will occur via an `unwrap` or an
// `assert`, unless a failure happens first, in which case the result
// will be an error anyway.
Ok(match iter.size_hint() {
(0, Some(0)) => {
assert!(iter.next().is_none());
f(&[])
}
(1, Some(1)) => {
let t0 = iter.next().unwrap()?;
assert!(iter.next().is_none());
f(&[t0])
}
(2, Some(2)) => {
let t0 = iter.next().unwrap()?;
let t1 = iter.next().unwrap()?;
assert!(iter.next().is_none());
f(&[t0, t1])
}
_ => f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?),
})
}
}