Codex Handbook
execpolicy-legacy/src/arg_matcher.rs 118 lines
#![allow(clippy::needless_lifetimes)]use crate::arg_type::ArgType;use crate::starlark::values::ValueLike;use allocative::Allocative;use derive_more::derive::Display;use starlark::any::ProvidesStaticType;use starlark::values::AllocValue;use starlark::values::Heap;use starlark::values::NoSerialize;use starlark::values::StarlarkValue;use starlark::values::UnpackValue;use starlark::values::Value;use starlark::values::starlark_value;use starlark::values::string::StarlarkStr;/// Patterns that lists of arguments should be compared against.#[derive(Clone, Debug, Display, Eq, PartialEq, NoSerialize, ProvidesStaticType, Allocative)]#[display("{}", self)]pub enum ArgMatcher {    /// Literal string value.    Literal(String),    /// We cannot say what type of value this should match, but it is *not* a file path.    OpaqueNonFile,    /// Required readable file.    ReadableFile,    /// Required writeable file.    WriteableFile,    /// Non-empty list of readable files.    ReadableFiles,    /// Non-empty list of readable files, or empty list, implying readable cwd.    ReadableFilesOrCwd,    /// Positive integer, like one that is required for `head -n`.    PositiveInteger,    /// Bespoke matcher for safe sed commands.    SedCommand,    /// Matches an arbitrary number of arguments without attributing any    /// particular meaning to them. Caller is responsible for interpreting them.    UnverifiedVarargs,}impl ArgMatcher {    pub fn cardinality(&self) -> ArgMatcherCardinality {        match self {            ArgMatcher::Literal(_)            | ArgMatcher::OpaqueNonFile            | ArgMatcher::ReadableFile            | ArgMatcher::WriteableFile            | ArgMatcher::PositiveInteger            | ArgMatcher::SedCommand => ArgMatcherCardinality::One,            ArgMatcher::ReadableFiles => ArgMatcherCardinality::AtLeastOne,            ArgMatcher::ReadableFilesOrCwd | ArgMatcher::UnverifiedVarargs => {                ArgMatcherCardinality::ZeroOrMore            }        }    }    pub fn arg_type(&self) -> ArgType {        match self {            ArgMatcher::Literal(value) => ArgType::Literal(value.clone()),            ArgMatcher::OpaqueNonFile => ArgType::OpaqueNonFile,            ArgMatcher::ReadableFile => ArgType::ReadableFile,            ArgMatcher::WriteableFile => ArgType::WriteableFile,            ArgMatcher::ReadableFiles => ArgType::ReadableFile,            ArgMatcher::ReadableFilesOrCwd => ArgType::ReadableFile,            ArgMatcher::PositiveInteger => ArgType::PositiveInteger,            ArgMatcher::SedCommand => ArgType::SedCommand,            ArgMatcher::UnverifiedVarargs => ArgType::Unknown,        }    }}pub enum ArgMatcherCardinality {    One,    AtLeastOne,    ZeroOrMore,}impl ArgMatcherCardinality {    pub fn is_exact(&self) -> Option<usize> {        match self {            ArgMatcherCardinality::One => Some(1),            ArgMatcherCardinality::AtLeastOne => None,            ArgMatcherCardinality::ZeroOrMore => None,        }    }}impl<'v> AllocValue<'v> for ArgMatcher {    fn alloc_value(self, heap: Heap<'v>) -> Value<'v> {        heap.alloc_simple(self)    }}#[starlark_value(type = "ArgMatcher")]impl<'v> StarlarkValue<'v> for ArgMatcher {    type Canonical = ArgMatcher;}impl<'v> UnpackValue<'v> for ArgMatcher {    type Error = starlark::Error;    fn unpack_value_impl(value: Value<'v>) -> starlark::Result<Option<Self>> {        if let Some(str) = value.downcast_ref::<StarlarkStr>() {            Ok(Some(ArgMatcher::Literal(str.as_str().to_string())))        } else {            Ok(value.downcast_ref::<ArgMatcher>().cloned())        }    }}