ci-cargo

CI for Rust code.
git clone https://git.philomathiclife.com/repos/ci-cargo
Log | Files | Refs | README

manifest.rs (150615B)


      1 use super::{
      2     args::NonZeroUsizePlus1,
      3     cargo::{Toolchain, ToolchainErr},
      4 };
      5 use alloc::borrow::Cow;
      6 use core::cmp::Ordering;
      7 use std::{
      8     fs,
      9     io::{Error, ErrorKind, StderrLock, Write as _},
     10     path::{Path, PathBuf},
     11 };
     12 use toml::{
     13     Spanned,
     14     de::{DeArray, DeValue, Error as TomlErr},
     15     map::Map,
     16 };
     17 /// `"workspace"`.
     18 const WORKSPACE: &str = "workspace";
     19 /// `"package"`.
     20 const PACKAGE: &str = "package";
     21 /// `"rust-version"`.
     22 const RUST_VERSION: &str = "rust-version";
     23 /// Error returned from extracting `"workspace"`.
     24 #[cfg_attr(test, derive(Debug, PartialEq))]
     25 #[derive(Clone, Copy)]
     26 pub(crate) enum WorkspaceErr {
     27     /// Variant returned when there is no `"workspace"` key.
     28     Missing,
     29     /// Variant returned when `"workspace"` is not a table.
     30     InvalidType,
     31     /// Variant returned when `workspace.package` does not exist.
     32     MissingPackage,
     33     /// Variant returned when `workspace.package` is not a table.
     34     InvalidPackageType,
     35     /// Variant returned when `workspace.package.rust-version` does not exist.
     36     MissingPackageMsrv,
     37     /// Variant returned when `workspace.package.rust-version` is not a string.
     38     InvalidPackageMsrvType,
     39     /// Variant returned when `workspace.package.rust-version` is not a valid MSRV.
     40     Msrv,
     41 }
     42 impl WorkspaceErr {
     43     /// Writes `self` to `stderr`.
     44     fn write(self, mut stderr: StderrLock<'_>, file: &Path) -> Result<(), Error> {
     45         match self {
     46             Self::Missing => writeln!(
     47                 stderr,
     48                 "'{WORKSPACE}' does not exist in {}.",
     49                 file.display()
     50             ),
     51             Self::InvalidType => writeln!(
     52                 stderr,
     53                 "'{WORKSPACE}' exists but is not a table in {}.",
     54                 file.display()
     55             ),
     56             Self::MissingPackage => writeln!(
     57                 stderr,
     58                 "'{WORKSPACE}.{PACKAGE}' does not exist in {}.",
     59                 file.display()
     60             ),
     61             Self::InvalidPackageType => writeln!(
     62                 stderr,
     63                 "'{WORKSPACE}.{PACKAGE}' exists but is not a table in {}.",
     64                 file.display()
     65             ),
     66             Self::MissingPackageMsrv => writeln!(
     67                 stderr,
     68                 "'{WORKSPACE}.{PACKAGE}.{RUST_VERSION}' does not exist in {}.",
     69                 file.display()
     70             ),
     71             Self::InvalidPackageMsrvType => writeln!(
     72                 stderr,
     73                 "'{WORKSPACE}.{PACKAGE}.{RUST_VERSION}' exists but is not a string in {}.",
     74                 file.display()
     75             ),
     76             Self::Msrv => writeln!(
     77                 stderr,
     78                 "'{WORKSPACE}.{PACKAGE}.{RUST_VERSION}' exists but is not a valid MSRV in {}.",
     79                 file.display()
     80             ),
     81         }
     82     }
     83 }
     84 /// `"name"`.
     85 const NAME: &str = "name";
     86 /// Error returned from extracting `"package"`.
     87 #[cfg_attr(test, derive(Debug))]
     88 pub(crate) enum PackageErr {
     89     /// Variant returned when there is no `"package"` key.
     90     Missing,
     91     /// Variant returned when `"package"` is not a table.
     92     InvalidType,
     93     /// Variant returned when `packagen.name` does not exist.
     94     MissingName,
     95     /// Variant returned when `package.name` is not a string.
     96     InvalidNameType,
     97     /// Variant returned when `package.rust-version` is not a string nor table.
     98     InvalidMsrvType,
     99     /// Variant returned when `package.rust-version` is not a valid MSRV.
    100     Msrv,
    101     /// Variant returned when `package.rust-version` is table that doesn't contain the `"workspace"` key.
    102     MsrvWorkspaceMissing,
    103     /// Variant returned when `package.rust-version.workspace` is not a Boolean with value `true`.
    104     MsrvWorkspaceVal,
    105     /// Variant returned when `package.workspace` is not a string.
    106     InvalidWorkspaceType,
    107     /// Variant returned when searching for the workspace file errors.
    108     WorkspaceIo(Error),
    109     /// Variant returned when there is no workspace `Cargo.toml`.
    110     ///
    111     /// This is only returned if the package's MSRV is inherited from the workspace, there is no
    112     /// `workspace` key in the package's `Cargo.toml`, and there is no `workspace` key in the table
    113     /// `package` (i.e., this is only returned when we must search for it by crawling up the directory).
    114     WorkspaceDoesNotExist,
    115     /// Variant returned when the file located at `package.workspace` could not be read.
    116     ///
    117     /// This is only returned if the table `package` had a key `workspace` that was a string, or we searched
    118     /// for the workspace and found a `Cargo.toml`.
    119     WorkspaceRead(Error, PathBuf),
    120     /// Variant returned when the file located at `package.workspace` is not valid TOML.
    121     ///
    122     /// This is only returned if the table `package` had a key `workspace` that was a string, or we searched
    123     /// for the workspace and found a `Cargo.toml`.
    124     WorkspaceToml(TomlErr, PathBuf),
    125     /// Variant returned when `package.rust-version` defers to the workspace MSRV, but there was an error
    126     /// extracting the workspace MSRV from the file located at the contained `PathBuf`.
    127     Workspace(WorkspaceErr, PathBuf),
    128 }
    129 impl PackageErr {
    130     /// Writes `self` to `stderr`.
    131     #[expect(clippy::unreachable, reason = "want to crash when there is a bug")]
    132     fn write(self, mut stderr: StderrLock<'_>, file: &Path) -> Result<(), Error> {
    133         match self {
    134             Self::Missing => writeln!(stderr, "'{PACKAGE}' does not exist in {}.", file.display()),
    135             Self::InvalidType => writeln!(
    136                 stderr,
    137                 "'{PACKAGE}' exists but is not a table in {}.",
    138                 file.display()
    139             ),
    140             Self::MissingName => writeln!(stderr, "'{PACKAGE}.{NAME}' does not exist in {}.", file.display()),
    141             Self::InvalidNameType => writeln!(
    142                 stderr,
    143                 "'{PACKAGE}.{NAME}' exists but is not a string in {}.",
    144                 file.display()
    145             ),
    146             Self::InvalidMsrvType => writeln!(
    147                 stderr,
    148                 "'{PACKAGE}.{RUST_VERSION}' exists but is not a string nor table in {}.",
    149                 file.display()
    150             ),
    151             Self::Msrv => writeln!(
    152                 stderr,
    153                 "'{PACKAGE}.{RUST_VERSION}' is a string but is not a valid MSRV in {}.",
    154                 file.display()
    155             ),
    156             Self::MsrvWorkspaceMissing => writeln!(
    157                 stderr,
    158                 "'{PACKAGE}.{RUST_VERSION}' is a table but does not contain the key '{WORKSPACE}' in {}.",
    159                 file.display()
    160             ),
    161             Self::MsrvWorkspaceVal => writeln!(
    162                 stderr,
    163                 "'{PACKAGE}.{RUST_VERSION}.{WORKSPACE}' exists but is not a Boolean or is not true in {}.",
    164                 file.display()
    165             ),
    166             Self::WorkspaceIo(e) => writeln!(
    167                 stderr,
    168                 "There was an error looking for the workspace Cargo.toml in {} and its ancestor directories: {e}.",
    169                 file.parent().unwrap_or_else(|| unreachable!("there is a bug in main. manifest::Manifest::from_toml must be passed the absolute path to the package's Cargo.toml.")).display(),
    170             ),
    171             Self::WorkspaceDoesNotExist => writeln!(
    172                 stderr,
    173                 "There is no workspace Cargo.toml in {} nor its ancestor directories.",
    174                 file.parent().unwrap_or_else(|| unreachable!("there is a bug in main. manifest::Manifest::from_toml must be passed the absolute path to the package's Cargo.toml.")).display(),
    175             ),
    176             Self::InvalidWorkspaceType => writeln!(
    177                 stderr,
    178                 "'{PACKAGE}.{WORKSPACE}' exists but is not a string in {}.",
    179                 file.display()
    180             ),
    181             Self::WorkspaceRead(e, p) => {
    182                 writeln!(stderr, "There was an issue reading the workspace file {}: {e}.", p.display())
    183             }
    184             Self::WorkspaceToml(e, p) => write!(
    185                 stderr,
    186                 "Error parsing workspace file {} as TOML: {e}.",
    187                 p.display()
    188             ),
    189             Self::Workspace(e, p) => e.write(stderr, &p),
    190         }
    191     }
    192 }
    193 /// `"features"`.
    194 const FEATURES: &str = "features";
    195 /// Error returned from extracting feature dependencies.
    196 #[cfg_attr(test, derive(Debug, PartialEq))]
    197 pub(crate) enum FeatureDependenciesErr {
    198     /// Variant returned when a feature is not an array.
    199     ///
    200     /// The contained `String` is the name of the feature.
    201     InvalidFeatureType(String),
    202     /// Variant returned when a feature dependency is not a string.
    203     ///
    204     /// The contained `String` is the name of the feature.
    205     InvalidDependencyType(String),
    206     /// Variant returned when a feature dependency is not a feature nor dependency.
    207     ///
    208     /// The first contained `String` is the name of the feature, and the second `String` is the name of the invalid
    209     /// feature dependency.
    210     ///
    211     /// Note this is only possible when `allow_implied_features` is `false` when passed to
    212     /// [`Features::validate_dependencies`].
    213     InvalidDependency(String, String),
    214     /// Variant returned when a feature is cyclic.
    215     ///
    216     /// The contained `String` is the name of the feature.
    217     CyclicFeature(String),
    218     /// Variant returned when a feature dependency is redundant.
    219     ///
    220     /// The first contained `String` is the name of the feature, and the second `String` is the name of the
    221     /// redundant feature dependency.
    222     RedundantDependency(String, String),
    223 }
    224 impl FeatureDependenciesErr {
    225     /// Writes `self` to `stderr`.
    226     fn write(self, mut stderr: StderrLock<'_>, file: &Path) -> Result<(), Error> {
    227         match self {
    228             Self::InvalidFeatureType(name) => {
    229                 writeln!(
    230                     stderr,
    231                     "'{FEATURES}.{name}' is not an array in {}.",
    232                     file.display()
    233                 )
    234             }
    235             Self::InvalidDependencyType(name) => writeln!(
    236                 stderr,
    237                 "'{FEATURES}.{name}' contains a value that is not a string in {}.",
    238                 file.display()
    239             ),
    240             Self::InvalidDependency(name, dep_name) => writeln!(
    241                 stderr,
    242                 "'{FEATURES}.{name}' contains '{dep_name}' which is neither a feature nor dependency in {}. It may be an implied feature from an optional dependency, but --allow-implied-features was not passed.",
    243                 file.display()
    244             ),
    245             Self::CyclicFeature(name) => writeln!(
    246                 stderr,
    247                 "'{FEATURES}.{name}' is a cyclic feature in {}.",
    248                 file.display()
    249             ),
    250             Self::RedundantDependency(name, dep_name) => writeln!(
    251                 stderr,
    252                 "'{FEATURES}.{name}' contains the redundant dependency '{dep_name}' in {}.",
    253                 file.display()
    254             ),
    255         }
    256     }
    257 }
    258 /// Error returned from extracting `"features"`.
    259 #[cfg_attr(test, derive(Debug, PartialEq))]
    260 pub(crate) enum FeaturesErr {
    261     /// Variant returned when `features` is not a table in Cargo.toml.
    262     InvalidType,
    263     /// Variant returned when `features` contains a feature with an invalid name.
    264     ///
    265     /// The contained `String` is the name of the feature.
    266     InvalidName(String),
    267     /// Variant returned when there is an issue with a feature's dependencies.
    268     FeatureDependencies(FeatureDependenciesErr),
    269 }
    270 impl FeaturesErr {
    271     /// Writes `self` to `stderr`.
    272     fn write(self, mut stderr: StderrLock<'_>, file: &Path) -> Result<(), Error> {
    273         match self {
    274             Self::InvalidType => {
    275                 writeln!(
    276                     stderr,
    277                     "'{FEATURES}' exists but is not a table in {}.",
    278                     file.display()
    279                 )
    280             }
    281             Self::InvalidName(name) => {
    282                 writeln!(
    283                     stderr,
    284                     "'{FEATURES}.{name}' is not a valid feature name in {}.",
    285                     file.display()
    286                 )
    287             }
    288             Self::FeatureDependencies(e) => e.write(stderr, file),
    289         }
    290     }
    291 }
    292 /// Error returned from extracting dependencies.
    293 #[cfg_attr(test, derive(Debug, PartialEq))]
    294 pub(crate) enum DependenciesErr {
    295     /// Variant returned when the dependencies is not a table.
    296     ///
    297     /// The contained `str` is the name of the dependencies (e.g., `"dependencies"`).
    298     Type(&'static str),
    299     /// Variant returned when a dependency has an invalid name.
    300     ///
    301     /// The contained `str` is the name of dependencies (e.g., `"dependencies"`), and the `String` is the
    302     /// name of the dependency.
    303     Name(&'static str, String),
    304     /// Variant returned when a dependency is not a string or table.
    305     ///
    306     /// The contained `str` is the name of dependencies (e.g., `"dependencies"`), and the `String` is the
    307     /// name of the dependency.
    308     DependencyType(&'static str, String),
    309     /// Variant returned when a dependency contains an `"optional"` key whose value is not a Boolean.
    310     ///
    311     /// The contained `str` is the name of dependencies (e.g., `"dependencies"`), and the `String` is the
    312     /// name of the dependency.
    313     OptionalType(&'static str, String),
    314     /// Variant returned when an optional dependency would cause an implied feature to be created.
    315     ///
    316     /// Note this is only possible when `allow_implied_features` is `false` when passed to
    317     /// [`Features::add_optional_dependencies`].
    318     ///
    319     /// The contained `str` is the name of dependencies (e.g., `"dependencies"`), and the `String` is the
    320     /// name of the dependency.
    321     ImpliedFeature(&'static str, String),
    322 }
    323 /// Error returned from extracting dependencies to add implied features.
    324 #[cfg_attr(test, derive(Debug, PartialEq))]
    325 pub(crate) enum ImpliedFeaturesErr {
    326     /// Variant returned from extracting dependencies.
    327     Dependencies(DependenciesErr),
    328     /// Variant returned when `target` is not a table in Cargo.toml.
    329     TargetType,
    330     /// Variant returned when `target` contains a key whose value is not a table.
    331     ///
    332     /// The contained `String` is the name of the key.
    333     TargetPlatformType(String),
    334     /// Variant returned when a target platform contains an issue with dependencies.
    335     ///
    336     /// The contained `String` is the name of the target platform.
    337     TagetPlatformDependencies(String, DependenciesErr),
    338     /// Variant returned when a feature dependency is not a feature nor dependency.
    339     ///
    340     /// The first contained `String` is the name of the feature, and the second `String` is the name of the invalid
    341     /// feature dependency.
    342     ///
    343     /// Note this is only possible when `allow_implied_features` is `true` when passed to
    344     /// [`Features::validate_dependencies`] since when `false` we verify the the dependency
    345     /// is defined as a feature.
    346     InvalidDependency(String, String),
    347 }
    348 /// `"optional"`.
    349 const OPTIONAL: &str = "optional";
    350 /// `"target"`.
    351 const TARGET: &str = "target";
    352 impl ImpliedFeaturesErr {
    353     /// Writes `self` to `stderr`.
    354     fn write(self, mut stderr: StderrLock<'_>, file: &Path) -> Result<(), Error> {
    355         match self {
    356             Self::Dependencies(e) => match e {
    357                 DependenciesErr::Type(name) => {
    358                     writeln!(
    359                         stderr,
    360                         "'{name}' exists but is not a table in {}.",
    361                         file.display()
    362                     )
    363                 }
    364                 DependenciesErr::Name(name, dep_name) => {
    365                     writeln!(
    366                         stderr,
    367                         "'{name}.{dep_name}' is not a valid dependency name in {}.",
    368                         file.display()
    369                     )
    370                 }
    371                 DependenciesErr::DependencyType(name, dep_name) => {
    372                     writeln!(
    373                         stderr,
    374                         "'{name}.{dep_name}' exists but is not a string nor table in {}.",
    375                         file.display()
    376                     )
    377                 }
    378                 DependenciesErr::OptionalType(name, dep_name) => {
    379                     writeln!(
    380                         stderr,
    381                         "'{name}.{dep_name}.{OPTIONAL}' exists but is not a Boolean in {}.",
    382                         file.display()
    383                     )
    384                 }
    385                 DependenciesErr::ImpliedFeature(name, dep_name) => {
    386                     writeln!(
    387                         stderr,
    388                         "'{name}.{dep_name}' causes an implied feature to be defined in {}, but implied features were forbidden. --allow-implied-features can be passed to allow it.",
    389                         file.display()
    390                     )
    391                 }
    392             },
    393             Self::TargetType => {
    394                 writeln!(
    395                     stderr,
    396                     "'{TARGET}' exists but is not a table in {}.",
    397                     file.display()
    398                 )
    399             }
    400             Self::TargetPlatformType(name) => {
    401                 writeln!(
    402                     stderr,
    403                     "'{TARGET}.{name}' exists but is not a table in {}.",
    404                     file.display()
    405                 )
    406             }
    407             Self::TagetPlatformDependencies(name, e) => match e {
    408                 DependenciesErr::Type(table_name) => {
    409                     writeln!(
    410                         stderr,
    411                         "'{TARGET}.{name}.{table_name}' exists but is not a table in {}.",
    412                         file.display()
    413                     )
    414                 }
    415                 DependenciesErr::Name(table_name, dep_name) => {
    416                     writeln!(
    417                         stderr,
    418                         "'{TARGET}.{name}.{table_name}.{dep_name}' is not a valid dependency name in {}.",
    419                         file.display()
    420                     )
    421                 }
    422                 DependenciesErr::DependencyType(table_name, dep_name) => writeln!(
    423                     stderr,
    424                     "'{TARGET}.{name}.{table_name}.{dep_name}' exists but is not a string nor table in {}.",
    425                     file.display()
    426                 ),
    427                 DependenciesErr::OptionalType(table_name, dep_name) => writeln!(
    428                     stderr,
    429                     "'{TARGET}.{name}.{table_name}.{dep_name}.{OPTIONAL}' exists but is not a Boolean in {}.",
    430                     file.display()
    431                 ),
    432                 DependenciesErr::ImpliedFeature(table_name, dep_name) => {
    433                     writeln!(
    434                         stderr,
    435                         "'{TARGET}.{name}.{table_name}.{dep_name}' causes an implied feature to be defined in {}, but implied features were forbidden. --allow-implied-features can be passed to allow it.",
    436                         file.display()
    437                     )
    438                 }
    439             },
    440             Self::InvalidDependency(name, dep_name) => writeln!(
    441                 stderr,
    442                 "'{FEATURES}.{name}' contains '{dep_name}' which is neither a feature nor dependency in {}.",
    443                 file.display()
    444             ),
    445         }
    446     }
    447 }
    448 /// Error returned from parsing Cargo.toml.
    449 #[cfg_attr(test, derive(Debug, PartialEq))]
    450 pub(crate) enum ManifestErr {
    451     /// Variant returned when Cargo.toml is not valid TOML.
    452     Toml(TomlErr, PathBuf),
    453     /// Variant returned when extracting `package`.
    454     Package(PackageErr, PathBuf),
    455     /// Variant returned when extracting `features`.
    456     Features(FeaturesErr, PathBuf),
    457     /// Variant returned when extracting dependencies in order to add implied features.
    458     ImpliedFeatures(ImpliedFeaturesErr, PathBuf),
    459     /// Variant returned when ignoring a feature that does not exist.
    460     UndefinedIgnoreFeature(String, PathBuf),
    461 }
    462 impl ManifestErr {
    463     /// Writes `self` to `stderr`.
    464     pub(crate) fn write(self, mut stderr: StderrLock<'_>) -> Result<(), Error> {
    465         match self {
    466             Self::Toml(e, file) => write!(
    467                 stderr,
    468                 "Error parsing package file {} as TOML: {e}.",
    469                 file.display()
    470             ),
    471             Self::Package(e, file) => e.write(stderr, &file),
    472             Self::Features(e, file) => e.write(stderr, &file),
    473             Self::ImpliedFeatures(e, file) => e.write(stderr, &file),
    474             Self::UndefinedIgnoreFeature(feature, file) => writeln!(
    475                 stderr,
    476                 "The feature '{feature}' was requested to be ignored, but it is not a feature in the package file {}.",
    477                 file.display()
    478             ),
    479         }
    480     }
    481 }
    482 /// Error when there are too many features to create the power set.
    483 #[cfg_attr(test, derive(Debug, PartialEq))]
    484 pub(crate) struct TooManyFeaturesErr;
    485 /// Parses `val` as a `u64` in decimal notation without leading 0s.
    486 ///
    487 /// # Errors
    488 ///
    489 /// Errors iff `val` is not a valid `u64` in decimal notation without leading 0s.
    490 pub(crate) fn parse_int(val: &str) -> Result<u64, ()> {
    491     val.as_bytes().first().ok_or(()).and_then(|fst| {
    492         if *fst == b'0' {
    493             if val.len() == 1 { Ok(0) } else { Err(()) }
    494         } else {
    495             val.parse().map_err(|_e| ())
    496         }
    497     })
    498 }
    499 /// MSRV in Cargo.toml.
    500 #[cfg_attr(test, derive(Debug, PartialEq))]
    501 pub(crate) struct Msrv {
    502     /// Major version.
    503     major: u64,
    504     /// Minor version.
    505     minor: Option<u64>,
    506     /// Patch version.
    507     patch: Option<u64>,
    508 }
    509 impl Msrv {
    510     /// Converts `msrv` into `Self` based on a valid MSRV string.
    511     #[expect(unsafe_code, reason = "comments justify their correctness")]
    512     fn extract_msrv(msrv: &str) -> Result<Self, ()> {
    513         let mut iter = msrv.as_bytes().split(|b| *b == b'.');
    514         iter.next().ok_or(()).and_then(|fst| {
    515             // SAFETY:
    516             // The original input is a `str` and we split on `b'.'` which is a single-byte
    517             // UTF-8 code unit; thus we don't have to worry about splitting a multi-byte
    518             // UTF-8 code unit.
    519             let major_utf8 = unsafe { str::from_utf8_unchecked(fst) };
    520             parse_int(major_utf8).and_then(|major| {
    521                 iter.next().map_or_else(
    522                     || {
    523                         Ok(Self {
    524                             major,
    525                             minor: None,
    526                             patch: None,
    527                         })
    528                     },
    529                     |snd| {
    530                         // SAFETY:
    531                         // The original input is a `str` and we split on `b'.'` which is
    532                         // a single-byte UTF-8 code unit; thus we don't have to worry
    533                         // about splitting a multi-byte UTF-8 code unit.
    534                         let minor_utf8 = unsafe { str::from_utf8_unchecked(snd) };
    535                         parse_int(minor_utf8).and_then(|minor_val| {
    536                             iter.next().map_or_else(
    537                                 || {
    538                                     Ok(Self {
    539                                         major,
    540                                         minor: Some(minor_val),
    541                                         patch: None,
    542                                     })
    543                                 },
    544                                 |lst| {
    545                                     // SAFETY:
    546                                     // The original input is a `str` and we split on
    547                                     // `b'.'` which is a single-byte UTF-8 code
    548                                     // unit; thus we don't have to worry about
    549                                     // splitting a multi-byte UTF-8 code unit.
    550                                     let patch_utf8 = unsafe { str::from_utf8_unchecked(lst) };
    551                                     parse_int(patch_utf8).and_then(|patch_val| {
    552                                         iter.next().map_or_else(
    553                                             || {
    554                                                 Ok(Self {
    555                                                     major,
    556                                                     minor: Some(minor_val),
    557                                                     patch: Some(patch_val),
    558                                                 })
    559                                             },
    560                                             |_| Err(()),
    561                                         )
    562                                     })
    563                                 },
    564                             )
    565                         })
    566                     },
    567                 )
    568             })
    569         })
    570     }
    571     /// Reads `workspace` from `toml` extracting the MSRV.
    572     fn extract_workspace(
    573         toml: &Map<Spanned<Cow<'_, str>>, Spanned<DeValue<'_>>>,
    574     ) -> Result<Self, WorkspaceErr> {
    575         toml.get(WORKSPACE)
    576             .ok_or(WorkspaceErr::Missing)
    577             .and_then(|work_span| {
    578                 if let DeValue::Table(ref workspace) = *work_span.get_ref() {
    579                     workspace
    580                         .get(PACKAGE)
    581                         .ok_or(WorkspaceErr::MissingPackage)
    582                         .and_then(|pack_span| {
    583                             if let DeValue::Table(ref package) = *pack_span.get_ref() {
    584                                 package
    585                                     .get(RUST_VERSION)
    586                                     .ok_or(WorkspaceErr::MissingPackageMsrv)
    587                                     .and_then(|msrv_span| {
    588                                         if let DeValue::String(ref msrv) = *msrv_span.get_ref() {
    589                                             Self::extract_msrv(msrv)
    590                                                 .map_err(|()| WorkspaceErr::Msrv)
    591                                         } else {
    592                                             Err(WorkspaceErr::InvalidPackageMsrvType)
    593                                         }
    594                                     })
    595                             } else {
    596                                 Err(WorkspaceErr::InvalidPackageType)
    597                             }
    598                         })
    599                 } else {
    600                     Err(WorkspaceErr::InvalidType)
    601                 }
    602             })
    603     }
    604     /// Recursively looks for `Cargo.toml` in `cur_dir` and ancestor directories until one is found
    605     /// that contains a key named [`WORKSPACE`]. Once found, it's MSRV will be parsed and returned.
    606     ///
    607     /// We make this recursive in case the (impossible?) path traversal becomes cyclic; in which
    608     /// we want a stack overflow to occur.
    609     ///
    610     /// Note if any error occurs not related to a not found file error, then this will error.
    611     fn get_workspace_toml(mut cur_dir: PathBuf) -> Result<Self, PackageErr> {
    612         cur_dir.push(super::cargo_toml());
    613         match fs::read_to_string(&cur_dir) {
    614             Ok(file) => Map::parse(&file)
    615                 .map_err(|e| PackageErr::WorkspaceToml(e, cur_dir.clone()))
    616                 .and_then(|toml| {
    617                     let t = toml.into_inner();
    618                     if t.contains_key(WORKSPACE) {
    619                         Self::extract_workspace(&t).map_err(|e| PackageErr::Workspace(e, cur_dir))
    620                     } else {
    621                         _ = cur_dir.pop();
    622                         if cur_dir.pop() {
    623                             Self::get_workspace_toml(cur_dir)
    624                         } else {
    625                             Err(PackageErr::WorkspaceDoesNotExist)
    626                         }
    627                     }
    628                 }),
    629             Err(e) => {
    630                 if matches!(e.kind(), ErrorKind::NotFound) {
    631                     _ = cur_dir.pop();
    632                     if cur_dir.pop() {
    633                         Self::get_workspace_toml(cur_dir)
    634                     } else {
    635                         Err(PackageErr::WorkspaceIo(e))
    636                     }
    637                 } else {
    638                     Err(PackageErr::WorkspaceIo(e))
    639                 }
    640             }
    641         }
    642     }
    643     /// Extracts `"rust-version"` from `"package"` or `toml` in the case it's defined in a workspace.
    644     #[expect(
    645         clippy::panic_in_result_fn,
    646         reason = "want to crash when there is a bug"
    647     )]
    648     fn extract_from_toml(
    649         toml: &Map<Spanned<Cow<'_, str>>, Spanned<DeValue<'_>>>,
    650         package: &Map<Spanned<Cow<'_, str>>, Spanned<DeValue<'_>>>,
    651         cargo_toml: &Path,
    652     ) -> Result<Option<Self>, PackageErr> {
    653         package.get(RUST_VERSION).map_or(Ok(None), |msrv_span| {
    654             match *msrv_span.get_ref() {
    655                 DeValue::String(ref msrv) => Self::extract_msrv(msrv)
    656                     .map_err(|()| PackageErr::Msrv)
    657                     .map(Some),
    658                 DeValue::Table(ref msrv) => msrv
    659                     .get(WORKSPACE)
    660                     .ok_or(PackageErr::MsrvWorkspaceMissing)
    661                     .and_then(|work| {
    662                         if matches!(*work.get_ref(), DeValue::Boolean(b) if b) {
    663                             package.get(WORKSPACE).map_or_else(
    664                                 || if toml.contains_key(WORKSPACE) {
    665                                     Self::extract_workspace(toml).map_err(|e| PackageErr::Workspace(e, cargo_toml.to_path_buf())).map(Some)
    666                                 } else {
    667                                     let mut search_path = cargo_toml.to_path_buf();
    668                                     assert!(search_path.pop(), "there is a bug in main. manifest::Manifest::from_toml must be passed the absolute path to the package's Cargo.toml.");
    669                                     if search_path.pop() {
    670                                         Self::get_workspace_toml(search_path).map(Some)
    671                                     } else {
    672                                         Err(PackageErr::WorkspaceDoesNotExist)
    673                                     }
    674                                 },
    675                                 |path_span| {
    676                                     if let DeValue::String(ref workspace_path) = *path_span.get_ref() {
    677                                         let mut path = cargo_toml.to_path_buf();
    678                                         assert!(path.pop(), "there is a bug in main. manifest::Manifest::from_toml must be passed the absolute path to the package's Cargo.toml.");
    679                                         path.push(workspace_path.as_ref());
    680                                         path.push(super::cargo_toml());
    681                                         fs::read_to_string(&path).map_err(|e| PackageErr::WorkspaceRead(e, path.clone())).and_then(|workspace_file| Map::parse(&workspace_file).map_err(|e| PackageErr::WorkspaceToml(e, path.clone())).and_then(|workspace_toml| Self::extract_workspace(workspace_toml.get_ref()).map_err(|e| PackageErr::Workspace(e, path)).map(Some)))
    682                                     } else {
    683                                         Err(PackageErr::InvalidWorkspaceType)
    684                                     }
    685                                 },
    686                             )
    687                         } else {
    688                             Err(PackageErr::MsrvWorkspaceVal)
    689                         }
    690                     }),
    691                 DeValue::Integer(_)
    692                 | DeValue::Float(_)
    693                 | DeValue::Boolean(_)
    694                 | DeValue::Datetime(_)
    695                 | DeValue::Array(_) => Err(PackageErr::InvalidMsrvType),
    696             }
    697         })
    698     }
    699     /// Returns `Some` containing the MSRV with `'+'` prepended iff `stable` is semantically greater than `self`
    700     /// or the default toolchan is semantically not equivalent to `self`; otherwise returns `None`.
    701     ///
    702     /// When `stable` is semantically less than the MSRV, an error is returned.
    703     pub(crate) fn compare_to_other(
    704         &self,
    705         default: bool,
    706         rustup_home: Option<&Path>,
    707         cargo_path: &Path,
    708         cargo_home: Option<&Path>,
    709     ) -> Result<Option<String>, Box<ToolchainErr>> {
    710         if default {
    711             Toolchain::Default(false)
    712         } else {
    713             Toolchain::Stable
    714         }
    715         .get_version(rustup_home, cargo_path, cargo_home)
    716         .and_then(|stable_dflt_version| {
    717             match self.major.cmp(&stable_dflt_version.major) {
    718                 Ordering::Less => Ok(true),
    719                 Ordering::Equal => self.minor.map_or_else(
    720                     || Ok(false),
    721                     |min| match min.cmp(&stable_dflt_version.minor) {
    722                         Ordering::Less => Ok(true),
    723                         Ordering::Equal => self.patch.map_or_else(
    724                             || Ok(false),
    725                             |pat| match pat.cmp(&stable_dflt_version.patch) {
    726                                 Ordering::Less => Ok(true),
    727                                 Ordering::Equal => Ok(false),
    728                                 Ordering::Greater => {
    729                                     if default {
    730                                         Ok(true)
    731                                     } else {
    732                                         Err(Box::new(ToolchainErr::MsrvTooHigh))
    733                                     }
    734                                 }
    735                             },
    736                         ),
    737                         Ordering::Greater => {
    738                             if default {
    739                                 Ok(true)
    740                             } else {
    741                                 Err(Box::new(ToolchainErr::MsrvTooHigh))
    742                             }
    743                         }
    744                     },
    745                 ),
    746                 Ordering::Greater => {
    747                     if default {
    748                         Ok(true)
    749                     } else {
    750                         Err(Box::new(ToolchainErr::MsrvTooHigh))
    751                     }
    752                 }
    753             }
    754             .and_then(|get_msrv| {
    755                 if get_msrv {
    756                     Toolchain::Msrv(&self.minor.map_or_else(
    757                         || format!("+{}", self.major),
    758                         |min| {
    759                             self.patch.map_or_else(
    760                                 || format!("+{}.{min}", self.major),
    761                                 |pat| format!("+{}.{min}.{pat}", self.major),
    762                             )
    763                         },
    764                     ))
    765                     .get_version(rustup_home, cargo_path, cargo_home)
    766                     .and_then(|msrv_version| {
    767                         if msrv_version.major == self.major
    768                             && self.minor.is_none_or(|minor| {
    769                                 msrv_version.minor == minor
    770                                     && self.patch.is_none_or(|patch| msrv_version.patch == patch)
    771                             })
    772                         {
    773                             Ok(Some(format!(
    774                                 "+{}.{}.{}",
    775                                 msrv_version.major, msrv_version.minor, msrv_version.patch
    776                             )))
    777                         } else {
    778                             Err(Box::new(ToolchainErr::MsrvNotCompatibleWithInstalledMsrv(
    779                                 msrv_version,
    780                             )))
    781                         }
    782                     })
    783                 } else {
    784                     Ok(None)
    785                 }
    786             })
    787         })
    788     }
    789 }
    790 /// `package` info.
    791 #[cfg_attr(test, derive(Debug, PartialEq))]
    792 pub(crate) struct Package {
    793     /// `rust-version`.
    794     msrv: Option<Msrv>,
    795     /// `name`.
    796     name: String,
    797 }
    798 impl Package {
    799     /// MSRV.
    800     pub(crate) const fn msrv(&self) -> Option<&Msrv> {
    801         self.msrv.as_ref()
    802     }
    803     /// Name.
    804     pub(crate) const fn name(&self) -> &str {
    805         self.name.as_str()
    806     }
    807     /// Extracts `"package"` from `toml`.
    808     fn extract_from_toml(
    809         toml: &Map<Spanned<Cow<'_, str>>, Spanned<DeValue<'_>>>,
    810         cargo_toml: &Path,
    811     ) -> Result<Self, PackageErr> {
    812         toml.get(PACKAGE)
    813             .ok_or(PackageErr::Missing)
    814             .and_then(|pack_span| {
    815                 if let DeValue::Table(ref package) = *pack_span.get_ref() {
    816                     package
    817                         .get(NAME)
    818                         .ok_or(PackageErr::MissingName)
    819                         .and_then(|name_span| {
    820                             if let DeValue::String(ref name) = *name_span.get_ref() {
    821                                 Msrv::extract_from_toml(toml, package, cargo_toml).map(|msrv| {
    822                                     Self {
    823                                         msrv,
    824                                         name: name.clone().into_owned(),
    825                                     }
    826                                 })
    827                             } else {
    828                                 Err(PackageErr::InvalidNameType)
    829                             }
    830                         })
    831                 } else {
    832                     Err(PackageErr::InvalidType)
    833                 }
    834             })
    835     }
    836 }
    837 /// Returns `true` iff `nodes` is pairwise disconnected.
    838 #[expect(
    839     clippy::arithmetic_side_effects,
    840     clippy::indexing_slicing,
    841     reason = "comment justifies correctness"
    842 )]
    843 fn pairwise_disconnected(nodes: &[&str], features: &[(String, Vec<String>)]) -> bool {
    844     /// `panic`s with a static message about the existence of a bug in [`Manifest::deserialize`].
    845     #[expect(clippy::unreachable, reason = "want to crash when there is a bug")]
    846     fn impossible<T>() -> T {
    847         unreachable!(
    848             "there is a bug in manifest::Manifest::deserialize where feature dependencies are not only features."
    849         )
    850     }
    851     /// Returns `true` iff `feature_deps` directly contains `feature` or indirectly in the `Vec<String>`
    852     /// associated with it.
    853     fn contains(
    854         feature_deps: &[String],
    855         feature: &str,
    856         features: &[(String, Vec<String>)],
    857     ) -> bool {
    858         feature_deps.iter().any(|feat| {
    859             feat == feature
    860                 || contains(
    861                     &features
    862                         .iter()
    863                         .find(|val| val.0 == *feat)
    864                         .unwrap_or_else(impossible)
    865                         .1,
    866                     feature,
    867                     features,
    868                 )
    869         })
    870     }
    871     !nodes.iter().enumerate().any(|(idx, feature)| {
    872         let feature_info = &features
    873             .iter()
    874             .find(|val| val.0 == **feature)
    875             .unwrap_or_else(impossible)
    876             .1;
    877         // `idx < nodes.len()`, so overflow is not possible and indexing is fine.
    878         nodes[idx + 1..].iter().any(|feat| {
    879             contains(feature_info, feat, features)
    880                 || contains(
    881                     features
    882                         .iter()
    883                         .find(|val| val.0 == **feat)
    884                         .unwrap_or_else(impossible)
    885                         .1
    886                         .as_slice(),
    887                     feature,
    888                     features,
    889                 )
    890         })
    891     })
    892 }
    893 /// Power set of [`Features`] returned from [`Features::power_set`].
    894 ///
    895 /// Note this is technically not the power set of features since semantically equivalent sets are ignored.
    896 ///
    897 /// The last set iterated will always be the empty set. If no features in [`Features`] depend on another
    898 /// feature, then this will always return the entire set of features first; otherwise the entire set will
    899 /// never be returned. The expected cardinality of a set iterated decreases; thus while it will almost always
    900 /// be possible for a set _A_ to have larger cardinality than a set _B_ even when _A_ is iterated before _B_,
    901 /// the expected value is smaller.
    902 ///
    903 /// The reason we attempt, but don't guarantee, that the first set iterated corresponds to a semantically
    904 /// equivalent set as the original set is to take advantage of the parallel compiliation that occurs. Typically
    905 /// the more features one enables, the more dependencies and functionality is added. By compiling code that
    906 /// maximizes this first, we take better advantage of how code is compiled; in contrast if we compiled fewer
    907 /// features first, subsequent compilations with more features will have to happen. We don't guarantee this
    908 /// though since it slightly complicates code; instead we iterate based on the _expected_ cardinality in
    909 /// descending order.
    910 ///
    911 /// We don't implement `Iterator` since we want to re-use the same `String` that represents the set we are
    912 /// returning.
    913 #[cfg_attr(test, derive(Debug, PartialEq))]
    914 pub(crate) struct PowerSet<'a> {
    915     /// The set of features.
    916     feats: &'a [(String, Vec<String>)],
    917     /// `true` iff there are more sets to iterate.
    918     has_remaining: bool,
    919     /// `true` iff `feats` has redundant features; thus requiring us to check if a given set should be returned.
    920     check_overlap: bool,
    921     /// The current element of the power set that we are to return.
    922     ///
    923     /// This gets decremented as we iterate sets.
    924     idx: usize,
    925     /// Intermediate buffer we use to check if a set contains redundant features.
    926     buffer: Vec<&'a str>,
    927     /// The set we return.
    928     ///
    929     /// This is of the form `"<feat_1>,<feat_2>,...,<feat_n>"`.
    930     set: String,
    931     /// Number of sets skipped due to an equivalence with a smaller set.
    932     skipped_sets_counter: usize,
    933     /// `true` iff they empty set should be skipped.
    934     ///
    935     /// This doesn't contribute to [`Self::skipped_sets_counter`].
    936     skip_empty_set: bool,
    937 }
    938 impl<'a> PowerSet<'a> {
    939     /// Max cardinality of a set we allow to take the power set of.
    940     // usize::MAX = 2^usize::BITS - 1 >= usize::BITS since usize::MAX >= 0;
    941     // thus `usize::BITS as usize` is free from truncation.
    942     #[expect(clippy::as_conversions, reason = "comment justifies correctness")]
    943     const MAX_SET_LEN: usize = usize::BITS as usize;
    944     /// Returns the cardinality less one of the power set of a set
    945     /// whose cardinality is `set_len`.
    946     ///
    947     /// `set_len` MUST not be greater than [`Self::MAX_SET_LEN`].
    948     #[expect(
    949         clippy::arithmetic_side_effects,
    950         reason = "comment justifies correctness"
    951     )]
    952     const fn len_minus_one(set_len: usize) -> usize {
    953         assert!(
    954             set_len <= Self::MAX_SET_LEN,
    955             "manifest::PowerSet::len_minus_one must be passed a `usize` no larger than PowerSet::MAX_SET_LEN"
    956         );
    957         if set_len == Self::MAX_SET_LEN {
    958             usize::MAX
    959         } else {
    960             // We verified that `set_len <= usize::BITS`; thus
    961             // this won't overflow nor underflow since 2^0 = 1.
    962             (1 << set_len) - 1
    963         }
    964     }
    965     /// Returns the cardinality of `self`.
    966     ///
    967     /// Note this is constant and is not affected by iteration of
    968     /// `self`. This isn't the remaining length. [`Self::skip_empty_set`]
    969     /// contributes towards this value.
    970     #[expect(
    971         clippy::arithmetic_side_effects,
    972         reason = "comment justifies correctness"
    973     )]
    974     pub(crate) fn len(&self) -> NonZeroUsizePlus1 {
    975         // We don't allow construction of `PowerSet` unless the set of features
    976         // is no more than [`Self::MAX_SET_LEN`]; thus this won't `panic`.
    977         // Underflow won't occur either since we don't allow construction when the
    978         // set of features is empty and when we must skip the empty set.
    979         // `NonZeroUsizePlus1` treats `0` as `usize::MAX + 1`, so we use wrapping addition.
    980         // This will only wrapp when `self.features.len() == Self::MAX_SET_LEN` and `!self.skip_empty_set`.
    981         NonZeroUsizePlus1::new(
    982             (Self::len_minus_one(self.feats.len()) - usize::from(self.skip_empty_set))
    983                 .wrapping_add(1),
    984         )
    985     }
    986     /// Contructs `Self` based on `features`.
    987     ///
    988     /// When iterating the sets, the empty set will be skipped iff `skip_empty_set`;
    989     /// but this _won't_ contribute to `skipped_sets_counter`.
    990     ///
    991     /// Returns `None` iff `features` is empty and `skip_empty_set`.
    992     fn new(
    993         features: &'a Features,
    994         skip_empty_set: bool,
    995     ) -> Result<Option<Self>, TooManyFeaturesErr> {
    996         let len = features.0.len();
    997         match len {
    998             0 if skip_empty_set => Ok(None),
    999             ..=Self::MAX_SET_LEN => {
   1000                 let mut buffer = Vec::with_capacity(len);
   1001                 features.0.iter().fold((), |(), key| {
   1002                     buffer.push(key.0.as_ref());
   1003                 });
   1004                 let check_overlap = !pairwise_disconnected(buffer.as_slice(), &features.0);
   1005                 Ok(Some(Self {
   1006                     feats: &features.0,
   1007                     has_remaining: true,
   1008                     check_overlap,
   1009                     // We verified `len <= Self::MAX_SET_LEN`, so this won't `panic`.
   1010                     idx: Self::len_minus_one(len),
   1011                     buffer,
   1012                     // This won't overflow since `usize::MAX = 2^usize::BITS - 1`, `usize::BITS >= 16`, the max
   1013                     // value of `len` is `usize::BITS`.
   1014                     // 16 * usize::BITS < 2^usize::BITS for `usize::BITS > 6`.
   1015                     set: String::with_capacity(len << 4),
   1016                     skipped_sets_counter: 0,
   1017                     skip_empty_set,
   1018                 }))
   1019             }
   1020             _ => Err(TooManyFeaturesErr),
   1021         }
   1022     }
   1023     /// Resets `self` such that iteration returns to the beginning.
   1024     pub(crate) const fn reset(&mut self) {
   1025         // We don't allow construction of `PowerSet` when the number of
   1026         // features exceeds [`Self::MAX_SET_LEN`], so this won't `panic`.
   1027         self.idx = Self::len_minus_one(self.feats.len());
   1028         self.has_remaining = true;
   1029         self.skipped_sets_counter = 0;
   1030     }
   1031     /// Writes the next element into `self.buffer` even if the set contains overlapping features.
   1032     #[expect(
   1033         clippy::arithmetic_side_effects,
   1034         reason = "comment justifies correctness"
   1035     )]
   1036     fn inner_next_set(&mut self) {
   1037         self.buffer.clear();
   1038         self.feats.iter().enumerate().fold((), |(), (i, feat)| {
   1039             if self.idx & (1 << i) != 0 {
   1040                 self.buffer.push(feat.0.as_str());
   1041             }
   1042         });
   1043         if self.idx == 0 {
   1044             self.has_remaining = false;
   1045         // The empty set is always the last set.
   1046         } else if self.idx == 1 && self.skip_empty_set {
   1047             self.idx = 0;
   1048             self.has_remaining = false;
   1049         } else {
   1050             // This won't underflow since `idx > 0`.
   1051             self.idx -= 1;
   1052         }
   1053     }
   1054     /// Transforms the current element into its string form.
   1055     fn current_set(&mut self) {
   1056         self.set.clear();
   1057         self.buffer.iter().fold((), |(), s| {
   1058             self.set.push_str(s);
   1059             self.set.push(',');
   1060         });
   1061         // We remove the trailing comma. In the event `self.set` is empty, this does nothing.
   1062         _ = self.set.pop();
   1063     }
   1064     /// Returns the next set.
   1065     ///
   1066     /// This returns `None` iff there are no more sets to return. It will continue to return `None`
   1067     /// unless [`Self::reset`] is called.
   1068     pub(crate) fn next_set(&mut self) -> Option<&str> {
   1069         self.next_set_with_skip_count().map(|tup| tup.0)
   1070     }
   1071     /// Returns the next set along with the number of set skipped thus far.
   1072     ///
   1073     /// This returns `None` iff there are no more sets to return. It will continue to return `None`
   1074     /// unless [`Self::reset`] is called.
   1075     #[expect(
   1076         clippy::arithmetic_side_effects,
   1077         reason = "comment justifies correctness"
   1078     )]
   1079     pub(crate) fn next_set_with_skip_count(&mut self) -> Option<(&str, usize)> {
   1080         if self.has_remaining {
   1081             if self.check_overlap {
   1082                 while self.has_remaining {
   1083                     self.inner_next_set();
   1084                     if pairwise_disconnected(self.buffer.as_slice(), self.feats) {
   1085                         self.current_set();
   1086                         return Some((&self.set, self.skipped_sets_counter));
   1087                     }
   1088                     // This maxes at `usize::MAX` since we ensure a power set is not created on a
   1089                     // set with more than `usize::BITS` elements.
   1090                     // We set to set every time [`Self::reset`] is called as well.
   1091                     self.skipped_sets_counter += 1;
   1092                 }
   1093                 None
   1094             } else {
   1095                 self.inner_next_set();
   1096                 self.current_set();
   1097                 Some((&self.set, self.skipped_sets_counter))
   1098             }
   1099         } else {
   1100             None
   1101         }
   1102     }
   1103 }
   1104 /// Dependency table.
   1105 enum DepTable {
   1106     /// Library dependencies.
   1107     Dependencies,
   1108     /// Build dependencies.
   1109     BuildDependencies,
   1110 }
   1111 impl DepTable {
   1112     /// Returns the string representation of `self`.
   1113     const fn into_str(self) -> &'static str {
   1114         match self {
   1115             Self::Dependencies => "dependencies",
   1116             Self::BuildDependencies => "build-dependencies",
   1117         }
   1118     }
   1119 }
   1120 /// `"dep:"`.
   1121 const DEP: &[u8; 4] = b"dep:";
   1122 /// Returns `true` iff `utf8` begins with [`DEP`].
   1123 fn is_feature_dependency_a_dependency(utf8: &[u8]) -> bool {
   1124     utf8.starts_with(DEP)
   1125 }
   1126 /// Returns `true` iff `name` does not contain a `'/'` nor begins with [`DEP`].
   1127 fn is_feature_dependency_a_feature(name: &str) -> bool {
   1128     let utf8 = name.as_bytes();
   1129     !(utf8.contains(&b'/') || is_feature_dependency_a_dependency(utf8))
   1130 }
   1131 /// Features in Cargo.toml.
   1132 ///
   1133 /// Note this contains a `Vec` instead of a `HashMap` or `BTreeMap` since we enforce that very few entries exist
   1134 /// due to the exponential nature of generating the power set; thus making a `Vec` more efficient and faster.
   1135 /// This size is so small that we don't even sort and perform a binary search.
   1136 ///
   1137 /// The `String` in the tuple represents the name of the feature, and the `Vec` in the tuple represents the
   1138 /// feature dependencies. The feature dependencies will not contain any dependency that contains a `'/'`
   1139 /// but will contain all others. The name of each feature will not contain a `'/'` nor begin with [`DEP`].
   1140 /// Each dependency that is a feature (i.e., does not begin with [`DEP`]) is well-defined (i.e., is a feature
   1141 /// itself) when `false` is passed to [`Self::extract_from_toml`]; when `true` is passed, then feature dependencies
   1142 /// that are features are not verified to be defined in `self` since implied features still have to be added.
   1143 /// Each feature does not contain any cycles nor redundant dependencies.
   1144 ///
   1145 /// One must still add implied features caused from any optional dependencies iff `true` is passed to
   1146 /// [`Self::extract_from_toml`]; after which, one needs to remove all dependencies that are not features and verify
   1147 /// all dependencies that are features are defined in `self` in order for [`PowerSet`] to work correctly. A feature
   1148 /// with name `<dependency>` needs to be added with an empty `Vec` of dependencies iff no features exist that have a
   1149 /// dependency whose name is `"dep:<dependency>"` _and_ there doesn't already exist a feature with that name.
   1150 /// An error MUST NOT happen if there is such a feature since different kinds of dependencies can have the
   1151 /// same name. While this will allow for the situation where a feature is defined with the same name as
   1152 /// an implied feature, that won't matter once `cargo` is run since it will error anyway.
   1153 #[cfg_attr(test, derive(Debug, PartialEq))]
   1154 pub(crate) struct Features(Vec<(String, Vec<String>)>);
   1155 impl Features {
   1156     /// Returns `true` iff `self` contains a feature named `"default"`.
   1157     pub(crate) fn contains_default(&self) -> bool {
   1158         self.0.iter().any(|f| f.0 == "default")
   1159     }
   1160     /// `panic`s with a static message about the existence of a bug in `validate_dependencies`.
   1161     ///
   1162     /// This is used in lieu of `unreachable` in `validate_dependencies`, `check_redundant_features`
   1163     /// and `extract_feature_dependencies`.
   1164     #[expect(clippy::unreachable, reason = "want to crash when there is a bug")]
   1165     fn impossible<T>() -> T {
   1166         unreachable!("there is a bug in manifest::Features::validate_dependencies.")
   1167     }
   1168     /// Verifies dependencies associated with `feature` is valid.
   1169     ///
   1170     /// `dependencies` are assumed to be associated with `feature` which the pair of is checked to be
   1171     /// a key-value pair from `features` iff `allow_implied_features`. This verifies the following:
   1172     ///
   1173     /// * `dependencies` is an array that only contains strings.
   1174     /// * Each string in `dependencies` that does not contain a `'/'` nor begins with [`DEP`] is a key
   1175     ///   in `features` iff `allow_implied_features`.
   1176     /// * `feature` nor any dependency that is a feature in `dependencies` is cyclic.
   1177     ///
   1178     /// `cycle_detection` MUST contain only `feature` when this is called externally.
   1179     ///
   1180     /// This MUST only be called by itself or [`Self::extract_feature_dependencies`].
   1181     fn validate_dependencies<'a>(
   1182         feature: &str,
   1183         dependencies: &'a DeValue<'_>,
   1184         features: &'a Map<Spanned<Cow<'_, str>>, Spanned<DeValue<'_>>>,
   1185         cycle_detection: &mut Vec<&'a str>,
   1186         allow_implied_features: bool,
   1187     ) -> Result<(), FeatureDependenciesErr> {
   1188         if let DeValue::Array(ref info) = *dependencies {
   1189             info.iter().try_fold((), |(), dep_span| {
   1190                 if let DeValue::String(ref dep_name) = *dep_span.get_ref() {
   1191                     if is_feature_dependency_a_feature(dep_name) {
   1192                         if cycle_detection.contains(&dep_name.as_ref()) {
   1193                             Err(FeatureDependenciesErr::CyclicFeature(
   1194                                 dep_name.clone().into_owned(),
   1195                             ))
   1196                         } else if let Some(next_feature) = features.get(dep_name.as_ref()) {
   1197                             cycle_detection.push(dep_name);
   1198                             Self::validate_dependencies(
   1199                                 dep_name,
   1200                                 next_feature.get_ref(),
   1201                                 features,
   1202                                 cycle_detection,
   1203                                 allow_implied_features,
   1204                             )
   1205                             .map(|()| {
   1206                                 // We require calling code to add `feature` before calling this function. We
   1207                                 // always add the most recent feature dependency. Therefore this is not empty.
   1208                                 _ = cycle_detection.pop().unwrap_or_else(Self::impossible);
   1209                             })
   1210                         } else if allow_implied_features {
   1211                             // `dep_name` may be an implied feature which we have yet to add.
   1212                             Ok(())
   1213                         } else {
   1214                             // We require calling code to add `feature` before calling this function. We always
   1215                             // add the most recent feature dependency. Therefore this is not empty.
   1216                             Err(FeatureDependenciesErr::InvalidDependency(
   1217                                 cycle_detection
   1218                                     .pop()
   1219                                     .unwrap_or_else(Self::impossible)
   1220                                     .to_owned(),
   1221                                 dep_name.clone().into_owned(),
   1222                             ))
   1223                         }
   1224                     } else {
   1225                         Ok(())
   1226                     }
   1227                 } else {
   1228                     Err(FeatureDependenciesErr::InvalidDependencyType(
   1229                         feature.to_owned(),
   1230                     ))
   1231                 }
   1232             })
   1233         } else {
   1234             Err(FeatureDependenciesErr::InvalidFeatureType(
   1235                 feature.to_owned(),
   1236             ))
   1237         }
   1238     }
   1239     /// Verifies there are no redundant dependencies that are features in `dependencies`.
   1240     ///
   1241     /// Returns `true` iff there is a redundant dependency.
   1242     ///
   1243     /// This must be called _after_ `validate_dependencies` is called on the same arguments.
   1244     fn check_redundant_dependencies(
   1245         feature: &str,
   1246         dependencies: &DeArray<'_>,
   1247         features: &Map<Spanned<Cow<'_, str>>, Spanned<DeValue<'_>>>,
   1248         allow_implied_features: bool,
   1249     ) -> bool {
   1250         dependencies.iter().any(|dep_span| {
   1251             if let DeValue::String(ref dep_name) = *dep_span.get_ref() {
   1252                 is_feature_dependency_a_feature(dep_name)
   1253                     && (feature == dep_name
   1254                         || features.get(dep_name.as_ref()).map_or_else(
   1255                             || {
   1256                                 if allow_implied_features {
   1257                                     false
   1258                                 } else {
   1259                                     // We require `validate_dependencies` to be called before this function which
   1260                                     // ensures all features recursively in the `dependencies` are defined as features iff `!allow_implied_features`.
   1261                                     Self::impossible()
   1262                                 }
   1263                             },
   1264                             |next_feature_span| {
   1265                                 Self::check_redundant_dependencies(
   1266                                     feature,
   1267                                     next_feature_span
   1268                                         .get_ref()
   1269                                         .as_array()
   1270                                         // We require `validate_dependencies` to be called before this function
   1271                                         // which ensures all feature dependencies recursively are arrays.
   1272                                         .unwrap_or_else(Self::impossible),
   1273                                     features,
   1274                                     allow_implied_features,
   1275                                 )
   1276                             },
   1277                         ))
   1278             } else {
   1279                 // We require `validate_dependencies` to be called before this function which ensures all
   1280                 // dependencies recursivley in `dependencies` are strings.
   1281                 Self::impossible()
   1282             }
   1283         })
   1284     }
   1285     /// Extracts the feature dependencies associated with `feature`.
   1286     ///
   1287     /// `dependencies` are assumed to be associated with `feature` which the pair of is checked to be
   1288     /// a key-value pair from `features` iff `allow_implied_features`. This verifies the following:
   1289     ///
   1290     /// * `dependencies` is an array that only contains strings.
   1291     /// * Each string in `dependencies` that does not contain a `'/'` nor begins with [`DEP`] is a key
   1292     ///   in `features` iff `allow_implied_features`.
   1293     /// * There is no redundant feature in `dependencies` where "redundant" means the following:
   1294     ///   * There are no cycles (e.g., feature = \["feature"] or feature = \["a"], a = \["b"], b = \["a"]).
   1295     ///   * No unnecessary dependencies that are features (e.g., feature = \["a", "a"] or feature = \["a", "b"]
   1296     ///     a = \["b"], b = \[]).
   1297     /// * There are no duplicate dependencies in `dependencies` that beging with [`DEP`].
   1298     ///
   1299     /// Note since all dependencies that contain a `'/'` are ignored, there may be duplicates of them.
   1300     /// Also when checking for redundant features in `dependencies`, _only_ features are considered; thus
   1301     /// something like the following is allowed: feature = \["dep:a", "a"], a = \["dep:a"]
   1302     ///
   1303     /// This must only be called from [`Self::extract_from_toml`].
   1304     #[expect(
   1305         clippy::arithmetic_side_effects,
   1306         reason = "comment justifies correctness"
   1307     )]
   1308     fn extract_feature_dependencies<'a>(
   1309         feature: &'a str,
   1310         dependencies: &'a DeValue<'_>,
   1311         features: &'a Map<Spanned<Cow<'_, str>>, Spanned<DeValue<'_>>>,
   1312         cycle_buffer: &mut Vec<&'a str>,
   1313         allow_implied_features: bool,
   1314     ) -> Result<Vec<String>, FeatureDependenciesErr> {
   1315         // `Self::validate_dependencies` requires `cycle_buffer` to contain, and only contain, `feature`.
   1316         cycle_buffer.clear();
   1317         cycle_buffer.push(feature);
   1318         Self::validate_dependencies(feature, dependencies, features, cycle_buffer, allow_implied_features).and_then(|()| {
   1319             // `validate_dependencies` ensures `dependencies` is an array.
   1320             let deps = dependencies.as_array().unwrap_or_else(Self::impossible);
   1321             let mut vec_deps = Vec::with_capacity(deps.len());
   1322             deps.iter().enumerate().try_fold((), |(), (idx, dep_span)| if let DeValue::String(ref dep_name) = *dep_span.get_ref() {
   1323                 let dep_utf8 = dep_name.as_bytes();
   1324                 if dep_utf8.contains(&b'/') {
   1325                     Ok(())
   1326                 } else if is_feature_dependency_a_dependency(dep_utf8) {
   1327                     if vec_deps.iter().any(|d| d == dep_name) {
   1328                         Err(FeatureDependenciesErr::RedundantDependency(feature.to_owned(), dep_name.clone().into_owned()))
   1329                     } else {
   1330                         vec_deps.push(dep_name.clone().into_owned());
   1331                         Ok(())
   1332                     }
   1333                 } else if let Some(next_feature_span) = features.get(dep_name.as_ref()) {
   1334                     // `validate_dependencies` ensures all feature
   1335                     // dependencies recursively are arrays.
   1336                     let feat_info = next_feature_span.get_ref().as_array().unwrap_or_else(Self::impossible);
   1337                     // `idx < deps.iter().len()`; thus this won't overflow.
   1338                     deps.iter().skip(idx + 1).try_fold((), |(), next_dep_span| if let DeValue::String(ref next_dep_name) = *next_dep_span.get_ref() {
   1339                         if is_feature_dependency_a_feature(next_dep_name) {
   1340                             if dep_name == next_dep_name {
   1341                                 Err(FeatureDependenciesErr::RedundantDependency(feature.to_owned(), dep_name.clone().into_owned()))
   1342                             } else if Self::check_redundant_dependencies(next_dep_name, feat_info, features, allow_implied_features) {
   1343                                 Err(FeatureDependenciesErr::RedundantDependency(feature.to_owned(), next_dep_name.clone().into_owned()))
   1344                             } else {
   1345                                 features.get(next_dep_name.as_ref()).map_or_else(
   1346                                     || {
   1347                                         if allow_implied_features {
   1348                                             Ok(())
   1349                                         } else {
   1350                                             // `validate_dependencies` ensures all features
   1351                                             // recursively in the feature dependencies are defined
   1352                                             // as features iff `!allow_implied_features`.
   1353                                             Self::impossible()
   1354                                         }
   1355                                     },
   1356                                     |next_dep_feature_span| {
   1357                                         // `validate_dependencies` ensures all feature
   1358                                         // dependencies recursively are arrays.
   1359                                         if Self::check_redundant_dependencies(dep_name, next_dep_feature_span.get_ref().as_array().unwrap_or_else(Self::impossible), features, allow_implied_features) {
   1360                                             Err(FeatureDependenciesErr::RedundantDependency(feature.to_owned(), dep_name.clone().into_owned()))
   1361                                         } else {
   1362                                             Ok(())
   1363                                         }
   1364                                     }
   1365                                 )
   1366                             }
   1367                         } else {
   1368                             Ok(())
   1369                         }
   1370                     } else {
   1371                         // `validate_dependencies` ensures all dependencies recursively in `dependencies` are
   1372                         // strings.
   1373                         Self::impossible()
   1374                     }).map(|()| vec_deps.push(dep_name.clone().into_owned()))
   1375                 } else if allow_implied_features {
   1376                     vec_deps.push(dep_name.clone().into_owned());
   1377                     Ok(())
   1378                 } else {
   1379                     // `validate_dependencies` ensures all features
   1380                     // recursively in `dependencies` are defined as features
   1381                     // iff `!allow_implied_features`.
   1382                     Self::impossible()
   1383                 }
   1384             } else {
   1385                 // `validate_dependencies` ensures all dependencies recursively in `dependencies` are strings.
   1386                 Self::impossible()
   1387             }).map(|()| vec_deps)
   1388         })
   1389     }
   1390     /// Extracts `"features"` from `toml`.
   1391     fn extract_from_toml(
   1392         toml: &Map<Spanned<Cow<'_, str>>, Spanned<DeValue<'_>>>,
   1393         allow_implied_features: bool,
   1394     ) -> Result<Self, FeaturesErr> {
   1395         toml.get(FEATURES).map_or_else(
   1396             || Ok(Self(Vec::new())),
   1397             |features_span| {
   1398                 if let DeValue::Table(ref features) = *features_span.get_ref() {
   1399                     let mut cycle_buffer = Vec::with_capacity(features.len());
   1400                     let mut feats = Vec::with_capacity(features.len());
   1401                     features
   1402                         .iter()
   1403                         .try_fold((), |(), (name_span, feature_span)| {
   1404                             let name = name_span.get_ref();
   1405                             if is_feature_dependency_a_feature(name) {
   1406                                 Self::extract_feature_dependencies(
   1407                                     name,
   1408                                     feature_span.get_ref(),
   1409                                     features,
   1410                                     &mut cycle_buffer,
   1411                                     allow_implied_features,
   1412                                 )
   1413                                 .map_err(FeaturesErr::FeatureDependencies)
   1414                                 .map(|deps| {
   1415                                     feats.push((name.clone().into_owned(), deps));
   1416                                 })
   1417                             } else {
   1418                                 Err(FeaturesErr::InvalidName(name.clone().into_owned()))
   1419                             }
   1420                         })
   1421                         .map(|()| Self(feats))
   1422                 } else {
   1423                     Err(FeaturesErr::InvalidType)
   1424                 }
   1425             },
   1426         )
   1427     }
   1428     /// Extracts optional dependencies and adds their corresponding implied feature to `self` iff
   1429     /// `allow_implied_features` and it's appropriate to do so.
   1430     ///
   1431     /// This must only be called from [`Self::add_implied_features`].
   1432     fn add_optional_dependencies(
   1433         &mut self,
   1434         toml: &Map<Spanned<Cow<'_, str>>, Spanned<DeValue<'_>>>,
   1435         table: DepTable,
   1436         allow_implied_features: bool,
   1437     ) -> Result<(), DependenciesErr> {
   1438         let table_name = table.into_str();
   1439         toml.get(table_name).map_or(Ok(()), |deps_span| {
   1440             if let DeValue::Table(ref deps) = *deps_span.get_ref() {
   1441                 deps.iter().try_fold((), |(), dep_span| {
   1442                     let dep_name = dep_span.0.get_ref();
   1443                     if is_feature_dependency_a_feature(dep_name) {
   1444                         match *dep_span.1.get_ref() {
   1445                             DeValue::String(_) => Ok(()),
   1446                             DeValue::Table(ref dep_info) => {
   1447                                 dep_info.get(OPTIONAL).map_or(Ok(()), |opt_span| {
   1448                                     if let DeValue::Boolean(ref optional) = *opt_span.get_ref() {
   1449                                         if *optional {
   1450                                             self.0
   1451                                                 .iter()
   1452                                                 .try_fold((), |(), feat| {
   1453                                                     if feat.0 == *dep_name {
   1454                                                         // We already have a feature with the same name,
   1455                                                         // so we don't need to continue.
   1456                                                         Err(())
   1457                                                     } else if feat.1.iter().any(|feat_dep| {
   1458                                                         feat_dep
   1459                                                             .as_bytes()
   1460                                                             .split_at_checked(DEP.len())
   1461                                                             .is_some_and(|(pref, rem)| {
   1462                                                                 pref == DEP
   1463                                                                     && dep_name.as_bytes() == rem
   1464                                                             })
   1465                                                     }) {
   1466                                                         // The feature dependencies contain `"dep:<dep_name>"`,
   1467                                                         // so we don't need to add an implied feature.
   1468                                                         Err(())
   1469                                                     } else {
   1470                                                         // The feature name is not `<dep_name>` and all of
   1471                                                         // feature dependencies of all features are not named
   1472                                                         // `"dep:<dep_name>"`; thus we need to continue our
   1473                                                         // search.
   1474                                                         Ok(())
   1475                                                     }
   1476                                                 })
   1477                                                 .map_or(Ok(()), |()| {
   1478                                                     if allow_implied_features {
   1479                                                         // There is no feature with the name `<dep_name>` nor
   1480                                                         // are there any features that contain a feature
   1481                                                         // dependency named `"dep:<dep_name>"`; thus we must
   1482                                                         // insert an implied feature.
   1483                                                         self.0.push((
   1484                                                             dep_name.clone().into_owned(),
   1485                                                             Vec::new(),
   1486                                                         ));
   1487                                                         Ok(())
   1488                                                     } else {
   1489                                                         Err(DependenciesErr::ImpliedFeature(
   1490                                                             table_name,
   1491                                                             dep_name.clone().into_owned(),
   1492                                                         ))
   1493                                                     }
   1494                                                 })
   1495                                         } else {
   1496                                             Ok(())
   1497                                         }
   1498                                     } else {
   1499                                         Err(DependenciesErr::OptionalType(
   1500                                             table_name,
   1501                                             dep_name.clone().into_owned(),
   1502                                         ))
   1503                                     }
   1504                                 })
   1505                             }
   1506                             DeValue::Integer(_)
   1507                             | DeValue::Float(_)
   1508                             | DeValue::Boolean(_)
   1509                             | DeValue::Datetime(_)
   1510                             | DeValue::Array(_) => Err(DependenciesErr::DependencyType(
   1511                                 table_name,
   1512                                 dep_name.clone().into_owned(),
   1513                             )),
   1514                         }
   1515                     } else {
   1516                         Err(DependenciesErr::Name(
   1517                             table_name,
   1518                             dep_name.clone().into_owned(),
   1519                         ))
   1520                     }
   1521                 })
   1522             } else {
   1523                 Err(DependenciesErr::Type(table_name))
   1524             }
   1525         })
   1526     }
   1527     /// Adds implied features to `self` based on the optional dependencies in `toml` iff `allow_implied_features`.
   1528     fn add_implied_features(
   1529         &mut self,
   1530         toml: &Map<Spanned<Cow<'_, str>>, Spanned<DeValue<'_>>>,
   1531         allow_implied_features: bool,
   1532     ) -> Result<(), ImpliedFeaturesErr> {
   1533         self.add_optional_dependencies(toml, DepTable::Dependencies, allow_implied_features).map_err(ImpliedFeaturesErr::Dependencies).and_then(|()| self.add_optional_dependencies(toml, DepTable::BuildDependencies, allow_implied_features).map_err(ImpliedFeaturesErr::Dependencies).and_then(|()| toml.get(TARGET).map_or_else(
   1534             || Ok(()),
   1535             |target_span| {
   1536                 if let DeValue::Table(ref target) = *target_span.get_ref() {
   1537                     target.iter().try_fold((), |(), target_platform_span| {
   1538                         if let DeValue::Table(ref target_platform) = *target_platform_span.1.get_ref() {
   1539                             self.add_optional_dependencies(target_platform, DepTable::Dependencies, allow_implied_features).map_err(|e| ImpliedFeaturesErr::TagetPlatformDependencies(target_platform_span.0.get_ref().clone().into_owned(), e)).and_then(|()| self.add_optional_dependencies(target_platform, DepTable::BuildDependencies, allow_implied_features).map_err(|e| ImpliedFeaturesErr::TagetPlatformDependencies(target_platform_span.0.get_ref().clone().into_owned(), e)))
   1540                         } else {
   1541                             Err(ImpliedFeaturesErr::TargetPlatformType(target_platform_span.0.get_ref().clone().into_owned()))
   1542                         }
   1543                     })
   1544                 } else {
   1545                     Err(ImpliedFeaturesErr::TargetType)
   1546                 }
   1547             }
   1548         ).and_then(|()| {
   1549             if allow_implied_features {
   1550                 // We don't have to worry about cyclic features or anything other than the lack of a feature with
   1551                 // the name of the feature dependency.
   1552                 self.0.iter().try_fold((), |(), feature| feature.1.iter().try_fold((), |(), dep| {
   1553                      // We didn't save any feature dependencies that contain `'/'`, so we simply have to check if
   1554                      // a dependency begins with [`DEP`] to skip it.
   1555                      if is_feature_dependency_a_dependency(dep.as_bytes()) || self.0.iter().any(|other_feature| other_feature.0 == *dep) {
   1556                          Ok(())
   1557                      } else {
   1558                          Err(ImpliedFeaturesErr::InvalidDependency(feature.0.clone(), dep.clone()))
   1559                      }
   1560                  }))
   1561             } else {
   1562                 // When `!allowed_implied_features`, [`Self::validate_dependencies`] verifies non-dependency
   1563                 // feature dependencies are defined as features.
   1564                 Ok(())
   1565             }
   1566         })))
   1567     }
   1568     /// Returns the power set of `self` with semantically equivalent sets removed.
   1569     ///
   1570     /// The empty set of features is skipped iff `skip_no_feats`. None is only
   1571     /// returned if there are no sets of features. This is only possible iff
   1572     /// `self` contains no features and `skip_no_feats`.
   1573     pub(crate) fn power_set(
   1574         &self,
   1575         skip_no_feats: bool,
   1576     ) -> Result<Option<PowerSet<'_>>, TooManyFeaturesErr> {
   1577         PowerSet::new(self, skip_no_feats)
   1578     }
   1579 }
   1580 /// Package and features in `Cargo.toml`.
   1581 #[cfg_attr(test, derive(Debug, PartialEq))]
   1582 pub(crate) struct Manifest {
   1583     /// The package.
   1584     package: Package,
   1585     /// The features.
   1586     features: Features,
   1587 }
   1588 impl Manifest {
   1589     /// Returns the defined MSRV iff there was one defined.
   1590     pub(crate) const fn package(&self) -> &Package {
   1591         &self.package
   1592     }
   1593     /// Returns the defined features.
   1594     ///
   1595     /// Note the returned `Features` doesn't have any cyclic features, each feature dependency for a given
   1596     /// feature is a feature itself, and there are no redundant feature dependencies for a given feature.
   1597     pub(crate) const fn features(&self) -> &Features {
   1598         &self.features
   1599     }
   1600     /// Returns the data needed from `Cargo.toml`.
   1601     ///
   1602     /// Note `ignore_features` MUST not contain an empty `String`.
   1603     #[expect(
   1604         clippy::arithmetic_side_effects,
   1605         reason = "comments justify correctness"
   1606     )]
   1607     #[expect(
   1608         clippy::needless_pass_by_value,
   1609         reason = "want to drop `val` as soon as possible"
   1610     )]
   1611     pub(crate) fn from_toml(
   1612         val: String,
   1613         allow_implied_features: bool,
   1614         cargo_toml: &Path,
   1615         ignore_features: &[String],
   1616     ) -> Result<Self, Box<ManifestErr>> {
   1617         Map::parse(val.as_str())
   1618             .map_err(|e| Box::new(ManifestErr::Toml(e, cargo_toml.to_path_buf())))
   1619             .and_then(|span| {
   1620                 let cargo = span.get_ref();
   1621                 Package::extract_from_toml(cargo, cargo_toml)
   1622                     .map_err(|e| Box::new(ManifestErr::Package(e, cargo_toml.to_path_buf())))
   1623                     .and_then(|package| {
   1624                         Features::extract_from_toml(cargo, allow_implied_features)
   1625                             .map_err(|e| {
   1626                                 Box::new(ManifestErr::Features(e, cargo_toml.to_path_buf()))
   1627                             })
   1628                             .and_then(|mut features| {
   1629                                 features
   1630                                     .add_implied_features(cargo, allow_implied_features)
   1631                                     .map_err(|e| {
   1632                                         Box::new(ManifestErr::ImpliedFeatures(
   1633                                             e,
   1634                                             cargo_toml.to_path_buf(),
   1635                                         ))
   1636                                     })
   1637                                     .and_then(|()| {
   1638                                         features.0.iter_mut().fold(
   1639                                             (),
   1640                                             |(), &mut (_, ref mut deps)| {
   1641                                                 deps.retain(|d| {
   1642                                                     // We retain only features. Since we didn't save any
   1643                                                     // dependencies that contain `'/'`, it's slightly faster to just
   1644                                                     // check that a feature dependency is not a dependency.
   1645                                                     !is_feature_dependency_a_dependency(
   1646                                                         d.as_bytes(),
   1647                                                     )
   1648                                                 });
   1649                                             },
   1650                                         );
   1651                                         // First we ensure all features we are to ignore are defined;
   1652                                         // while doing this, we remove the feature. Note `ignore_features`
   1653                                         // and `features` only contain distinct features, so we simply
   1654                                         // have to check for the first occurrence.
   1655                                         // Note calling code is required to have removed the empty
   1656                                         // string if it had existed.
   1657                                         ignore_features
   1658                                             .iter()
   1659                                             .try_fold((), |(), ig_feat| {
   1660                                                 features
   1661                                                     .0
   1662                                                     .iter()
   1663                                                     .try_fold(0, |idx, info| {
   1664                                                         if info.0 == *ig_feat {
   1665                                                             Err(idx)
   1666                                                         } else {
   1667                                                             // Clearly free from overflow.
   1668                                                             Ok(idx + 1)
   1669                                                         }
   1670                                                     })
   1671                                                     .map_or_else(
   1672                                                         |idx| {
   1673                                                             drop(features.0.swap_remove(idx));
   1674                                                             Ok(())
   1675                                                         },
   1676                                                         |_| {
   1677                                                             Err(Box::new(
   1678                                                                 ManifestErr::UndefinedIgnoreFeature(
   1679                                                                     ig_feat.clone(),
   1680                                                                     cargo_toml.to_path_buf(),
   1681                                                                 ),
   1682                                                             ))
   1683                                                         },
   1684                                                     )
   1685                                             })
   1686                                             .map(|()| {
   1687                                                 // Now we remove all features that depend on the
   1688                                                 // features we are to ignore.
   1689                                                 ignore_features.iter().fold((), |(), ig_feat| {
   1690                                                     features.0.retain(|info| {
   1691                                                         !info.1.iter().any(|d| d == ig_feat)
   1692                                                     });
   1693                                                 });
   1694                                                 Self { package, features }
   1695                                             })
   1696                                     })
   1697                             })
   1698                     })
   1699             })
   1700     }
   1701 }
   1702 #[cfg(test)]
   1703 mod tests {
   1704     use super::{
   1705         DependenciesErr, FeatureDependenciesErr, Features, FeaturesErr, ImpliedFeaturesErr,
   1706         Manifest, ManifestErr, Msrv, NonZeroUsizePlus1, Package, PackageErr, Path, PathBuf,
   1707         PowerSet, TooManyFeaturesErr, WorkspaceErr,
   1708     };
   1709     impl PartialEq for PackageErr {
   1710         fn eq(&self, other: &Self) -> bool {
   1711             match *self {
   1712                 Self::Missing => matches!(*other, Self::Missing),
   1713                 Self::InvalidType => matches!(*other, Self::InvalidType),
   1714                 Self::MissingName => matches!(*other, Self::MissingName),
   1715                 Self::InvalidNameType => matches!(*other, Self::InvalidNameType),
   1716                 Self::InvalidMsrvType => matches!(*other, Self::InvalidMsrvType),
   1717                 Self::Msrv => matches!(*other, Self::Msrv),
   1718                 Self::MsrvWorkspaceMissing => matches!(*other, Self::MsrvWorkspaceMissing),
   1719                 Self::MsrvWorkspaceVal => matches!(*other, Self::MsrvWorkspaceVal),
   1720                 Self::InvalidWorkspaceType => matches!(*other, Self::InvalidWorkspaceType),
   1721                 Self::WorkspaceIo(ref e) => {
   1722                     matches!(*other, Self::WorkspaceIo(ref e2) if e.kind() == e2.kind())
   1723                 }
   1724                 Self::WorkspaceDoesNotExist => matches!(*other, Self::WorkspaceDoesNotExist),
   1725                 Self::WorkspaceRead(ref e, ref p) => {
   1726                     matches!(*other, Self::WorkspaceRead(ref e2, ref p2) if e.kind() == e2.kind() && p == p2)
   1727                 }
   1728                 Self::WorkspaceToml(ref e, ref p) => {
   1729                     matches!(*other, Self::WorkspaceToml(ref e2, ref p2) if e == e2 && p == p2)
   1730                 }
   1731                 Self::Workspace(e, ref p) => {
   1732                     matches!(*other, Self::Workspace(e2, ref p2) if e == e2 && p == p2)
   1733                 }
   1734             }
   1735         }
   1736     }
   1737     #[expect(
   1738         clippy::cognitive_complexity,
   1739         clippy::too_many_lines,
   1740         reason = "want to test a lot of things"
   1741     )]
   1742     #[test]
   1743     fn cargo_toml() {
   1744         assert!(
   1745             Manifest::from_toml("a".to_owned(), false, Path::new(""), &[])
   1746                 .map_or_else(|e| matches!(*e, ManifestErr::Toml(_, _)), |_| false)
   1747         );
   1748         assert_eq!(
   1749             Manifest::from_toml(String::new(), false, Path::new(""), &[]),
   1750             Err(Box::new(ManifestErr::Package(
   1751                 PackageErr::Missing,
   1752                 PathBuf::new()
   1753             )))
   1754         );
   1755         assert_eq!(
   1756             Manifest::from_toml("[' package']".to_owned(), false, Path::new(""), &[]),
   1757             Err(Box::new(ManifestErr::Package(
   1758                 PackageErr::Missing,
   1759                 PathBuf::new()
   1760             )))
   1761         );
   1762         assert_eq!(
   1763             Manifest::from_toml("['package ']".to_owned(), false, Path::new(""), &[]),
   1764             Err(Box::new(ManifestErr::Package(
   1765                 PackageErr::Missing,
   1766                 PathBuf::new()
   1767             )))
   1768         );
   1769         assert_eq!(
   1770             Manifest::from_toml("package=2".to_owned(), false, Path::new(""), &[]),
   1771             Err(Box::new(ManifestErr::Package(
   1772                 PackageErr::InvalidType,
   1773                 PathBuf::new()
   1774             )))
   1775         );
   1776         assert_eq!(
   1777             Manifest::from_toml("[package]".to_owned(), false, Path::new(""), &[]),
   1778             Err(Box::new(ManifestErr::Package(
   1779                 PackageErr::MissingName,
   1780                 PathBuf::new()
   1781             )))
   1782         );
   1783         assert_eq!(
   1784             Manifest::from_toml("[package]\nname=true".to_owned(), false, Path::new(""), &[]),
   1785             Err(Box::new(ManifestErr::Package(
   1786                 PackageErr::InvalidNameType,
   1787                 PathBuf::new()
   1788             )))
   1789         );
   1790         assert_eq!(
   1791             Manifest::from_toml(
   1792                 "[package]\nname=\"\"\n\nrust-version=2".to_owned(),
   1793                 false,
   1794                 Path::new(""),
   1795                 &[]
   1796             ),
   1797             Err(Box::new(ManifestErr::Package(
   1798                 PackageErr::InvalidMsrvType,
   1799                 PathBuf::new()
   1800             )))
   1801         );
   1802         assert_eq!(
   1803             Manifest::from_toml(
   1804                 "[package]\nname=\"\"\nrust-version=\"\"".to_owned(),
   1805                 false,
   1806                 Path::new(""),
   1807                 &[]
   1808             ),
   1809             Err(Box::new(ManifestErr::Package(
   1810                 PackageErr::Msrv,
   1811                 PathBuf::new()
   1812             )))
   1813         );
   1814         assert_eq!(
   1815             Manifest::from_toml(
   1816                 "[package]\nname=\"\"\nrust-version=\"a\"".to_owned(),
   1817                 false,
   1818                 Path::new(""),
   1819                 &[]
   1820             ),
   1821             Err(Box::new(ManifestErr::Package(
   1822                 PackageErr::Msrv,
   1823                 PathBuf::new()
   1824             )))
   1825         );
   1826         assert_eq!(
   1827             Manifest::from_toml(
   1828                 "[package]\nname=\"\"\nrust-version=\"1.00.0\"".to_owned(),
   1829                 false,
   1830                 Path::new(""),
   1831                 &[]
   1832             ),
   1833             Err(Box::new(ManifestErr::Package(
   1834                 PackageErr::Msrv,
   1835                 PathBuf::new()
   1836             )))
   1837         );
   1838         assert_eq!(
   1839             Manifest::from_toml(
   1840                 "[package]\nname=\"\"\nrust-version=\"1..0\"".to_owned(),
   1841                 false,
   1842                 Path::new(""),
   1843                 &[]
   1844             ),
   1845             Err(Box::new(ManifestErr::Package(
   1846                 PackageErr::Msrv,
   1847                 PathBuf::new()
   1848             )))
   1849         );
   1850         assert_eq!(
   1851             Manifest::from_toml(
   1852                 "[package]\nname=\"\"\nrust-version=\"1.\"".to_owned(),
   1853                 false,
   1854                 Path::new(""),
   1855                 &[]
   1856             ),
   1857             Err(Box::new(ManifestErr::Package(
   1858                 PackageErr::Msrv,
   1859                 PathBuf::new()
   1860             )))
   1861         );
   1862         assert_eq!(
   1863             Manifest::from_toml(
   1864                 "[package]\nname=\"\"\nrust-version=\"01.0.0\"".to_owned(),
   1865                 false,
   1866                 Path::new(""),
   1867                 &[]
   1868             ),
   1869             Err(Box::new(ManifestErr::Package(
   1870                 PackageErr::Msrv,
   1871                 PathBuf::new()
   1872             )))
   1873         );
   1874         assert_eq!(
   1875             Manifest::from_toml(
   1876                 "[package]\nname=\"\"\nrust-version=\"1.0.0.1\"".to_owned(),
   1877                 false,
   1878                 Path::new(""),
   1879                 &[]
   1880             ),
   1881             Err(Box::new(ManifestErr::Package(
   1882                 PackageErr::Msrv,
   1883                 PathBuf::new()
   1884             )))
   1885         );
   1886         assert_eq!(
   1887             Manifest::from_toml(
   1888                 "[package]\nname=\"\"\nrust-version=\"111111111111111111111111.2.3\"".to_owned(),
   1889                 false,
   1890                 Path::new(""),
   1891                 &[]
   1892             ),
   1893             Err(Box::new(ManifestErr::Package(
   1894                 PackageErr::Msrv,
   1895                 PathBuf::new()
   1896             )))
   1897         );
   1898         assert_eq!(
   1899             Manifest::from_toml(
   1900                 "[package]\nname=\"\"\nrust-version=\"1.0.0-nightly\"".to_owned(),
   1901                 false,
   1902                 Path::new(""),
   1903                 &[]
   1904             ),
   1905             Err(Box::new(ManifestErr::Package(
   1906                 PackageErr::Msrv,
   1907                 PathBuf::new()
   1908             )))
   1909         );
   1910         assert_eq!(
   1911             Manifest::from_toml(
   1912                 "[package]\nname=\"\"\nrust-version=\"-1.0.0\"".to_owned(),
   1913                 false,
   1914                 Path::new(""),
   1915                 &[]
   1916             ),
   1917             Err(Box::new(ManifestErr::Package(
   1918                 PackageErr::Msrv,
   1919                 PathBuf::new()
   1920             )))
   1921         );
   1922         assert_eq!(
   1923             Manifest::from_toml(
   1924                 "[package]\nname=\"\"\nrust-version=\" 1.0.0\"".to_owned(),
   1925                 false,
   1926                 Path::new(""),
   1927                 &[]
   1928             ),
   1929             Err(Box::new(ManifestErr::Package(
   1930                 PackageErr::Msrv,
   1931                 PathBuf::new()
   1932             )))
   1933         );
   1934         assert_eq!(
   1935             Manifest::from_toml(
   1936                 "[package]\nname=\"\"\nrust-version=\"1.0.0 \"".to_owned(),
   1937                 false,
   1938                 Path::new(""),
   1939                 &[]
   1940             ),
   1941             Err(Box::new(ManifestErr::Package(
   1942                 PackageErr::Msrv,
   1943                 PathBuf::new()
   1944             )))
   1945         );
   1946         assert_eq!(
   1947             Manifest::from_toml(
   1948                 "[package]\nname=\"\"\nrust-version={}".to_owned(),
   1949                 false,
   1950                 Path::new(""),
   1951                 &[]
   1952             ),
   1953             Err(Box::new(ManifestErr::Package(
   1954                 PackageErr::MsrvWorkspaceMissing,
   1955                 PathBuf::new()
   1956             )))
   1957         );
   1958         assert_eq!(
   1959             Manifest::from_toml(
   1960                 "[package]\nname=\"\"\nrust-version={workspace=2}".to_owned(),
   1961                 false,
   1962                 Path::new(""),
   1963                 &[]
   1964             ),
   1965             Err(Box::new(ManifestErr::Package(
   1966                 PackageErr::MsrvWorkspaceVal,
   1967                 PathBuf::new()
   1968             )))
   1969         );
   1970         assert_eq!(
   1971             Manifest::from_toml(
   1972                 "[package]\nname=\"\"\nrust-version={workspace=false}".to_owned(),
   1973                 false,
   1974                 Path::new(""),
   1975                 &[]
   1976             ),
   1977             Err(Box::new(ManifestErr::Package(
   1978                 PackageErr::MsrvWorkspaceVal,
   1979                 PathBuf::new()
   1980             )))
   1981         );
   1982         assert_eq!(
   1983             Manifest::from_toml(
   1984                 "[package]\nname=\"\"\nrust-version={workspace=true}\nworkspace=2".to_owned(),
   1985                 false,
   1986                 Path::new(""),
   1987                 &[]
   1988             ),
   1989             Err(Box::new(ManifestErr::Package(
   1990                 PackageErr::InvalidWorkspaceType,
   1991                 PathBuf::new()
   1992             )))
   1993         );
   1994         assert_eq!(
   1995             Manifest::from_toml(
   1996                 "workspace=2\n[package]\nname=\"\"\nrust-version={workspace=true}".to_owned(),
   1997                 false,
   1998                 Path::new(""),
   1999                 &[]
   2000             ),
   2001             Err(Box::new(ManifestErr::Package(
   2002                 PackageErr::Workspace(WorkspaceErr::InvalidType, PathBuf::new()),
   2003                 PathBuf::new()
   2004             )))
   2005         );
   2006         assert_eq!(
   2007             Manifest::from_toml(
   2008                 "[workspace]\n[package]\nname=\"\"\nrust-version={workspace=true}".to_owned(),
   2009                 false,
   2010                 Path::new(""),
   2011                 &[]
   2012             ),
   2013             Err(Box::new(ManifestErr::Package(
   2014                 PackageErr::Workspace(WorkspaceErr::MissingPackage, PathBuf::new()),
   2015                 PathBuf::new()
   2016             )))
   2017         );
   2018         assert_eq!(
   2019             Manifest::from_toml(
   2020                 "[workspace]\npackage=2\n[package]\nname=\"\"\nrust-version={workspace=true}"
   2021                     .to_owned(),
   2022                 false,
   2023                 Path::new(""),
   2024                 &[]
   2025             ),
   2026             Err(Box::new(ManifestErr::Package(
   2027                 PackageErr::Workspace(WorkspaceErr::InvalidPackageType, PathBuf::new()),
   2028                 PathBuf::new()
   2029             )))
   2030         );
   2031         assert_eq!(
   2032             Manifest::from_toml(
   2033                 "[workspace.package]\n[package]\nname=\"\"\nrust-version={workspace=true}"
   2034                     .to_owned(),
   2035                 false,
   2036                 Path::new(""),
   2037                 &[]
   2038             ),
   2039             Err(Box::new(ManifestErr::Package(
   2040                 PackageErr::Workspace(WorkspaceErr::MissingPackageMsrv, PathBuf::new()),
   2041                 PathBuf::new()
   2042             )))
   2043         );
   2044         assert_eq!(
   2045             Manifest::from_toml(
   2046                 "[workspace.package]\nrust-version={}\n[package]\nname=\"\"\nrust-version={workspace=true}"
   2047                     .to_owned(),
   2048                 false,
   2049                 Path::new(""),
   2050                 &[]
   2051             ),
   2052             Err(Box::new(ManifestErr::Package(
   2053                 PackageErr::Workspace(WorkspaceErr::InvalidPackageMsrvType, PathBuf::new()),
   2054                 PathBuf::new()
   2055             )))
   2056         );
   2057         assert_eq!(
   2058             Manifest::from_toml(
   2059                 "[workspace.package]\nrust-version=\"\"\n[package]\nname=\"\"\nrust-version={workspace=true}"
   2060                     .to_owned(),
   2061                 false,
   2062                 Path::new(""),
   2063                 &[]
   2064             ),
   2065             Err(Box::new(ManifestErr::Package(
   2066                 PackageErr::Workspace(WorkspaceErr::Msrv, PathBuf::new()),
   2067                 PathBuf::new()
   2068             )))
   2069         );
   2070         assert_eq!(
   2071             Manifest::from_toml(
   2072                 "features=2\n[package]\nname=\"\"".to_owned(),
   2073                 false,
   2074                 Path::new(""),
   2075                 &[]
   2076             ),
   2077             Err(Box::new(ManifestErr::Features(
   2078                 FeaturesErr::InvalidType,
   2079                 PathBuf::new()
   2080             )))
   2081         );
   2082         assert_eq!(
   2083             Manifest::from_toml(
   2084                 "[features]\n\"/\"=[]\n[package]\nname=\"\"".to_owned(),
   2085                 false,
   2086                 Path::new(""),
   2087                 &[]
   2088             ),
   2089             Err(Box::new(ManifestErr::Features(
   2090                 FeaturesErr::InvalidName("/".to_owned()),
   2091                 PathBuf::new()
   2092             )))
   2093         );
   2094         assert_eq!(
   2095             Manifest::from_toml(
   2096                 "[features]\n\"dep:\"=[]\n[package]\nname=\"\"".to_owned(),
   2097                 false,
   2098                 Path::new(""),
   2099                 &[]
   2100             ),
   2101             Err(Box::new(ManifestErr::Features(
   2102                 FeaturesErr::InvalidName("dep:".to_owned()),
   2103                 PathBuf::new()
   2104             )))
   2105         );
   2106         assert_eq!(
   2107             Manifest::from_toml(
   2108                 "[features]\n\"\"=2\n[package]\nname=\"\"".to_owned(),
   2109                 false,
   2110                 Path::new(""),
   2111                 &[]
   2112             ),
   2113             Err(Box::new(ManifestErr::Features(
   2114                 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::InvalidFeatureType(
   2115                     String::new()
   2116                 )),
   2117                 PathBuf::new()
   2118             )))
   2119         );
   2120         assert_eq!(
   2121             Manifest::from_toml(
   2122                 "[features]\n\"\"=[true]\n[package]\nname=\"\"".to_owned(),
   2123                 false,
   2124                 Path::new(""),
   2125                 &[]
   2126             ),
   2127             Err(Box::new(ManifestErr::Features(
   2128                 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::InvalidDependencyType(
   2129                     String::new()
   2130                 )),
   2131                 PathBuf::new()
   2132             )))
   2133         );
   2134         assert_eq!(
   2135             Manifest::from_toml(
   2136                 "[features]\n\"\"=[\"foo\"]\n[package]\nname=\"\"".to_owned(),
   2137                 false,
   2138                 Path::new(""),
   2139                 &[]
   2140             ),
   2141             Err(Box::new(ManifestErr::Features(
   2142                 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::InvalidDependency(
   2143                     String::new(),
   2144                     "foo".to_owned()
   2145                 )),
   2146                 PathBuf::new()
   2147             )))
   2148         );
   2149         // Feature dependencies can't be implied features when implied features are forbidden.
   2150         assert_eq!(
   2151             Manifest::from_toml(
   2152                 "[dependencies]\nfoo={optional=true}\n[features]\n\"\"=[\"foo\"]\n[package]\nname=\"\""
   2153                     .to_owned(),
   2154                 false,
   2155                 Path::new(""),
   2156                 &[]
   2157             ),
   2158             Err(Box::new(ManifestErr::Features(
   2159                 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::InvalidDependency(
   2160                     String::new(),
   2161                     "foo".to_owned()
   2162                 )),
   2163                 PathBuf::new()
   2164             )))
   2165         );
   2166         assert_eq!(
   2167             Manifest::from_toml(
   2168                 "[features]\n\"\"=[\"\"]\n[package]\nname=\"\"".to_owned(),
   2169                 false,
   2170                 Path::new(""),
   2171                 &[]
   2172             ),
   2173             Err(Box::new(ManifestErr::Features(
   2174                 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::CyclicFeature(
   2175                     String::new()
   2176                 )),
   2177                 PathBuf::new()
   2178             )))
   2179         );
   2180         assert_eq!(
   2181             Manifest::from_toml(
   2182                 "[features]\n\"\"=[\"a\"]\na=[\"\"]\n[package]\nname=\"\"".to_owned(),
   2183                 false,
   2184                 Path::new(""),
   2185                 &[]
   2186             ),
   2187             Err(Box::new(ManifestErr::Features(
   2188                 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::CyclicFeature(
   2189                     String::new()
   2190                 )),
   2191                 PathBuf::new()
   2192             )))
   2193         );
   2194         assert_eq!(
   2195             Manifest::from_toml(
   2196                 "[features]\n\"\"=[\"a\"]\na=[\"b\"]\nb=[\"a\"]\n[package]\nname=\"\"".to_owned(),
   2197                 false,
   2198                 Path::new(""),
   2199                 &[]
   2200             ),
   2201             Err(Box::new(ManifestErr::Features(
   2202                 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::CyclicFeature(
   2203                     "a".to_owned()
   2204                 )),
   2205                 PathBuf::new()
   2206             )))
   2207         );
   2208         assert_eq!(
   2209             Manifest::from_toml(
   2210                 "[features]\n\"\"=[\"a\"]\na=[\"c\",\"b\"]\nb=[\"a\"]\nc=[]\n[package]\nname=\"\""
   2211                     .to_owned(),
   2212                 false,
   2213                 Path::new(""),
   2214                 &[]
   2215             ),
   2216             Err(Box::new(ManifestErr::Features(
   2217                 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::CyclicFeature(
   2218                     "a".to_owned()
   2219                 )),
   2220                 PathBuf::new()
   2221             )))
   2222         );
   2223         assert_eq!(
   2224             Manifest::from_toml(
   2225                 "[features]\n\"\"=[]\na=[\"c\",\"b\"]\nb=[\"a\"]\nc=[]\n[package]\nname=\"\""
   2226                     .to_owned(),
   2227                 false,
   2228                 Path::new(""),
   2229                 &[]
   2230             ),
   2231             Err(Box::new(ManifestErr::Features(
   2232                 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::CyclicFeature(
   2233                     "a".to_owned()
   2234                 )),
   2235                 PathBuf::new()
   2236             )))
   2237         );
   2238         assert_eq!(
   2239             Manifest::from_toml(
   2240                 "[features]\n\"\"=[\"a\",\"b\"]\na=[\"b\"]\nb=[]\n[package]\nname=\"\"".to_owned(),
   2241                 false,
   2242                 Path::new(""),
   2243                 &[]
   2244             ),
   2245             Err(Box::new(ManifestErr::Features(
   2246                 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::RedundantDependency(
   2247                     String::new(),
   2248                     "b".to_owned()
   2249                 )),
   2250                 PathBuf::new()
   2251             )))
   2252         );
   2253         assert_eq!(
   2254             Manifest::from_toml(
   2255                 "[features]\n\"\"=[\"a\",\"a\"]\na=[]\n[package]\nname=\"\"".to_owned(),
   2256                 false,
   2257                 Path::new(""),
   2258                 &[]
   2259             ),
   2260             Err(Box::new(ManifestErr::Features(
   2261                 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::RedundantDependency(
   2262                     String::new(),
   2263                     "a".to_owned()
   2264                 )),
   2265                 PathBuf::new()
   2266             )))
   2267         );
   2268         // Duplicate `"dep:"` feature dependencies error.
   2269         assert_eq!(
   2270             Manifest::from_toml(
   2271                 "[features]\n\"\"=[\"dep:\",\"dep:\"]\na=[]\n[package]\nname=\"\"".to_owned(),
   2272                 false,
   2273                 Path::new(""),
   2274                 &[]
   2275             ),
   2276             Err(Box::new(ManifestErr::Features(
   2277                 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::RedundantDependency(
   2278                     String::new(),
   2279                     "dep:".to_owned()
   2280                 )),
   2281                 PathBuf::new()
   2282             )))
   2283         );
   2284         assert_eq!(
   2285             Manifest::from_toml(
   2286                 "target=2\n[package]\nname=\"\"".to_owned(),
   2287                 false,
   2288                 Path::new(""),
   2289                 &[]
   2290             ),
   2291             Err(Box::new(ManifestErr::ImpliedFeatures(
   2292                 ImpliedFeaturesErr::TargetType,
   2293                 PathBuf::new()
   2294             )))
   2295         );
   2296         assert_eq!(
   2297             Manifest::from_toml(
   2298                 "dependencies=2\n[package]\nname=\"\"".to_owned(),
   2299                 false,
   2300                 Path::new(""),
   2301                 &[]
   2302             ),
   2303             Err(Box::new(ManifestErr::ImpliedFeatures(
   2304                 ImpliedFeaturesErr::Dependencies(DependenciesErr::Type("dependencies")),
   2305                 PathBuf::new()
   2306             )))
   2307         );
   2308         assert_eq!(
   2309             Manifest::from_toml(
   2310                 "build-dependencies=2\n[package]\nname=\"\"".to_owned(),
   2311                 false,
   2312                 Path::new(""),
   2313                 &[]
   2314             ),
   2315             Err(Box::new(ManifestErr::ImpliedFeatures(
   2316                 ImpliedFeaturesErr::Dependencies(DependenciesErr::Type("build-dependencies")),
   2317                 PathBuf::new(),
   2318             )))
   2319         );
   2320         assert_eq!(
   2321             Manifest::from_toml(
   2322                 "[dependencies]\n\"dep:\"=\"\"\n[package]\nname=\"\"".to_owned(),
   2323                 false,
   2324                 Path::new(""),
   2325                 &[]
   2326             ),
   2327             Err(Box::new(ManifestErr::ImpliedFeatures(
   2328                 ImpliedFeaturesErr::Dependencies(DependenciesErr::Name(
   2329                     "dependencies",
   2330                     "dep:".to_owned()
   2331                 )),
   2332                 PathBuf::new(),
   2333             )))
   2334         );
   2335         assert_eq!(
   2336             Manifest::from_toml(
   2337                 "[dependencies]\n\"/\"=\"\"\n[package]\nname=\"\"".to_owned(),
   2338                 false,
   2339                 Path::new(""),
   2340                 &[]
   2341             ),
   2342             Err(Box::new(ManifestErr::ImpliedFeatures(
   2343                 ImpliedFeaturesErr::Dependencies(DependenciesErr::Name(
   2344                     "dependencies",
   2345                     "/".to_owned()
   2346                 )),
   2347                 PathBuf::new(),
   2348             )))
   2349         );
   2350         assert_eq!(
   2351             Manifest::from_toml(
   2352                 "[build-dependencies]\n\"dep:\"=\"\"\n[package]\nname=\"\"".to_owned(),
   2353                 false,
   2354                 Path::new(""),
   2355                 &[]
   2356             ),
   2357             Err(Box::new(ManifestErr::ImpliedFeatures(
   2358                 ImpliedFeaturesErr::Dependencies(DependenciesErr::Name(
   2359                     "build-dependencies",
   2360                     "dep:".to_owned()
   2361                 )),
   2362                 PathBuf::new(),
   2363             )))
   2364         );
   2365         assert_eq!(
   2366             Manifest::from_toml(
   2367                 "[build-dependencies]\n\"/\"=\"\"\n[package]\nname=\"\"".to_owned(),
   2368                 false,
   2369                 Path::new(""),
   2370                 &[]
   2371             ),
   2372             Err(Box::new(ManifestErr::ImpliedFeatures(
   2373                 ImpliedFeaturesErr::Dependencies(DependenciesErr::Name(
   2374                     "build-dependencies",
   2375                     "/".to_owned()
   2376                 )),
   2377                 PathBuf::new(),
   2378             )))
   2379         );
   2380         assert_eq!(
   2381             Manifest::from_toml(
   2382                 "[dependencies]\n\"\"=2\n[package]\nname=\"\"".to_owned(),
   2383                 false,
   2384                 Path::new(""),
   2385                 &[]
   2386             ),
   2387             Err(Box::new(ManifestErr::ImpliedFeatures(
   2388                 ImpliedFeaturesErr::Dependencies(DependenciesErr::DependencyType(
   2389                     "dependencies",
   2390                     String::new()
   2391                 )),
   2392                 PathBuf::new(),
   2393             )))
   2394         );
   2395         assert_eq!(
   2396             Manifest::from_toml(
   2397                 "[build-dependencies]\n\"\"=2\n[package]\nname=\"\"".to_owned(),
   2398                 false,
   2399                 Path::new(""),
   2400                 &[]
   2401             ),
   2402             Err(Box::new(ManifestErr::ImpliedFeatures(
   2403                 ImpliedFeaturesErr::Dependencies(DependenciesErr::DependencyType(
   2404                     "build-dependencies",
   2405                     String::new()
   2406                 )),
   2407                 PathBuf::new(),
   2408             )))
   2409         );
   2410         assert_eq!(
   2411             Manifest::from_toml(
   2412                 "[dependencies]\n\"\"={optional=2}\n[package]\nname=\"\"".to_owned(),
   2413                 false,
   2414                 Path::new(""),
   2415                 &[]
   2416             ),
   2417             Err(Box::new(ManifestErr::ImpliedFeatures(
   2418                 ImpliedFeaturesErr::Dependencies(DependenciesErr::OptionalType(
   2419                     "dependencies",
   2420                     String::new()
   2421                 )),
   2422                 PathBuf::new(),
   2423             )))
   2424         );
   2425         assert_eq!(
   2426             Manifest::from_toml(
   2427                 "[build-dependencies]\n\"\"={optional=2}\n[package]\nname=\"\"".to_owned(),
   2428                 false,
   2429                 Path::new(""),
   2430                 &[]
   2431             ),
   2432             Err(Box::new(ManifestErr::ImpliedFeatures(
   2433                 ImpliedFeaturesErr::Dependencies(DependenciesErr::OptionalType(
   2434                     "build-dependencies",
   2435                     String::new()
   2436                 )),
   2437                 PathBuf::new(),
   2438             )))
   2439         );
   2440         // Implied features are disallowed iff `!allow_implied_features`.
   2441         assert_eq!(
   2442             Manifest::from_toml(
   2443                 "[dependencies]\nfoo={optional=true}\n[package]\nname=\"\"".to_owned(),
   2444                 false,
   2445                 Path::new(""),
   2446                 &[]
   2447             ),
   2448             Err(Box::new(ManifestErr::ImpliedFeatures(
   2449                 ImpliedFeaturesErr::Dependencies(DependenciesErr::ImpliedFeature(
   2450                     "dependencies",
   2451                     "foo".to_owned()
   2452                 )),
   2453                 PathBuf::new(),
   2454             )))
   2455         );
   2456         assert_eq!(
   2457             Manifest::from_toml(
   2458                 "[target]\n\"\"=2\n[package]\nname=\"\"".to_owned(),
   2459                 false,
   2460                 Path::new(""),
   2461                 &[]
   2462             ),
   2463             Err(Box::new(ManifestErr::ImpliedFeatures(
   2464                 ImpliedFeaturesErr::TargetPlatformType(String::new()),
   2465                 PathBuf::new(),
   2466             )))
   2467         );
   2468         assert_eq!(
   2469             Manifest::from_toml(
   2470                 "[target.\"\"]\ndependencies=2\n[package]\nname=\"\"".to_owned(),
   2471                 false,
   2472                 Path::new(""),
   2473                 &[]
   2474             ),
   2475             Err(Box::new(ManifestErr::ImpliedFeatures(
   2476                 ImpliedFeaturesErr::TagetPlatformDependencies(
   2477                     String::new(),
   2478                     DependenciesErr::Type("dependencies")
   2479                 ),
   2480                 PathBuf::new(),
   2481             )))
   2482         );
   2483         assert_eq!(
   2484             Manifest::from_toml(
   2485                 "[target.\"\"]\nbuild-dependencies=2\n[package]\nname=\"\"".to_owned(),
   2486                 false,
   2487                 Path::new(""),
   2488                 &[]
   2489             ),
   2490             Err(Box::new(ManifestErr::ImpliedFeatures(
   2491                 ImpliedFeaturesErr::TagetPlatformDependencies(
   2492                     String::new(),
   2493                     DependenciesErr::Type("build-dependencies")
   2494                 ),
   2495                 PathBuf::new(),
   2496             )))
   2497         );
   2498         assert_eq!(
   2499             Manifest::from_toml(
   2500                 "[target.\"\".dependencies]\n\"/\"=\"\"\n[package]\nname=\"\"".to_owned(),
   2501                 false,
   2502                 Path::new(""),
   2503                 &[]
   2504             ),
   2505             Err(Box::new(ManifestErr::ImpliedFeatures(
   2506                 ImpliedFeaturesErr::TagetPlatformDependencies(
   2507                     String::new(),
   2508                     DependenciesErr::Name("dependencies", "/".to_owned())
   2509                 ),
   2510                 PathBuf::new(),
   2511             )))
   2512         );
   2513         assert_eq!(
   2514             Manifest::from_toml(
   2515                 "[target.\"\".dependencies]\n\"dep:\"=\"\"\n[package]\nname=\"\"".to_owned(),
   2516                 false,
   2517                 Path::new(""),
   2518                 &[]
   2519             ),
   2520             Err(Box::new(ManifestErr::ImpliedFeatures(
   2521                 ImpliedFeaturesErr::TagetPlatformDependencies(
   2522                     String::new(),
   2523                     DependenciesErr::Name("dependencies", "dep:".to_owned())
   2524                 ),
   2525                 PathBuf::new(),
   2526             )))
   2527         );
   2528         assert_eq!(
   2529             Manifest::from_toml(
   2530                 "[target.\"\".build-dependencies]\n\"/\"=\"\"\n[package]\nname=\"\"".to_owned(),
   2531                 false,
   2532                 Path::new(""),
   2533                 &[]
   2534             ),
   2535             Err(Box::new(ManifestErr::ImpliedFeatures(
   2536                 ImpliedFeaturesErr::TagetPlatformDependencies(
   2537                     String::new(),
   2538                     DependenciesErr::Name("build-dependencies", "/".to_owned())
   2539                 ),
   2540                 PathBuf::new(),
   2541             )))
   2542         );
   2543         assert_eq!(
   2544             Manifest::from_toml(
   2545                 "[target.\"\".build-dependencies]\n\"dep:\"=\"\"\n[package]\nname=\"\"".to_owned(),
   2546                 false,
   2547                 Path::new(""),
   2548                 &[]
   2549             ),
   2550             Err(Box::new(ManifestErr::ImpliedFeatures(
   2551                 ImpliedFeaturesErr::TagetPlatformDependencies(
   2552                     String::new(),
   2553                     DependenciesErr::Name("build-dependencies", "dep:".to_owned())
   2554                 ),
   2555                 PathBuf::new(),
   2556             )))
   2557         );
   2558         assert_eq!(
   2559             Manifest::from_toml(
   2560                 "[target.\"\".dependencies]\n\"\"=false\n[package]\nname=\"\"".to_owned(),
   2561                 false,
   2562                 Path::new(""),
   2563                 &[]
   2564             ),
   2565             Err(Box::new(ManifestErr::ImpliedFeatures(
   2566                 ImpliedFeaturesErr::TagetPlatformDependencies(
   2567                     String::new(),
   2568                     DependenciesErr::DependencyType("dependencies", String::new())
   2569                 ),
   2570                 PathBuf::new(),
   2571             )))
   2572         );
   2573         assert_eq!(
   2574             Manifest::from_toml(
   2575                 "[target.\"\".build-dependencies]\n\"\"=false\n[package]\nname=\"\"".to_owned(),
   2576                 false,
   2577                 Path::new(""),
   2578                 &[]
   2579             ),
   2580             Err(Box::new(ManifestErr::ImpliedFeatures(
   2581                 ImpliedFeaturesErr::TagetPlatformDependencies(
   2582                     String::new(),
   2583                     DependenciesErr::DependencyType("build-dependencies", String::new())
   2584                 ),
   2585                 PathBuf::new(),
   2586             )))
   2587         );
   2588         assert_eq!(
   2589             Manifest::from_toml(
   2590                 "[target.\"\".dependencies]\n\"\"={optional=2}\n[package]\nname=\"\"".to_owned(),
   2591                 false,
   2592                 Path::new(""),
   2593                 &[]
   2594             ),
   2595             Err(Box::new(ManifestErr::ImpliedFeatures(
   2596                 ImpliedFeaturesErr::TagetPlatformDependencies(
   2597                     String::new(),
   2598                     DependenciesErr::OptionalType("dependencies", String::new())
   2599                 ),
   2600                 PathBuf::new(),
   2601             )))
   2602         );
   2603         assert_eq!(
   2604             Manifest::from_toml(
   2605                 "[target.\"\".build-dependencies]\n\"\"={optional=2}\n[package]\nname=\"\""
   2606                     .to_owned(),
   2607                 false,
   2608                 Path::new(""),
   2609                 &[]
   2610             ),
   2611             Err(Box::new(ManifestErr::ImpliedFeatures(
   2612                 ImpliedFeaturesErr::TagetPlatformDependencies(
   2613                     String::new(),
   2614                     DependenciesErr::OptionalType("build-dependencies", String::new())
   2615                 ),
   2616                 PathBuf::new(),
   2617             )))
   2618         );
   2619         // An invalid dependency error occurs later when we `allow_implied_features` since
   2620         // implied features aren't added until after feature extraction.
   2621         assert_eq!(
   2622             Manifest::from_toml(
   2623                 "[features]\n\"\"=[\"foo\"]\n[package]\nname=\"\"".to_owned(),
   2624                 true,
   2625                 Path::new(""),
   2626                 &[]
   2627             ),
   2628             Err(Box::new(ManifestErr::ImpliedFeatures(
   2629                 ImpliedFeaturesErr::InvalidDependency(String::new(), "foo".to_owned()),
   2630                 PathBuf::new(),
   2631             )))
   2632         );
   2633         // In contrast, above would have erred sooner if `!allow_implied_features`.
   2634         assert_eq!(
   2635             Manifest::from_toml(
   2636                 "[features]\n\"\"=[\"foo\"]\n[package]\nname=\"\"".to_owned(),
   2637                 false,
   2638                 Path::new(""),
   2639                 &[]
   2640             ),
   2641             Err(Box::new(ManifestErr::Features(
   2642                 FeaturesErr::FeatureDependencies(FeatureDependenciesErr::InvalidDependency(
   2643                     String::new(),
   2644                     "foo".to_owned()
   2645                 )),
   2646                 PathBuf::new()
   2647             )))
   2648         );
   2649         assert_eq!(
   2650             Manifest::from_toml(
   2651                 "[package]\nname=\"\"".to_owned(),
   2652                 false,
   2653                 Path::new(""),
   2654                 &["a".to_owned()]
   2655             ),
   2656             Err(Box::new(ManifestErr::UndefinedIgnoreFeature(
   2657                 "a".to_owned(),
   2658                 PathBuf::new()
   2659             )))
   2660         );
   2661         // Even if we forbid implied features, we don't error when a feature is defined
   2662         // with the same name of an implied feature. This is due to simplicity in code
   2663         // and the fact that `cargo` will error anyway.
   2664         //
   2665         // For example once `cargo` is invoked, an error will occur due to duplicate features:
   2666         // the explict feature `foo` and the implied feature from the dependency `foo`.
   2667         assert_eq!(
   2668             Manifest::from_toml(
   2669                 "[dependencies]\nfoo={optional=true}\n[features]\nfoo=[]\n[package]\nname=\"\""
   2670                     .to_owned(),
   2671                 false,
   2672                 Path::new(""),
   2673                 &[]
   2674             ),
   2675             Ok(Manifest {
   2676                 package: Package {
   2677                     msrv: None,
   2678                     name: String::new(),
   2679                 },
   2680                 features: Features(vec![("foo".to_owned(), Vec::new())]),
   2681             })
   2682         );
   2683         // Allow major-only MSRV.
   2684         assert_eq!(
   2685             Manifest::from_toml(
   2686                 "[package]\nname=\"foo\"\nrust-version=\"0\"".to_owned(),
   2687                 false,
   2688                 Path::new(""),
   2689                 &[]
   2690             ),
   2691             Ok(Manifest {
   2692                 package: Package {
   2693                     msrv: Some(Msrv {
   2694                         major: 0,
   2695                         minor: None,
   2696                         patch: None,
   2697                     }),
   2698                     name: "foo".to_owned(),
   2699                 },
   2700                 features: Features(Vec::new()),
   2701             })
   2702         );
   2703         // Allow escapes.
   2704         assert_eq!(
   2705             Manifest::from_toml(
   2706                 "[\"\\u0070ackage\"]\n\"n\\u0061me\"=\"\\u0066oo\"\n\"\\u0072ust-version\"=\"0\\u002E\\u0031\"".to_owned(),
   2707                 false,
   2708                 Path::new(""),
   2709                 &[]
   2710             ),
   2711             Ok(Manifest {
   2712                 package: Package {
   2713                     msrv: Some(Msrv {
   2714                         major: 0,
   2715                         minor: Some(1),
   2716                         patch: None,
   2717                     }),
   2718                     name: "foo".to_owned(),
   2719                 },
   2720                 features: Features(Vec::new()),
   2721             })
   2722         );
   2723         assert_eq!(
   2724             Manifest::from_toml(
   2725                 "[package]\nname=\"\"\nrust-version=\"0.0.0\"".to_owned(),
   2726                 false,
   2727                 Path::new(""),
   2728                 &[]
   2729             ),
   2730             Ok(Manifest {
   2731                 package: Package {
   2732                     msrv: Some(Msrv {
   2733                         major: 0,
   2734                         minor: Some(0),
   2735                         patch: Some(0),
   2736                     }),
   2737                     name: String::new(),
   2738                 },
   2739                 features: Features(Vec::new()),
   2740             })
   2741         );
   2742         // Ignore non `rust-version` keys in `package`. Ignore keys in the root document except `package`,
   2743         // `features`, `dependencies`, `build-dependencies`, and `target`. Ignore keys in
   2744         // `target.<something>` unless the key is `dependencies` or `build-dependencies`. Don't treat
   2745         // `<something>` special in `target.<something>` other than its being a table.
   2746         assert_eq!(
   2747             Manifest::from_toml("dev-dependencies=2\n[package]\nname=\"\"\n\nfoo=2\nrust-version=\"18446744073709551615.18446744073709551615.18446744073709551615\"\n[foo]\nbar=false\n[target.\"\".foo]\nbar=2\n[target.foo]\nbar=false\n[target.dependencies]\nfoo=2\n[target.build-dependencies]\nfoo=false\n[target.dev-dependencies]\nfoo=true\n".to_owned(), false, Path::new(""), &[]),
   2748             Ok(Manifest {
   2749                 package: Package {
   2750                     msrv: Some(Msrv {
   2751                         major: u64::MAX,
   2752                         minor: Some(u64::MAX),
   2753                         patch: Some(u64::MAX),
   2754                     }),
   2755                     name: String::new(),
   2756                 },
   2757                 features: Features(Vec::new()),
   2758             })
   2759         );
   2760         // [package]
   2761         // name = ""
   2762         //
   2763         // ["\u0064ependencies"]
   2764         // "\u0000" = "\u0000"
   2765         // a = { optional = true }
   2766         //
   2767         // ["build-\u0064ependencies"]
   2768         // "\u0000" = { optional = true }
   2769         //
   2770         // [dev-dependencies]
   2771         // buzz = { optional = true }
   2772         //
   2773         // [target."".dependencies]
   2774         // b = { optional = false, foo = 2 }
   2775         // fizz = { optional = true, foo = 3 }
   2776         //
   2777         // [target.a.dependencies]
   2778         // c = { optional = true }
   2779         // wuzz = { optional = true }
   2780         //
   2781         // [features]
   2782         // default = ["bar","dep:lk","a/ak", "a/ak"]
   2783         // bar = ["dep\u003Awuzz"]
   2784         //
   2785         // We allow any and all key names unless it's the features table or a dependency table; in which case
   2786         // key names must not contain `'/'` nor begin with `"dep:"`.
   2787         //
   2788         // The order of features is based on the following hierarchy:
   2789         // * Explict features: lexicographically sorted
   2790         // * dependencies: optional only, lexicographically sorted, only if an explicit feature doesn't exist with
   2791         //   the same name nor any explicit feature contains a dependency named `"dep:<dependecy>"` and we allow
   2792         //   implied features. If such feature exists, we don't error but simply don't add.
   2793         // * build-dependencies: read above.
   2794         // * target.<something>: lexicographically sorted by something, within `something`, `dependencies`
   2795         //   is first using the same methodology as item 2, last `build-dependencies`.
   2796         //
   2797         // Once the order of features is determined, the only feature dependencies that are retained are those
   2798         // that don't contain `'/'` nor begin with `"dep:"`. We don't require dependencies to be defined for
   2799         // feature dependencies that contain `'/'` or begin with `"dep:"`. We don't care about duplicate feature
   2800         // dependencies that contain `'/'`.
   2801         //
   2802         // Based on above, `Features` looks like the following:
   2803         // 1. (bar, [])
   2804         // 2. (default, ["bar"])
   2805         // 3. (a, [])
   2806         // 4. (\x00, [])
   2807         // 5. (fizz, [])
   2808         // 6. (c, [])
   2809         assert_eq!(
   2810             Manifest::from_toml(
   2811                 "[\"\\u0064ependencies\"]\n\"\\u0000\"=\"\\u0000\"\na={optional=true}\n[\"build-\\u0064ependencies\"]\n\"\\u0000\"={optional=true}\n[target.\"\".dependencies]\nb={optional=false,foo=2}\nfizz={optional=true,foo=3}\n[features]\ndefault=[\"bar\",\"dep:lk\",\"a/ak\",\"a/ak\"]\nbar=[\"dep\\u003Awuzz\"]\n[dev-dependencies]\nbuzz={optional=true}\n[target.a.dependencies]\nc={optional=true}\nwuzz={optional=true}\n[package]\nname=\"\"".to_owned(),
   2812                 true,
   2813                 Path::new(""),
   2814                 &[]
   2815             ),
   2816             Ok(Manifest {
   2817                 package: Package {
   2818                     msrv: None,
   2819                     name: String::new(),
   2820                 },
   2821                 features: Features(vec![("bar".to_owned(), Vec::new()), ("default".to_owned(), vec!["bar".to_owned()]), ("a".to_owned(), Vec::new()), ("\0".to_owned(), Vec::new()), ("fizz".to_owned(), Vec::new()), ("c".to_owned(), Vec::new())]),
   2822             })
   2823         );
   2824         // [package]
   2825         // name = ""
   2826         //
   2827         // [dependencies]
   2828         // foo = { "optional" = true }
   2829         // fizz = { "optional" = true }
   2830         //
   2831         // [features]
   2832         // fizz = ["dep:fizz"]
   2833         // bar = ["dep:foo"]
   2834         assert_eq!(
   2835             Manifest::from_toml(
   2836                 "[package]\nname=\"\"\n[dependencies]\nfoo={optional=true}\nfizz={optional=true}\n[features]\nfizz=[\"dep:fizz\"]\nbar=[\"dep:foo\"]".to_owned(),
   2837                 false,
   2838                 Path::new(""),
   2839                 &[]
   2840             ),
   2841             Ok(Manifest {
   2842                 package: Package {
   2843                     msrv: None,
   2844                     name: String::new(),
   2845                 },
   2846                 features: Features(vec![
   2847                     ("bar".to_owned(), Vec::new()),
   2848                     ("fizz".to_owned(), Vec::new())
   2849                 ]),
   2850             })
   2851         );
   2852         // [package]
   2853         // name = ""
   2854         //
   2855         // [dependencies]
   2856         // bar = { "optional" = true }
   2857         //
   2858         // [features]
   2859         // foo = ["bar"]
   2860         assert_eq!(
   2861             Manifest::from_toml(
   2862                 "[package]\nname=\"\"\n[dependencies]\nbar={optional=true}\n[features]\nfoo=[\"bar\"]"
   2863                     .to_owned(),
   2864                 true,
   2865                 Path::new(""),
   2866                 &[]
   2867             ),
   2868             Ok(Manifest {
   2869                 package: Package {
   2870                     msrv: None,
   2871                     name: String::new(),
   2872                 },
   2873                 features: Features(vec![
   2874                     ("foo".to_owned(), vec!["bar".to_owned()]),
   2875                     ("bar".to_owned(), Vec::new()),
   2876                 ]),
   2877             })
   2878         );
   2879         assert_eq!(
   2880             Manifest::from_toml(
   2881                 "[package]\nname=\"\"\n[features]\na=[]\nb=[\"a\"]".to_owned(),
   2882                 false,
   2883                 Path::new(""),
   2884                 &["a".to_owned()]
   2885             ),
   2886             Ok(Manifest {
   2887                 package: Package {
   2888                     msrv: None,
   2889                     name: String::new(),
   2890                 },
   2891                 features: Features(vec![]),
   2892             })
   2893         );
   2894         assert_eq!(
   2895             Manifest::from_toml(
   2896                 "[package]\nname=\"\"\n[features]\na=[]\nb=[\"a\"]".to_owned(),
   2897                 false,
   2898                 Path::new(""),
   2899                 &["b".to_owned()]
   2900             ),
   2901             Ok(Manifest {
   2902                 package: Package {
   2903                     msrv: None,
   2904                     name: String::new(),
   2905                 },
   2906                 features: Features(vec![("a".to_owned(), Vec::new())]),
   2907             })
   2908         );
   2909         assert_eq!(
   2910             Manifest::from_toml(
   2911                 "[package]\nname=\"\"\n[dependencies]\nc={optional=true}\n[features]\nb=[\"c\"]"
   2912                     .to_owned(),
   2913                 true,
   2914                 Path::new(""),
   2915                 &["c".to_owned()]
   2916             ),
   2917             Ok(Manifest {
   2918                 package: Package {
   2919                     msrv: None,
   2920                     name: String::new(),
   2921                 },
   2922                 features: Features(vec![]),
   2923             })
   2924         );
   2925         assert_eq!(
   2926             Manifest::from_toml(
   2927                 "[package]\nname=\"\"\n[dependencies]\nc={optional=true}\n[features]\nb=[\"c\"]"
   2928                     .to_owned(),
   2929                 true,
   2930                 Path::new(""),
   2931                 &["b".to_owned()]
   2932             ),
   2933             Ok(Manifest {
   2934                 package: Package {
   2935                     msrv: None,
   2936                     name: String::new(),
   2937                 },
   2938                 features: Features(vec![("c".to_owned(), Vec::new())]),
   2939             })
   2940         );
   2941     }
   2942     #[expect(clippy::unreachable, reason = "want to crash when there is a bug")]
   2943     #[expect(
   2944         clippy::cognitive_complexity,
   2945         clippy::too_many_lines,
   2946         reason = "want to test for a lot of things"
   2947     )]
   2948     #[test]
   2949     fn power_set() {
   2950         #[cfg(target_pointer_width = "16")]
   2951         let feat_len_one_too_large = 17;
   2952         #[cfg(target_pointer_width = "32")]
   2953         let feat_len_one_too_large = 33;
   2954         #[cfg(target_pointer_width = "64")]
   2955         let feat_len_one_too_large = 65;
   2956         let mut feats = Features(vec![(String::new(), Vec::new()); feat_len_one_too_large]);
   2957         assert_eq!(PowerSet::new(&feats, false), Err(TooManyFeaturesErr));
   2958         #[cfg(target_pointer_width = "16")]
   2959         let max_feat_len = 16;
   2960         #[cfg(target_pointer_width = "32")]
   2961         let max_feat_len = 32;
   2962         #[cfg(target_pointer_width = "64")]
   2963         let max_feat_len = 64;
   2964         feats.0 = vec![(String::new(), Vec::new()); max_feat_len];
   2965         #[cfg(any(
   2966             target_pointer_width = "16",
   2967             target_pointer_width = "32",
   2968             target_pointer_width = "64"
   2969         ))]
   2970         assert_eq!(
   2971             PowerSet::new(&feats, false),
   2972             Ok(Some(PowerSet {
   2973                 feats: feats.0.as_slice(),
   2974                 has_remaining: true,
   2975                 check_overlap: false,
   2976                 idx: usize::MAX,
   2977                 buffer: vec![""; max_feat_len],
   2978                 set: String::new(),
   2979                 skipped_sets_counter: 0,
   2980                 skip_empty_set: false,
   2981             }))
   2982         );
   2983         feats.0 = Vec::new();
   2984         assert_eq!(
   2985             PowerSet::new(&feats, false),
   2986             Ok(Some(PowerSet {
   2987                 feats: feats.0.as_slice(),
   2988                 has_remaining: true,
   2989                 check_overlap: false,
   2990                 idx: 0,
   2991                 buffer: Vec::new(),
   2992                 set: String::new(),
   2993                 skipped_sets_counter: 0,
   2994                 skip_empty_set: false,
   2995             }))
   2996         );
   2997         assert_eq!(PowerSet::new(&feats, true), Ok(None));
   2998         let mut power_set = PowerSet::new(&feats, false)
   2999             .unwrap_or_else(|_e| {
   3000                 unreachable!("not possible since we just verified PowerSet::new returned Ok")
   3001             })
   3002             .unwrap_or_else(|| {
   3003                 unreachable!("not possible since we just verified PowerSet::new returned Ok(Some)")
   3004             });
   3005         assert_eq!(power_set.len(), NonZeroUsizePlus1::new(1));
   3006         assert_eq!(power_set.next_set(), Some(""));
   3007         assert_eq!(
   3008             power_set,
   3009             PowerSet {
   3010                 feats: feats.0.as_slice(),
   3011                 has_remaining: false,
   3012                 check_overlap: false,
   3013                 idx: 0,
   3014                 buffer: Vec::new(),
   3015                 set: String::new(),
   3016                 skipped_sets_counter: 0,
   3017                 skip_empty_set: false
   3018             }
   3019         );
   3020         assert_eq!(power_set.next_set(), None);
   3021         assert_eq!(power_set.len(), NonZeroUsizePlus1::new(1));
   3022         assert_eq!(
   3023             power_set,
   3024             PowerSet {
   3025                 feats: feats.0.as_slice(),
   3026                 has_remaining: false,
   3027                 check_overlap: false,
   3028                 idx: 0,
   3029                 buffer: Vec::new(),
   3030                 set: String::new(),
   3031                 skipped_sets_counter: 0,
   3032                 skip_empty_set: false
   3033             }
   3034         );
   3035         assert_eq!(power_set.next_set(), None);
   3036         power_set.reset();
   3037         assert_eq!(
   3038             power_set,
   3039             PowerSet {
   3040                 feats: feats.0.as_slice(),
   3041                 has_remaining: true,
   3042                 check_overlap: false,
   3043                 idx: 0,
   3044                 buffer: Vec::new(),
   3045                 set: String::new(),
   3046                 skipped_sets_counter: 0,
   3047                 skip_empty_set: false
   3048             }
   3049         );
   3050         assert_eq!(power_set.next_set(), Some(""));
   3051         assert_eq!(
   3052             power_set,
   3053             PowerSet {
   3054                 feats: feats.0.as_slice(),
   3055                 has_remaining: false,
   3056                 check_overlap: false,
   3057                 idx: 0,
   3058                 buffer: Vec::new(),
   3059                 set: String::new(),
   3060                 skipped_sets_counter: 0,
   3061                 skip_empty_set: false
   3062             }
   3063         );
   3064         assert_eq!(power_set.next_set(), None);
   3065         assert_eq!(
   3066             power_set,
   3067             PowerSet {
   3068                 feats: feats.0.as_slice(),
   3069                 has_remaining: false,
   3070                 check_overlap: false,
   3071                 idx: 0,
   3072                 buffer: Vec::new(),
   3073                 set: String::new(),
   3074                 skipped_sets_counter: 0,
   3075                 skip_empty_set: false
   3076             }
   3077         );
   3078         assert_eq!(power_set.next_set(), None);
   3079         // [features]
   3080         // a = ["b"]
   3081         // b = ["c", "d"]
   3082         // c = []
   3083         // d = []
   3084         feats.0 = vec![
   3085             ("a".to_owned(), vec!["b".to_owned()]),
   3086             ("b".to_owned(), vec!["c".to_owned(), "d".to_owned()]),
   3087             ("c".to_owned(), Vec::new()),
   3088             ("d".to_owned(), Vec::new()),
   3089         ];
   3090         assert_eq!(
   3091             PowerSet::new(&feats, false),
   3092             Ok(Some(PowerSet {
   3093                 feats: feats.0.as_slice(),
   3094                 has_remaining: true,
   3095                 // At least one feature depends on another, so this will be set to `true`.
   3096                 check_overlap: true,
   3097                 idx: 15,
   3098                 buffer: vec!["a", "b", "c", "d"],
   3099                 set: String::new(),
   3100                 skipped_sets_counter: 0,
   3101                 skip_empty_set: false
   3102             }))
   3103         );
   3104         power_set = PowerSet::new(&feats, false)
   3105             .unwrap_or_else(|_e| {
   3106                 unreachable!("not possible since we just verified PowerSet::new returned Ok")
   3107             })
   3108             .unwrap_or_else(|| {
   3109                 unreachable!("not possible since we just verified PowerSet::new returned Ok(Some)")
   3110             });
   3111         assert_eq!(power_set.len(), NonZeroUsizePlus1::new(16));
   3112         // Order is the following:
   3113         // 1. a,b,c,d: skipped since a depends on b.
   3114         // 2. b,c,d: skipped since b depends on c.
   3115         // 3. a,c,d: skipped since a depends on c (via b).
   3116         // 4. c,d
   3117         // 5. a,b,d: skipped since a depends on b.
   3118         // 6. b,d: skipped since b depends on d.
   3119         // 7. a,d: skipped since a depends on d (via b).
   3120         // 8. d
   3121         // 9. a,b,c: skipped since a depends on b.
   3122         // 10. b,c: skipped since b depends on c.
   3123         // 11. a,c: skipped since a depends on c (via b).
   3124         // 12. c
   3125         // 13. a,b: skipped since a depends on b.
   3126         // 14. b
   3127         // 15. a
   3128         // 16.
   3129         assert_eq!(power_set.next_set(), Some("c,d"));
   3130         assert_eq!(
   3131             power_set,
   3132             PowerSet {
   3133                 feats: feats.0.as_slice(),
   3134                 has_remaining: true,
   3135                 check_overlap: true,
   3136                 // We started at 15, and we iterated 4 items (skipping 3).
   3137                 idx: 11,
   3138                 buffer: vec!["c", "d"],
   3139                 set: "c,d".to_owned(),
   3140                 skipped_sets_counter: 3,
   3141                 skip_empty_set: false
   3142             }
   3143         );
   3144         assert_eq!(power_set.next_set(), Some("d"));
   3145         assert_eq!(
   3146             power_set,
   3147             PowerSet {
   3148                 feats: feats.0.as_slice(),
   3149                 has_remaining: true,
   3150                 check_overlap: true,
   3151                 // We started at 11, and we iterated 4 items (skipping 3).
   3152                 idx: 7,
   3153                 buffer: vec!["d"],
   3154                 set: "d".to_owned(),
   3155                 skipped_sets_counter: 6,
   3156                 skip_empty_set: false
   3157             }
   3158         );
   3159         assert_eq!(power_set.next_set(), Some("c"));
   3160         assert_eq!(
   3161             power_set,
   3162             PowerSet {
   3163                 feats: feats.0.as_slice(),
   3164                 has_remaining: true,
   3165                 check_overlap: true,
   3166                 // We started at 7, and we iterated 4 items (skipping 3).
   3167                 idx: 3,
   3168                 buffer: vec!["c"],
   3169                 set: "c".to_owned(),
   3170                 skipped_sets_counter: 9,
   3171                 skip_empty_set: false
   3172             }
   3173         );
   3174         assert_eq!(power_set.next_set(), Some("b"));
   3175         assert_eq!(
   3176             power_set,
   3177             PowerSet {
   3178                 feats: feats.0.as_slice(),
   3179                 has_remaining: true,
   3180                 check_overlap: true,
   3181                 // We started at 3, and we iterated 2 items (skipping 1).
   3182                 idx: 1,
   3183                 buffer: vec!["b"],
   3184                 set: "b".to_owned(),
   3185                 skipped_sets_counter: 10,
   3186                 skip_empty_set: false
   3187             }
   3188         );
   3189         assert_eq!(power_set.next_set(), Some("a"));
   3190         assert_eq!(
   3191             power_set,
   3192             PowerSet {
   3193                 feats: feats.0.as_slice(),
   3194                 has_remaining: true,
   3195                 check_overlap: true,
   3196                 // We started at 1, and we iterated 1 item.
   3197                 idx: 0,
   3198                 buffer: vec!["a"],
   3199                 set: "a".to_owned(),
   3200                 skipped_sets_counter: 10,
   3201                 skip_empty_set: false
   3202             }
   3203         );
   3204         assert_eq!(power_set.next_set(), Some(""));
   3205         assert_eq!(
   3206             power_set,
   3207             PowerSet {
   3208                 feats: feats.0.as_slice(),
   3209                 has_remaining: false,
   3210                 check_overlap: true,
   3211                 // We started at 0, and we iterated 1 item but we don't underflow instead `has_remaining` is set
   3212                 // to `false`.
   3213                 idx: 0,
   3214                 buffer: Vec::new(),
   3215                 set: String::new(),
   3216                 skipped_sets_counter: 10,
   3217                 skip_empty_set: false
   3218             }
   3219         );
   3220         assert_eq!(power_set.next_set(), None);
   3221         // Internal state is left unchanged.
   3222         assert_eq!(
   3223             power_set,
   3224             PowerSet {
   3225                 feats: feats.0.as_slice(),
   3226                 has_remaining: false,
   3227                 check_overlap: true,
   3228                 idx: 0,
   3229                 buffer: Vec::new(),
   3230                 set: String::new(),
   3231                 skipped_sets_counter: 10,
   3232                 skip_empty_set: false
   3233             }
   3234         );
   3235         assert_eq!(power_set.next_set(), None);
   3236         // Internal state is left unchanged.
   3237         assert_eq!(
   3238             power_set,
   3239             PowerSet {
   3240                 feats: feats.0.as_slice(),
   3241                 has_remaining: false,
   3242                 check_overlap: true,
   3243                 idx: 0,
   3244                 buffer: Vec::new(),
   3245                 set: String::new(),
   3246                 skipped_sets_counter: 10,
   3247                 skip_empty_set: false
   3248             }
   3249         );
   3250         assert_eq!(power_set.len(), NonZeroUsizePlus1::new(16));
   3251         power_set.reset();
   3252         // `PowerSet::reset` only resets what is necessary nothing more; in particular, `buffer` and `set` are
   3253         // left alone.
   3254         assert_eq!(
   3255             power_set,
   3256             PowerSet {
   3257                 feats: feats.0.as_slice(),
   3258                 has_remaining: true,
   3259                 check_overlap: true,
   3260                 idx: 15,
   3261                 buffer: Vec::new(),
   3262                 set: String::new(),
   3263                 skipped_sets_counter: 0,
   3264                 skip_empty_set: false
   3265             }
   3266         );
   3267         assert_eq!(power_set.len(), NonZeroUsizePlus1::new(16));
   3268         // Same as above except no feature depends on any other.
   3269         // [features]
   3270         // a = []
   3271         // b = []
   3272         // c = []
   3273         // d = []
   3274         feats.0 = vec![
   3275             ("a".to_owned(), Vec::new()),
   3276             ("b".to_owned(), Vec::new()),
   3277             ("c".to_owned(), Vec::new()),
   3278             ("d".to_owned(), Vec::new()),
   3279         ];
   3280         assert_eq!(
   3281             PowerSet::new(&feats, false),
   3282             Ok(Some(PowerSet {
   3283                 feats: feats.0.as_slice(),
   3284                 has_remaining: true,
   3285                 check_overlap: false,
   3286                 idx: 15,
   3287                 buffer: vec!["a", "b", "c", "d"],
   3288                 set: String::new(),
   3289                 skipped_sets_counter: 0,
   3290                 skip_empty_set: false
   3291             }))
   3292         );
   3293         power_set = PowerSet::new(&feats, false)
   3294             .unwrap_or_else(|_e| {
   3295                 unreachable!("not possible since we just verified PowerSet::new returned Ok")
   3296             })
   3297             .unwrap_or_else(|| {
   3298                 unreachable!("not possible since we just verified PowerSet::new returned Ok(Some)")
   3299             });
   3300         assert_eq!(power_set.len(), NonZeroUsizePlus1::new(16));
   3301         // Order is the same as above except nothing is skipped:
   3302         // 1. a,b,c,d
   3303         // 2. b,c,d
   3304         // 3. a,c,d
   3305         // 4. c,d
   3306         // 5. a,b,d
   3307         // 6. b,d
   3308         // 7. a,d
   3309         // 8. d
   3310         // 9. a,b,c
   3311         // 10. b,c
   3312         // 11. a,c
   3313         // 12. c
   3314         // 13. a,b
   3315         // 14. b
   3316         // 15. a
   3317         // 16.
   3318         assert_eq!(power_set.next_set(), Some("a,b,c,d"));
   3319         assert_eq!(
   3320             power_set,
   3321             PowerSet {
   3322                 feats: feats.0.as_slice(),
   3323                 has_remaining: true,
   3324                 check_overlap: false,
   3325                 idx: 14,
   3326                 buffer: vec!["a", "b", "c", "d"],
   3327                 set: "a,b,c,d".to_owned(),
   3328                 skipped_sets_counter: 0,
   3329                 skip_empty_set: false
   3330             }
   3331         );
   3332         assert_eq!(power_set.next_set(), Some("b,c,d"));
   3333         assert_eq!(
   3334             power_set,
   3335             PowerSet {
   3336                 feats: feats.0.as_slice(),
   3337                 has_remaining: true,
   3338                 check_overlap: false,
   3339                 idx: 13,
   3340                 buffer: vec!["b", "c", "d"],
   3341                 set: "b,c,d".to_owned(),
   3342                 skipped_sets_counter: 0,
   3343                 skip_empty_set: false
   3344             }
   3345         );
   3346         assert_eq!(power_set.next_set(), Some("a,c,d"));
   3347         assert_eq!(
   3348             power_set,
   3349             PowerSet {
   3350                 feats: feats.0.as_slice(),
   3351                 has_remaining: true,
   3352                 check_overlap: false,
   3353                 idx: 12,
   3354                 buffer: vec!["a", "c", "d"],
   3355                 set: "a,c,d".to_owned(),
   3356                 skipped_sets_counter: 0,
   3357                 skip_empty_set: false
   3358             }
   3359         );
   3360         assert_eq!(power_set.next_set(), Some("c,d"));
   3361         assert_eq!(
   3362             power_set,
   3363             PowerSet {
   3364                 feats: feats.0.as_slice(),
   3365                 has_remaining: true,
   3366                 check_overlap: false,
   3367                 idx: 11,
   3368                 buffer: vec!["c", "d"],
   3369                 set: "c,d".to_owned(),
   3370                 skipped_sets_counter: 0,
   3371                 skip_empty_set: false
   3372             }
   3373         );
   3374         assert_eq!(power_set.next_set(), Some("a,b,d"));
   3375         assert_eq!(
   3376             power_set,
   3377             PowerSet {
   3378                 feats: feats.0.as_slice(),
   3379                 has_remaining: true,
   3380                 check_overlap: false,
   3381                 idx: 10,
   3382                 buffer: vec!["a", "b", "d"],
   3383                 set: "a,b,d".to_owned(),
   3384                 skipped_sets_counter: 0,
   3385                 skip_empty_set: false
   3386             }
   3387         );
   3388         assert_eq!(power_set.next_set(), Some("b,d"));
   3389         assert_eq!(
   3390             power_set,
   3391             PowerSet {
   3392                 feats: feats.0.as_slice(),
   3393                 has_remaining: true,
   3394                 check_overlap: false,
   3395                 idx: 9,
   3396                 buffer: vec!["b", "d"],
   3397                 set: "b,d".to_owned(),
   3398                 skipped_sets_counter: 0,
   3399                 skip_empty_set: false
   3400             }
   3401         );
   3402         assert_eq!(power_set.next_set(), Some("a,d"));
   3403         assert_eq!(
   3404             power_set,
   3405             PowerSet {
   3406                 feats: feats.0.as_slice(),
   3407                 has_remaining: true,
   3408                 check_overlap: false,
   3409                 idx: 8,
   3410                 buffer: vec!["a", "d"],
   3411                 set: "a,d".to_owned(),
   3412                 skipped_sets_counter: 0,
   3413                 skip_empty_set: false
   3414             }
   3415         );
   3416         assert_eq!(power_set.next_set(), Some("d"));
   3417         assert_eq!(
   3418             power_set,
   3419             PowerSet {
   3420                 feats: feats.0.as_slice(),
   3421                 has_remaining: true,
   3422                 check_overlap: false,
   3423                 idx: 7,
   3424                 buffer: vec!["d"],
   3425                 set: "d".to_owned(),
   3426                 skipped_sets_counter: 0,
   3427                 skip_empty_set: false
   3428             }
   3429         );
   3430         assert_eq!(power_set.next_set(), Some("a,b,c"));
   3431         assert_eq!(
   3432             power_set,
   3433             PowerSet {
   3434                 feats: feats.0.as_slice(),
   3435                 has_remaining: true,
   3436                 check_overlap: false,
   3437                 idx: 6,
   3438                 buffer: vec!["a", "b", "c"],
   3439                 set: "a,b,c".to_owned(),
   3440                 skipped_sets_counter: 0,
   3441                 skip_empty_set: false
   3442             }
   3443         );
   3444         assert_eq!(power_set.next_set(), Some("b,c"));
   3445         assert_eq!(
   3446             power_set,
   3447             PowerSet {
   3448                 feats: feats.0.as_slice(),
   3449                 has_remaining: true,
   3450                 check_overlap: false,
   3451                 idx: 5,
   3452                 buffer: vec!["b", "c"],
   3453                 set: "b,c".to_owned(),
   3454                 skipped_sets_counter: 0,
   3455                 skip_empty_set: false
   3456             }
   3457         );
   3458         assert_eq!(power_set.next_set(), Some("a,c"));
   3459         assert_eq!(
   3460             power_set,
   3461             PowerSet {
   3462                 feats: feats.0.as_slice(),
   3463                 has_remaining: true,
   3464                 check_overlap: false,
   3465                 idx: 4,
   3466                 buffer: vec!["a", "c"],
   3467                 set: "a,c".to_owned(),
   3468                 skipped_sets_counter: 0,
   3469                 skip_empty_set: false
   3470             }
   3471         );
   3472         assert_eq!(power_set.next_set(), Some("c"));
   3473         assert_eq!(
   3474             power_set,
   3475             PowerSet {
   3476                 feats: feats.0.as_slice(),
   3477                 has_remaining: true,
   3478                 check_overlap: false,
   3479                 idx: 3,
   3480                 buffer: vec!["c"],
   3481                 set: "c".to_owned(),
   3482                 skipped_sets_counter: 0,
   3483                 skip_empty_set: false
   3484             }
   3485         );
   3486         assert_eq!(power_set.next_set(), Some("a,b"));
   3487         assert_eq!(
   3488             power_set,
   3489             PowerSet {
   3490                 feats: feats.0.as_slice(),
   3491                 has_remaining: true,
   3492                 check_overlap: false,
   3493                 idx: 2,
   3494                 buffer: vec!["a", "b"],
   3495                 set: "a,b".to_owned(),
   3496                 skipped_sets_counter: 0,
   3497                 skip_empty_set: false
   3498             }
   3499         );
   3500         assert_eq!(power_set.next_set(), Some("b"));
   3501         assert_eq!(
   3502             power_set,
   3503             PowerSet {
   3504                 feats: feats.0.as_slice(),
   3505                 has_remaining: true,
   3506                 check_overlap: false,
   3507                 idx: 1,
   3508                 buffer: vec!["b"],
   3509                 set: "b".to_owned(),
   3510                 skipped_sets_counter: 0,
   3511                 skip_empty_set: false
   3512             }
   3513         );
   3514         assert_eq!(power_set.next_set(), Some("a"));
   3515         assert_eq!(
   3516             power_set,
   3517             PowerSet {
   3518                 feats: feats.0.as_slice(),
   3519                 has_remaining: true,
   3520                 check_overlap: false,
   3521                 idx: 0,
   3522                 buffer: vec!["a"],
   3523                 set: "a".to_owned(),
   3524                 skipped_sets_counter: 0,
   3525                 skip_empty_set: false
   3526             }
   3527         );
   3528         assert_eq!(power_set.next_set(), Some(""));
   3529         assert_eq!(
   3530             power_set,
   3531             PowerSet {
   3532                 feats: feats.0.as_slice(),
   3533                 has_remaining: false,
   3534                 check_overlap: false,
   3535                 idx: 0,
   3536                 buffer: Vec::new(),
   3537                 set: String::new(),
   3538                 skipped_sets_counter: 0,
   3539                 skip_empty_set: false
   3540             }
   3541         );
   3542         assert_eq!(power_set.next_set(), None);
   3543         assert_eq!(
   3544             power_set,
   3545             PowerSet {
   3546                 feats: feats.0.as_slice(),
   3547                 has_remaining: false,
   3548                 check_overlap: false,
   3549                 idx: 0,
   3550                 buffer: Vec::new(),
   3551                 set: String::new(),
   3552                 skipped_sets_counter: 0,
   3553                 skip_empty_set: false
   3554             }
   3555         );
   3556         assert_eq!(power_set.len(), NonZeroUsizePlus1::new(16));
   3557         feats.0 = vec![("a".to_owned(), Vec::new())];
   3558         assert_eq!(
   3559             PowerSet::new(&feats, true),
   3560             Ok(Some(PowerSet {
   3561                 feats: feats.0.as_slice(),
   3562                 has_remaining: true,
   3563                 check_overlap: false,
   3564                 idx: 1,
   3565                 buffer: vec!["a"],
   3566                 set: String::new(),
   3567                 skipped_sets_counter: 0,
   3568                 skip_empty_set: true
   3569             }))
   3570         );
   3571         power_set = PowerSet::new(&feats, true)
   3572             .unwrap_or_else(|_e| {
   3573                 unreachable!("not possible since we just verified PowerSet::new returned Ok")
   3574             })
   3575             .unwrap_or_else(|| {
   3576                 unreachable!("not possible since we just verified PowerSet::new returned Ok(Some)")
   3577             });
   3578         assert_eq!(power_set.len(), NonZeroUsizePlus1::new(1));
   3579         assert_eq!(power_set.next_set(), Some("a"));
   3580         assert_eq!(
   3581             power_set,
   3582             PowerSet {
   3583                 feats: feats.0.as_slice(),
   3584                 has_remaining: false,
   3585                 check_overlap: false,
   3586                 idx: 0,
   3587                 buffer: vec!["a"],
   3588                 set: "a".to_owned(),
   3589                 skipped_sets_counter: 0,
   3590                 skip_empty_set: true,
   3591             }
   3592         );
   3593         assert_eq!(power_set.next_set(), None);
   3594         assert_eq!(
   3595             power_set,
   3596             PowerSet {
   3597                 feats: feats.0.as_slice(),
   3598                 has_remaining: false,
   3599                 check_overlap: false,
   3600                 idx: 0,
   3601                 buffer: vec!["a"],
   3602                 set: "a".to_owned(),
   3603                 skipped_sets_counter: 0,
   3604                 skip_empty_set: true,
   3605             }
   3606         );
   3607         assert_eq!(power_set.next_set(), None);
   3608         assert_eq!(
   3609             power_set,
   3610             PowerSet {
   3611                 feats: feats.0.as_slice(),
   3612                 has_remaining: false,
   3613                 check_overlap: false,
   3614                 idx: 0,
   3615                 buffer: vec!["a"],
   3616                 set: "a".to_owned(),
   3617                 skipped_sets_counter: 0,
   3618                 skip_empty_set: true,
   3619             }
   3620         );
   3621         power_set.reset();
   3622         assert_eq!(
   3623             power_set,
   3624             PowerSet {
   3625                 feats: feats.0.as_slice(),
   3626                 has_remaining: true,
   3627                 check_overlap: false,
   3628                 idx: 1,
   3629                 buffer: vec!["a"],
   3630                 set: "a".to_owned(),
   3631                 skipped_sets_counter: 0,
   3632                 skip_empty_set: true,
   3633             }
   3634         );
   3635         assert_eq!(power_set.next_set(), Some("a"));
   3636         assert_eq!(power_set.next_set(), None);
   3637         assert_eq!(
   3638             power_set,
   3639             PowerSet {
   3640                 feats: feats.0.as_slice(),
   3641                 has_remaining: false,
   3642                 check_overlap: false,
   3643                 idx: 0,
   3644                 buffer: vec!["a"],
   3645                 set: "a".to_owned(),
   3646                 skipped_sets_counter: 0,
   3647                 skip_empty_set: true,
   3648             }
   3649         );
   3650         assert_eq!(power_set.len(), NonZeroUsizePlus1::new(1));
   3651     }
   3652 }