xidl-parser 0.105.0

A IDL codegen.
Documentation
use std::error::Error;
use std::fmt;

/// Diagnostics raised while analysing or projecting API versioning annotations.
#[derive(Debug, Clone)]
pub enum VersioningError {
    /// `@version` applied to a declaration that is not an enum.
    VersionOutsideEnum { target: String },
    /// Two enums in one specification carry the `@version` marker.
    DuplicateVersionEnum { first: String, second: String },
    /// The `@version` enum declares no members.
    EmptyVersionEnum { ident: String },
    /// Two version members resolve to the same display value.
    DuplicateVersionValue {
        value: String,
        first: String,
        second: String,
    },
    /// A lifecycle annotation appears without a `@version` enum in the specification.
    MissingVersionEnum { annotation: String, decl: String },
    /// A lifecycle annotation argument is not an `Enum::member` reference.
    MalformedVersionReference { annotation: String, decl: String },
    /// A raw version marker failed to lower into a valid typed annotation.
    MalformedVersionMarker { decl: String },
    /// A version parameter violates its argument or wire-location contract.
    MalformedVersionParameter { decl: String, reason: String },
    /// A version timeline declares more than one version marker or parameter.
    DuplicateVersionParameter { decl: String },
    /// A lifecycle annotation references a version the timeline does not declare.
    UnknownVersionReference {
        annotation: String,
        decl: String,
        reference: String,
        declared: String,
    },
    /// A rejected versioning annotation has no supported contract semantics.
    UnsupportedVersionAnnotation { name: String, decl: String },
    /// A lifecycle annotation applied to a declaration that cannot carry it.
    UnsupportedVersionTarget { annotation: String, target: String },
    /// The `@version` enum itself carries a lifecycle annotation.
    VersionedVersionEnum { annotation: String, ident: String },
    /// The same lifecycle annotation appears twice on one declaration.
    DuplicateLifecycleAnnotation { annotation: String, decl: String },
    /// `@added` and `@removed` leave an empty availability interval.
    EmptyAvailability {
        decl: String,
        added: String,
        removed: String,
    },
    /// A child's annotated interval reaches outside its parent's interval.
    ChildOutsideParent {
        decl: String,
        parent: String,
        version: String,
    },
    /// A surviving declaration references a declaration the projection drops.
    DanglingReference {
        decl: String,
        reference: String,
        version: String,
    },
    /// A version selection was requested for a specification without a `@version` enum.
    UnversionedSpecification { selection: String },
    /// A requested version is not declared by the timeline.
    UnknownSelectedVersion { selection: String, declared: String },
    /// A requested version matches both a member ident and another member's value.
    AmbiguousSelectedVersion {
        selection: String,
        first: String,
        second: String,
    },
    /// The projector received a version position outside the timeline.
    UnknownVersion { index: usize },
    /// Both version selection properties were set.
    ConflictingSelection { first: String, second: String },
    /// The requested version selection is empty.
    EmptySelection,
    /// `api_version` received `*`, which only `api_versions` accepts.
    SelectionRequiresOneVersion { selection: String },
    /// The version layout property holds an unknown value.
    UnknownVersionLayout { value: String },
    /// Two declarations available in the same version resolve to the same
    /// effective wire name inside one container.
    DuplicateWireName {
        container: String,
        wire: String,
        first: String,
        second: String,
        version: Option<String>,
    },
}

impl fmt::Display for VersioningError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::VersionOutsideEnum { target } => write!(
                f,
                "xidl versioning: @version is only valid on an enum declaration, not on {target}"
            ),
            Self::DuplicateVersionEnum { first, second } => write!(
                f,
                "xidl versioning: multiple @version enums declared: {first} and {second}"
            ),
            Self::EmptyVersionEnum { ident } => write!(
                f,
                "xidl versioning: the @version enum {ident} declares no versions"
            ),
            Self::DuplicateVersionValue {
                value,
                first,
                second,
            } => write!(
                f,
                "xidl versioning: versions {first} and {second} both resolve to value \"{value}\""
            ),
            Self::MissingVersionEnum { annotation, decl } => write!(
                f,
                "xidl versioning: {annotation} on {decl} requires a @version enum in the specification"
            ),
            Self::MalformedVersionReference { annotation, decl } => write!(
                f,
                "xidl versioning: {annotation} on {decl} requires a version reference like Versions::v1"
            ),
            Self::MalformedVersionMarker { decl } => {
                write!(
                    f,
                    "xidl versioning: @version on {decl} must be bare or declare in=... and name=..."
                )
            }
            Self::MalformedVersionParameter { decl, reason } => {
                write!(f, "xidl versioning: @version on {decl}: {reason}")
            }
            Self::DuplicateVersionParameter { decl } => write!(
                f,
                "xidl versioning: @version on {decl} is declared more than once"
            ),
            Self::UnknownVersionReference {
                annotation,
                decl,
                reference,
                declared,
            } => write!(
                f,
                "xidl versioning: {annotation} on {decl} references {reference}, which is not declared ({declared})"
            ),
            Self::UnsupportedVersionAnnotation { name, decl } => {
                write!(f, "xidl versioning: {name} on {decl} is not supported; ")?;
                if name.eq_ignore_ascii_case("@renamedFrom") {
                    write!(
                        f,
                        "use @rename(\"wire_name\") for the serialized name; use @added/@removed declarations for changes between versions"
                    )
                } else {
                    write!(
                        f,
                        "use @version, @added and @removed for version availability"
                    )
                }
            }
            Self::UnsupportedVersionTarget { annotation, target } => write!(
                f,
                "xidl versioning: {annotation} cannot be applied to {target}"
            ),
            Self::VersionedVersionEnum { annotation, ident } => write!(
                f,
                "xidl versioning: the @version enum {ident} cannot carry {annotation}"
            ),
            Self::DuplicateLifecycleAnnotation { annotation, decl } => {
                write!(f, "xidl versioning: duplicate {annotation} on {decl}")
            }
            Self::EmptyAvailability {
                decl,
                added,
                removed,
            } => write!(
                f,
                "xidl versioning: {decl} is unavailable in every version (@added({added}) and @removed({removed}) leave an empty interval)"
            ),
            Self::ChildOutsideParent {
                decl,
                parent,
                version,
            } => write!(
                f,
                "xidl versioning: {decl} is annotated at {version}, outside the availability of {parent}"
            ),
            Self::DanglingReference {
                decl,
                reference,
                version,
            } => write!(
                f,
                "xidl versioning: {decl} references {reference}, which does not exist in {version}"
            ),
            Self::UnversionedSpecification { selection } => write!(
                f,
                "xidl versioning: version selection {selection} requires a @version enum in the specification"
            ),
            Self::UnknownSelectedVersion {
                selection,
                declared,
            } => write!(
                f,
                "xidl versioning: version {selection} is not declared ({declared})"
            ),
            Self::AmbiguousSelectedVersion {
                selection,
                first,
                second,
            } => write!(
                f,
                "xidl versioning: version {selection} matches both {first} and {second}; use the member ident"
            ),
            Self::UnknownVersion { index } => write!(
                f,
                "xidl versioning: version position {index} is not part of the declared timeline"
            ),
            Self::ConflictingSelection { first, second } => write!(
                f,
                "xidl versioning: {first} and {second} cannot both be set"
            ),
            Self::EmptySelection => write!(
                f,
                "xidl versioning: the version selection is empty; name at least one version or use \"*\""
            ),
            Self::SelectionRequiresOneVersion { selection } => write!(
                f,
                "xidl versioning: {selection} selects one version; use the plural version property with \"*\" for every version"
            ),
            Self::UnknownVersionLayout { value } => write!(
                f,
                "xidl versioning: unknown version layout \"{value}\"; expected \"merged\" or \"per_version\""
            ),
            Self::DuplicateWireName {
                container,
                wire,
                first,
                second,
                version,
            } => match version {
                Some(version) => write!(
                    f,
                    "xidl versioning: {first} and {second} both serialize as \"{wire}\" in version {version}; effective wire names must stay unique inside {container} for every version"
                ),
                None => write!(
                    f,
                    "xidl versioning: {first} and {second} both serialize as \"{wire}\"; effective wire names must stay unique inside {container}"
                ),
            },
        }
    }
}

impl Error for VersioningError {}