xidl-parser 0.44.0

A IDL codegen.
Documentation
use super::{Annotation, AnnotationParams};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
pub enum SerializeKind {
    Cdr,
    PlainCdr,
    PlCdr,
    PlainCdr2,
    DelimitedCdr,
    PlCdr2,
}

#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
pub enum SerializeVersion {
    Xcdr1,
    Xcdr2,
}

#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy)]
pub struct SerializeConfig {
    pub explicit_kind: Option<SerializeKind>,
    pub version: Option<SerializeVersion>,
}

#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
pub enum Extensibility {
    Final,
    Appendable,
    Mutable,
    None,
}

impl SerializeConfig {
    pub fn apply_pragma(&mut self, pragma: super::Pragma) {
        match pragma {
            super::Pragma::XidlcSerialize(kind) => self.explicit_kind = Some(kind),
            super::Pragma::XidlcVersion(version) => {
                self.version = Some(version);
                self.explicit_kind = None;
            }
            super::Pragma::XidlcPackage(_)
            | super::Pragma::XidlcOpenApiVersion(_)
            | super::Pragma::XidlcOpenApiService { .. } => {}
        }
    }

    pub fn resolve(&self, extensibility: Extensibility) -> SerializeKind {
        if let Some(kind) = self.explicit_kind {
            return kind;
        }

        match self.version {
            None => SerializeKind::Cdr,
            Some(SerializeVersion::Xcdr1) => match extensibility {
                Extensibility::Mutable => SerializeKind::PlCdr,
                Extensibility::Final | Extensibility::Appendable => SerializeKind::Cdr,
                Extensibility::None => SerializeKind::PlainCdr,
            },
            Some(SerializeVersion::Xcdr2) => match extensibility {
                Extensibility::Final => SerializeKind::PlainCdr2,
                Extensibility::Appendable => SerializeKind::DelimitedCdr,
                Extensibility::Mutable => SerializeKind::PlCdr2,
                Extensibility::None => SerializeKind::Cdr,
            },
        }
    }

    pub fn resolve_for_annotations(&self, annotations: &[Annotation]) -> SerializeKind {
        self.resolve(extensibility_from_annotations(annotations))
    }
}

pub fn extensibility_from_annotations(annotations: &[Annotation]) -> Extensibility {
    let mut final_flag = false;
    let mut appendable = false;
    let mut mutable = false;

    for annotation in annotations {
        if let Annotation::Builtin { name, .. } = annotation {
            if name.eq_ignore_ascii_case("final") {
                final_flag = true;
            } else if name.eq_ignore_ascii_case("appendable") {
                appendable = true;
            } else if name.eq_ignore_ascii_case("mutable") {
                mutable = true;
            }
        }

        if let Annotation::Builtin { name, params } = annotation {
            if name.eq_ignore_ascii_case("extensibility") {
                if let Some(AnnotationParams::Raw(raw)) = params {
                    let value = raw.trim().trim_matches('"');
                    if value.eq_ignore_ascii_case("final") {
                        final_flag = true;
                    } else if value.eq_ignore_ascii_case("appendable") {
                        appendable = true;
                    } else if value.eq_ignore_ascii_case("mutable") {
                        mutable = true;
                    }
                }
            }
        }
    }

    if mutable {
        Extensibility::Mutable
    } else if appendable {
        Extensibility::Appendable
    } else if final_flag {
        Extensibility::Final
    } else {
        Extensibility::None
    }
}

#[cfg(test)]
mod tests;