use crate::sorted_set::SortedSet;
use camino::Utf8Path;
use std::{borrow::Borrow, cmp::Ordering};
pub struct BuildTarget<'g> {
id: BuildTargetId<'g>,
inner: &'g BuildTargetImpl,
}
impl<'g> BuildTarget<'g> {
pub(super) fn new((id, inner): (&'g OwnedBuildTargetId, &'g BuildTargetImpl)) -> Self {
Self {
id: id.as_borrowed(),
inner,
}
}
#[inline]
pub fn id(&self) -> BuildTargetId<'g> {
self.id
}
pub fn name(&self) -> &'g str {
match self.id {
BuildTargetId::Library | BuildTargetId::BuildScript => self
.inner
.lib_name
.as_ref()
.expect("library targets have lib_name set"),
other => other.name().expect("non-library targets can't return None"),
}
}
#[inline]
pub fn kind(&self) -> BuildTargetKind<'g> {
BuildTargetKind::new(&self.inner.kind)
}
#[inline]
pub fn required_features(&self) -> &'g [String] {
&self.inner.required_features
}
#[inline]
pub fn path(&self) -> &'g Utf8Path {
&self.inner.path
}
#[inline]
pub fn edition(&self) -> &'g str {
&self.inner.edition
}
#[inline]
pub fn doc_by_default(&self) -> bool {
self.inner.doc_by_default
}
#[inline]
pub fn doctest_by_default(&self) -> bool {
self.inner.doctest_by_default
}
#[deprecated(since = "0.17.16", note = "use `doctest_by_default` instead")]
#[inline]
pub fn doc_tests(&self) -> bool {
self.inner.doctest_by_default
}
#[inline]
pub fn test_by_default(&self) -> bool {
self.inner.test_by_default
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub enum BuildTargetId<'g> {
Library,
BuildScript,
Binary(&'g str),
Example(&'g str),
Test(&'g str),
Benchmark(&'g str),
}
impl<'g> BuildTargetId<'g> {
pub fn name(&self) -> Option<&'g str> {
match self {
BuildTargetId::Library => None,
BuildTargetId::BuildScript => None,
BuildTargetId::Binary(name) => Some(name),
BuildTargetId::Example(name) => Some(name),
BuildTargetId::Test(name) => Some(name),
BuildTargetId::Benchmark(name) => Some(name),
}
}
pub(super) fn as_key(&self) -> &(dyn BuildTargetKey + 'g) {
self
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub enum BuildTargetKind<'g> {
LibraryOrExample(&'g [String]),
ProcMacro,
Binary,
}
impl<'g> BuildTargetKind<'g> {
fn new(inner: &'g BuildTargetKindImpl) -> Self {
match inner {
BuildTargetKindImpl::LibraryOrExample(crate_types) => {
BuildTargetKind::LibraryOrExample(crate_types.as_slice())
}
BuildTargetKindImpl::ProcMacro => BuildTargetKind::ProcMacro,
BuildTargetKindImpl::Binary => BuildTargetKind::Binary,
}
}
}
#[derive(Clone, Debug)]
pub(super) struct BuildTargetImpl {
pub(super) kind: BuildTargetKindImpl,
pub(super) lib_name: Option<Box<str>>,
pub(super) required_features: Vec<String>,
pub(super) path: Box<Utf8Path>,
pub(super) edition: Box<str>,
pub(super) doc_by_default: bool,
pub(super) doctest_by_default: bool,
pub(super) test_by_default: bool,
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(all(test, feature = "proptest1"), derive(proptest_derive::Arbitrary))]
pub(super) enum OwnedBuildTargetId {
Library,
BuildScript,
Binary(Box<str>),
Example(Box<str>),
Test(Box<str>),
Benchmark(Box<str>),
}
impl OwnedBuildTargetId {
fn as_borrowed(&self) -> BuildTargetId<'_> {
match self {
OwnedBuildTargetId::Library => BuildTargetId::Library,
OwnedBuildTargetId::BuildScript => BuildTargetId::BuildScript,
OwnedBuildTargetId::Binary(name) => BuildTargetId::Binary(name.as_ref()),
OwnedBuildTargetId::Example(name) => BuildTargetId::Example(name.as_ref()),
OwnedBuildTargetId::Test(name) => BuildTargetId::Test(name.as_ref()),
OwnedBuildTargetId::Benchmark(name) => BuildTargetId::Benchmark(name.as_ref()),
}
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub(super) enum BuildTargetKindImpl {
LibraryOrExample(SortedSet<String>),
ProcMacro,
Binary,
}
pub(super) trait BuildTargetKey {
fn key(&self) -> BuildTargetId<'_>;
}
impl BuildTargetKey for BuildTargetId<'_> {
fn key(&self) -> BuildTargetId<'_> {
*self
}
}
impl BuildTargetKey for OwnedBuildTargetId {
fn key(&self) -> BuildTargetId<'_> {
self.as_borrowed()
}
}
impl<'g> Borrow<dyn BuildTargetKey + 'g> for OwnedBuildTargetId {
fn borrow(&self) -> &(dyn BuildTargetKey + 'g) {
self
}
}
impl PartialEq for dyn BuildTargetKey + '_ {
fn eq(&self, other: &Self) -> bool {
self.key() == other.key()
}
}
impl Eq for dyn BuildTargetKey + '_ {}
impl PartialOrd for dyn BuildTargetKey + '_ {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for dyn BuildTargetKey + '_ {
fn cmp(&self, other: &Self) -> Ordering {
self.key().cmp(&other.key())
}
}
#[cfg(all(test, feature = "proptest1"))]
mod tests {
use super::*;
use proptest::prelude::*;
impl OwnedBuildTargetId {
fn as_key(&self) -> &dyn BuildTargetKey {
self
}
}
proptest! {
#[test]
fn consistent_borrow(id1 in any::<OwnedBuildTargetId>(), id2 in any::<OwnedBuildTargetId>()) {
prop_assert_eq!(
id1.eq(&id1),
id1.as_key().eq(id1.as_key()),
"consistent eq implementation (same IDs)"
);
prop_assert_eq!(
id1.eq(&id2),
id1.as_key().eq(id2.as_key()),
"consistent eq implementation (different IDs)"
);
prop_assert_eq!(
id1.partial_cmp(&id2),
id1.as_key().partial_cmp(id2.as_key()),
"consistent partial_cmp implementation"
);
prop_assert_eq!(
id1.cmp(&id2),
id1.as_key().cmp(id2.as_key()),
"consistent cmp implementation"
);
}
}
}