use crate::types::{
*,
flags::*,
generation::*,
parsing::*,
};
use cookie_factory::{GenError, do_gen, gen_call, gen_cond};
use nom::combinator::{flat_map, map, map_opt};
pub mod metadata {
use super::*;
pub const NAME: &str = "{{protocol.name}}";
pub const MAJOR_VERSION: ShortShortUInt = {{protocol.major_version}};
pub const MINOR_VERSION: ShortShortUInt = {{protocol.minor_version}};
pub const REVISION: ShortShortUInt = {{protocol.revision}};
pub const PORT: LongUInt = {{protocol.port}};
pub const COPYRIGHT: &str = r#"{{protocol.copyright}}"#;
}
pub mod constants {
use super::*;
{{#each protocol.constants as |constant| ~}}
pub const {{sanitize_name constant.name}}: {{constant.type}} = {{constant.value}};
{{/each ~}}
}
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPError {
Soft(AMQPSoftError),
Hard(AMQPHardError),
}
impl AMQPError {
pub fn get_id(&self) -> ShortUInt {
match *self {
AMQPError::Soft(ref s) => s.get_id(),
AMQPError::Hard(ref h) => h.get_id(),
}
}
pub fn from_id(id: ShortUInt) -> Option<AMQPError> {
AMQPSoftError::from_id(id).map(AMQPError::Soft).or_else(|| AMQPHardError::from_id(id).map(AMQPError::Hard))
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPSoftError {
{{#each protocol.soft_errors as |constant| ~}}
{{camel constant.name}},
{{/each ~}}
}
impl AMQPSoftError {
pub fn get_id(&self) -> ShortUInt {
match *self {
{{#each protocol.soft_errors as |constant| ~}}
AMQPSoftError::{{camel constant.name}} => {{constant.value}},
{{/each ~}}
}
}
pub fn from_id(id: ShortUInt) -> Option<AMQPSoftError> {
match id {
{{#each protocol.soft_errors as |constant| ~}}
{{constant.value}} => Some(AMQPSoftError::{{camel constant.name}}),
{{/each ~}}
_ => None,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPHardError {
{{#each protocol.hard_errors as |constant| ~}}
{{camel constant.name}},
{{/each ~}}
}
impl AMQPHardError {
pub fn get_id(&self) -> ShortUInt {
match *self {
{{#each protocol.hard_errors as |constant| ~}}
AMQPHardError::{{camel constant.name}} => {{constant.value}},
{{/each ~}}
}
}
pub fn from_id(id: ShortUInt) -> Option<AMQPHardError> {
match id {
{{#each protocol.hard_errors as |constant| ~}}
{{constant.value}} => Some(AMQPHardError::{{camel constant.name}}),
{{/each ~}}
_ => None,
}
}
}
{{#each protocol.classes as |class| ~}}
use self::{{snake class.name}}::parse_{{snake class.name}};
{{/each ~}}
pub fn parse_class(i: &[u8]) -> ParserResult<'_, AMQPClass> {
map_opt(flat_map(parse_id, |id| move |i| match id {
{{#each protocol.classes as |class| ~}}
{{class.id}} => map(map(parse_{{snake class.name false}}, AMQPClass::{{camel class.name}}), Some)(i),
{{/each ~}}
_ => Ok((i, None)),
}), std::convert::identity)(i)
}
pub fn gen_class<'a>(input: (&'a mut [u8], usize), class: &AMQPClass) -> Result<(&'a mut [u8], usize), GenError> {
match *class {
{{#each protocol.classes as |class| ~}}
AMQPClass::{{camel class.name}}(ref {{snake class.name}}) => {{snake class.name}}::gen_{{snake class.name false}}(input, {{snake class.name}}),
{{/each ~}}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPClass {
{{#each protocol.classes as |class| ~}}
{{camel class.name}}({{snake class.name}}::AMQPMethod),
{{/each ~}}
}
impl AMQPClass {
pub fn get_amqp_class_id(&self) -> u16 {
match self {
{{#each protocol.classes as |class| ~}}
AMQPClass::{{camel class.name}}(_) => {{class.id}},
{{/each ~}}
}
}
}
{{#each protocol.classes as |class|}}
pub mod {{snake class.name}} {
use super::*;
pub fn parse_{{snake class.name false}}(i: &[u8]) -> ParserResult<'_, {{snake class.name}}::AMQPMethod> {
map_opt(flat_map(parse_id, |id| move |i| match id {
{{#each class.methods as |method| ~}}
{{method.id}} => map(map(parse_{{snake method.name false}}, AMQPMethod::{{camel method.name}}), Some)(i),
{{/each ~}}
_ => Ok((i, None)),
}), std::convert::identity)(i)
}
pub fn gen_{{snake class.name false}}<'a>(input: (&'a mut [u8], usize), method: &AMQPMethod) -> Result<(&'a mut [u8], usize), GenError> {
match *method {
{{#each class.methods as |method| ~}}
AMQPMethod::{{camel method.name}}(ref {{snake method.name}}) => {
do_gen!(input,
gen_id({{class.id}}) >>
gen_{{snake method.name false}}({{snake method.name}})
)
},
{{/each ~}}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPMethod {
{{#each class.methods as |method| ~}}
{{camel method.name}}({{camel method.name}}),
{{/each ~}}
}
{{#each class.methods as |method|}}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct {{camel method.name}} {
{{#each_argument method.arguments as |argument| ~}}
{{#if argument_is_value ~}}
{{#unless argument.force_default ~}}
pub {{snake argument.name}}: {{argument.type}},
{{/unless ~}}
{{else}}
{{#each_flag argument as |flag| ~}}
{{#unless flag.force_default ~}}
pub {{snake flag.name}}: Boolean,
{{/unless ~}}
{{/each_flag ~}}
{{/if ~}}
{{/each_argument ~}}
}
impl {{camel method.name}} {
pub fn get_amqp_class_id(&self) -> u16 {
{{class.id}}
}
pub fn get_amqp_method_id(&self) -> u16 {
{{method.id}}
}
}
pub fn parse_{{snake method.name false}}(i: &[u8]) -> ParserResult<'_, {{camel method.name}}> {
{{#each_argument method.arguments as |argument| ~}}
{{#if argument_is_value ~}}
let (i, {{#if argument.force_default ~}}_{{else}}{{snake argument.name}}{{/if ~}}) = parse_{{snake_type argument.type}}(i)?;
{{else}}
let (i, {{#if method.metadata.empty_flags ~}}_{{else}}flags{{/if ~}}) = parse_flags(i, &[
{{#each_flag argument as |flag| ~}}
"{{flag.name}}",
{{/each_flag ~}}
])?;
{{/if ~}}
{{/each_argument ~}}
Ok((i, {{camel method.name}} {
{{#each_argument method.arguments as |argument| ~}}
{{#if argument_is_value ~}}
{{#unless argument.force_default ~}}
{{snake argument.name}},
{{/unless ~}}
{{else}}
{{#each_flag argument as |flag| ~}}
{{#unless flag.force_default ~}}
{{snake flag.name}}: flags.get_flag("{{snake flag.name}}").unwrap_or({{flag.default_value}}),
{{/unless ~}}
{{/each_flag ~}}
{{/if ~}}
{{/each_argument ~}}
}))
}
pub fn gen_{{snake method.name false}}<'a>(input: (&'a mut [u8], usize), {{#if method.arguments ~}}{{#if method.metadata.is_empty ~}}_{{/if ~}}method{{else}}_{{/if ~}}: &{{camel method.name}}) -> Result<(&'a mut [u8],usize), GenError> {
{{#each_argument method.arguments as |argument| ~}}
{{#unless argument_is_value ~}}
let mut flags = AMQPFlags::default();
{{#each_flag argument as |flag| ~}}
flags.add_flag("{{snake flag.name}}".to_string(), {{#if flag.force_default ~}}{{flag.default_value}}{{else}}method.{{snake flag.name}}{{/if ~}});
{{/each_flag ~}}
{{/unless ~}}
{{/each_argument ~}}
do_gen!(input,
gen_id({{method.id}})
{{#each_argument method.arguments as |argument| ~}}
{{#if argument_is_value ~}}
>> gen_{{snake_type argument.type}}({{#if argument.force_default ~}}{{amqp_value argument.default_value}}{{else}}{{#if (pass_by_ref argument.type) ~}}&{{/if ~}}method.{{snake argument.name}}{{/if ~}})
{{else}}
>> gen_flags(&flags)
{{/if ~}}
{{/each_argument ~}}
)
}
{{/each ~}}
{{#if class.properties ~}}
#[derive(Clone, Debug, PartialEq)]
pub struct AMQPProperties {
{{#each class.properties as |property| ~}}
{{snake property.name}}: Option<{{property.type}}>,
{{/each ~}}
}
impl Default for AMQPProperties {
fn default() -> AMQPProperties {
AMQPProperties {
{{#each class.properties as |property| ~}}
{{snake property.name}}: None,
{{/each ~}}
}
}
}
impl AMQPProperties {
{{#each class.properties as |property| ~}}
pub fn with_{{snake property.name false}}(mut self, value: {{property.type}}) -> AMQPProperties {
self.{{snake property.name}} = Some(value);
self
}
{{/each ~}}
{{#each class.properties as |property| ~}}
pub fn {{snake property.name}}(&self) -> &Option<{{property.type}}> {
&self.{{snake property.name}}
}
{{/each ~}}
#[allow(clippy::identity_op)]
pub fn bitmask(&self) -> ShortUInt {
{{#each class.properties as |property| ~}}
(if self.{{snake property.name}}.is_some() { 1 << (15 - {{@index}}) } else { 0 }) {{#unless @last ~}} + {{/unless ~}}
{{/each ~}}
}
}
#[allow(clippy::identity_op)]
pub fn parse_properties(i: &[u8]) -> ParserResult<'_, AMQPProperties> {
let (i, flags) = parse_short_uint(i)?;
{{#each class.properties as |property| ~}}
let (i, {{snake property.name}}) = if flags & (1 << (15 - {{@index}})) != 0 { map(parse_{{snake_type property.type}}, Some)(i)? } else { (i, None) };
{{/each ~}}
Ok((i, AMQPProperties {
{{#each class.properties as |property| ~}}
{{snake property.name}},
{{/each ~}}
}))
}
#[clippy::cyclomatic_complexity = "32"]
pub fn gen_properties<'a>(input:(&'a mut [u8],usize), props: &AMQPProperties) -> Result<(&'a mut [u8],usize),GenError> {
do_gen!(input,
gen_short_uint(props.bitmask())
{{#each class.properties as |property| ~}}
>> gen_cond!(props.{{snake property.name}}.is_some(), gen_call!(gen_{{snake_type property.type}}, {{#if (pass_by_ref property.type) ~}}&{{/if ~}}props.{{snake property.name}}{{#if (pass_by_ref property.type) ~}}.as_ref(){{/if ~}}.unwrap()))
{{/each ~}}
)
}
{{/if ~}}
}
{{/each ~}}