mavspec_rust_gen 0.6.7

Rust code generation module for MAVSpec.
Documentation
use mavinspect::protocol::{Dialect, Enum, EnumEntry, MavType};
use serde::Serialize;

use crate::conventions::split_description;
use crate::generator::GeneratorParams;
use crate::patches::patched_enum_entry_name_stripped;
use crate::specs::dialects::dialect::DialectModuleSpec;
use crate::specs::dialects::dialect::MsrvSpec;
use crate::specs::Spec;

/// Input for enums root module template.
pub(crate) struct EnumsRootModuleSpec<'a> {
    dialect_canonical_name: &'a str,
    enums: &'a [&'a Enum],
    params: &'a GeneratorParams,
    msrv: Option<&'a MsrvSpec<'a>>,
}

impl<'a> Spec for EnumsRootModuleSpec<'a> {
    fn params(&self) -> &GeneratorParams {
        self.params
    }
}

impl<'a> EnumsRootModuleSpec<'a> {
    pub(crate) fn new(dialect_spec: &'a DialectModuleSpec, params: &'a GeneratorParams) -> Self {
        Self {
            dialect_canonical_name: dialect_spec.canonical_name(),
            enums: dialect_spec.enums(),
            params,
            msrv: dialect_spec.msrv(),
        }
    }

    pub(crate) fn dialect_canonical_name(&self) -> &str {
        self.dialect_canonical_name
    }

    pub(crate) fn enums(&self) -> &[&Enum] {
        self.enums
    }

    pub(crate) fn msrv_name(&self) -> Option<&'a str> {
        self.msrv.as_ref().map(|msrv| msrv.name)
    }
}

/// Input for MAVLink enum implementation module template.
///
/// Basically, this is a utility wrapper around `MAVInspect` [`Enum`].
#[derive(Debug, Clone, Serialize)]
pub(crate) struct EnumImplModuleSpec<'a> {
    name: &'a str,
    dialect: &'a Dialect,
    description: Vec<String>,
    inferred_type: MavType,
    entries: Vec<EnumEntrySpec<'a>>,
    is_bitmask: bool,
    params: &'a GeneratorParams,
    msrv: Option<&'a MsrvSpec<'a>>,
}

impl<'a> Spec for EnumImplModuleSpec<'a> {
    fn params(&self) -> &GeneratorParams {
        self.params
    }
}

impl<'a> EnumImplModuleSpec<'a> {
    pub(crate) fn new(mav_enum: &'a Enum, dialect_spec: &'a DialectModuleSpec) -> Self {
        let mut entries: Vec<EnumEntrySpec> = mav_enum
            .entries()
            .iter()
            .map(EnumEntrySpec::from_enum_entry)
            .collect();
        entries.sort_by_key(|entry| entry.value);

        EnumImplModuleSpec {
            name: mav_enum.name(),
            dialect: dialect_spec.dialect(),
            description: split_description(mav_enum.description()),
            inferred_type: mav_enum.inferred_type(),
            entries,
            is_bitmask: mav_enum.bitmask(),
            params: dialect_spec.params(),
            msrv: dialect_spec.msrv(),
        }
    }

    pub(crate) fn name(&self) -> &str {
        self.name
    }

    pub(crate) fn is_bitmask(&self) -> bool {
        self.is_bitmask
    }

    pub(crate) fn description(&self) -> &[String] {
        self.description.as_slice()
    }

    pub(crate) fn entries(&self) -> &[EnumEntrySpec] {
        self.entries.as_slice()
    }

    pub(crate) fn inferred_type(&self) -> &MavType {
        &self.inferred_type
    }

    pub(crate) fn dialect(&self) -> &Dialect {
        self.dialect
    }

    pub(crate) fn msrv(&self) -> Option<&'a MsrvSpec> {
        self.msrv
    }

    pub(crate) fn msrv_name(&self) -> Option<&'a str> {
        self.msrv.map(|msrv| msrv.name)
    }
}

/// Enum entry representation for template.
///
/// Basically, this is a utility wrapper around `MAVInspect` [`EnumEntry`].
#[derive(Debug, Clone, Serialize)]
pub(crate) struct EnumEntrySpec<'a> {
    value: u32,
    name: &'a str,
    name_stripped: String,
    description: Vec<String>,
}

impl<'a> EnumEntrySpec<'a> {
    pub(crate) fn from_enum_entry(entry: &'a EnumEntry) -> Self {
        Self {
            value: entry.value(),
            name: entry.name(),
            name_stripped: patched_enum_entry_name_stripped(entry),
            description: split_description(entry.description()),
        }
    }

    pub(crate) fn value(&self) -> u32 {
        self.value
    }

    pub(crate) fn value_expr(&self) -> syn::Expr {
        syn::parse_str(format!("{}", self.value()).as_str()).unwrap()
    }

    pub(crate) fn name(&self) -> &str {
        self.name
    }

    pub(crate) fn name_stripped(&self) -> &str {
        self.name_stripped.as_str()
    }

    pub(crate) fn description(&self) -> &[String] {
        self.description.as_slice()
    }
}

pub(crate) struct EnumInheritedModuleSpec<'a> {
    mav_enum: &'a Enum,
    dialect_canonical_name: &'a str,
    original_dialect_name: &'a str,
    params: &'a GeneratorParams,
    msrv: Option<&'a MsrvSpec<'a>>,
}

impl<'a> EnumInheritedModuleSpec<'a> {
    pub(crate) fn new(
        mav_enum: &'a Enum,
        dialect_spec: &'a DialectModuleSpec,
        original_dialect_name: &'a str,
        params: &'a GeneratorParams,
    ) -> Self {
        Self {
            mav_enum,
            dialect_canonical_name: dialect_spec.canonical_name(),
            original_dialect_name,
            params,
            msrv: dialect_spec.msrv(),
        }
    }

    pub(crate) fn name(&self) -> &str {
        self.mav_enum.name()
    }

    pub(crate) fn dialect_canonical_name(&self) -> &str {
        self.dialect_canonical_name
    }

    pub(crate) fn original_dialect_name(&self) -> &str {
        self.original_dialect_name
    }

    pub(crate) fn msrv_name(&self) -> Option<&'a str> {
        self.msrv.map(|msrv| msrv.name)
    }
}

impl<'a> Spec for EnumInheritedModuleSpec<'a> {
    fn params(&self) -> &GeneratorParams {
        self.params
    }
}