{# ei-scanner jinja template, for `` #}
#![allow(
unknown_lints,
unused_imports,
unused_parens,
clippy::useless_conversion,
clippy::double_parens,
clippy::match_single_binding,
clippy::unused_unit,
clippy::empty_docs,
clippy::doc_lazy_continuation,
// Explicitly set to warn
clippy::doc_markdown,
clippy::must_use_candidate,
clippy::semicolon_if_nothing_returned,
clippy::used_underscore_binding,
clippy::match_same_arms,
clippy::str_to_string,
missing_docs,
)]
// GENERATED FILE
{# TODO More complete handling of nullable types? #}
use crate::wire;
{%- macro interface_type(interface) -%}
super::{{interface.plainname}}::{{interface.plainname|camel}}
{% endmacro -%}
{%- macro arg_type(arg, owned, generic) -%}
{%- if arg.enum != None -%} {{ arg.enum.name|camel }}
{%- elif arg.protocol_type == 'string' and owned and arg.allow_null -%} Option<String>
{%- elif arg.protocol_type == 'string' and owned -%} String
{%- elif arg.protocol_type == 'string' and arg.allow_null -%} Option<&str>
{%- elif arg.protocol_type == 'string' -%} &str
{%- elif arg.protocol_type == 'int32' -%} i32
{%- elif arg.protocol_type == 'uint32' -%} u32
{%- elif arg.protocol_type == 'int64' -%} i64
{%- elif arg.protocol_type == 'uint64' -%} u64
{%- elif arg.protocol_type == 'object' and owned -%} {{interface_type(arg.interface)}}
{%- elif arg.protocol_type == 'object' -%} &{{interface_type(arg.interface)}}
{%- elif arg.protocol_type == 'new_id' and arg.interface -%} {{interface_type(arg.interface)}}
{%- elif arg.protocol_type == 'new_id' and arg.interface_arg and generic -%} {{arg.interface_arg.name|camel}}
{%- elif arg.protocol_type == 'new_id' and arg.interface_arg -%} crate::Object
{%- elif arg.protocol_type == 'float' -%} f32
{%- elif arg.protocol_type == 'fd' and owned -%} std::os::unix::io::OwnedFd
{%- elif arg.protocol_type == 'fd' -%} std::os::unix::io::BorrowedFd
{%- else -%} unhandled_arg_type_{{arg.protocol_type}}
{%- endif -%}
{% endmacro -%}
{#- Required because combining /// and /** */ comments doesn't work with indentation -#}
{%- macro doc_commentize(text) %}
{#- lstrip is required because there's an empty line before each description -#}
{%- for line in text.lstrip().splitlines() %}
/// {{line}}
{% endfor %}
{% endmacro -%}
{%- set message_enum_from = {'server': 'Event', 'client': 'Request'} -%}
{%- set current_actor = 'server' if extra.eis else 'client' -%}
{%- set opposite_actor = 'client' if extra.eis else 'server' -%}
{%- set module = 'crate::eis' if extra.eis else 'crate::ei' -%}
{%- set incoming_enum = message_enum_from[opposite_actor] -%}
{%- macro message_doc_comment(message, sender_actor) %}
/// {{message.description.summary|capitalize}}.
///
{% if message.context_type %}
/// **Note:** This {{ message_enum_from[sender_actor] | lower }} may only be used in a {{message.context_type}} [context type]({{module}}::handshake::ContextType).
///
{% endif %}
{% if message.is_destructor %}
/// **Note:** This {{ message_enum_from[sender_actor] | lower }} is a destructor.
///
{% endif %}
{{- doc_commentize(message.description.text|ei_escape_names) -}}
{% endmacro -%}
{% for interface in interfaces %}
/// {{interface.description.summary|capitalize}}.
///
/// {{current_actor|capitalize}}-side protocol definition module for interface `{{interface.protocol_name}}`.
///
/** {{interface.description.text|ei_escape_names}} */
pub mod {{interface.plainname}} {
use crate::wire;
/// {{interface.description.summary|capitalize}}.
///
/// {{current_actor|capitalize}}-side interface proxy for interface `{{interface.protocol_name}}`.
///
/** {{interface.description.text|ei_escape_names}} */
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct {{interface.plainname|camel}}(pub(crate) crate::Object);
impl {{interface.plainname|camel}} {
/// Returns the negotiated version of the interface.
pub fn version(&self) -> u32 {
self.0.version()
}
/// Returns `true` if the backend has this object.
pub fn is_alive(&self) -> bool {
self.0.is_alive()
}
}
impl crate::private::Sealed for {{interface.plainname|camel}} {}
impl wire::Interface for {{interface.plainname|camel}} {
const NAME: &'static str = "{{interface.protocol_name}}";
const VERSION: u32 = {{interface.version}};
{% if extra.eis %}
const CLIENT_SIDE: bool = false;
{% else %}
const CLIENT_SIDE: bool = true;
{% endif %}
fn new_unchecked(object: crate::Object) -> Self {
Self(object)
}
fn as_object(&self) -> &crate::Object {
&self.0
}
fn as_arg(&self) -> wire::Arg<'_> {
self.0.as_arg()
}
}
impl {{module}}::Interface for {{interface.plainname|camel}} {}
impl {{interface.plainname|camel}} {
{% for outgoing in interface.outgoing %}
{{ message_doc_comment(outgoing, current_actor) -}}
{% if outgoing.arguments %}
/// # Parameters
///
{% for arg in outgoing.arguments %}
{% if arg.protocol_type != 'new_id' and not arg.interface_arg_for %}
{% if arg.summary %}
/// - `{{arg.name}}`: {{arg.summary|capitalize}}.
{% else %}
/// - `{{arg.name}}`
{% endif %}
{% endif %}
{% endfor %}
///
{% endif %}
pub fn {{outgoing.name}}<
{%- for arg in outgoing.arguments %}
{% if arg.interface_arg_for %}
{{arg.name|camel}}: {{module}}::Interface
{% endif %}
{% endfor -%}
>(
&self,
{%- for arg in outgoing.arguments %}
{% if arg.protocol_type != 'new_id' and not arg.interface_arg_for %}
{{arg.name}}: {{arg_type(arg, false, false)}},
{% endif %}
{% endfor -%}
) -> (
{%- for arg in outgoing.arguments %}
{% if arg.protocol_type == 'new_id' %}
{{arg_type(arg, true, true)}}
{% endif %}
{% endfor -%}
) {
{%- for arg in outgoing.arguments %}
{% if arg.protocol_type == 'new_id' and arg.interface_arg %}
let {{arg.name}} = self.0.backend_weak().new_object({{arg.interface_arg.name|camel}}::NAME.to_string(), {{arg.version_arg.name}});
{% elif arg.protocol_type == 'new_id' %}
let {{arg.name}} = self.0.backend_weak().new_object("{{arg.interface.protocol_name}}".to_string(), {{arg.version_arg.name}});
{% endif -%}
{% endfor -%}
let args = &[
{%- for arg in outgoing.arguments %}
{% if arg.interface_arg_for %}
wire::Arg::{{arg.protocol_type|camel}}(Some({{arg.name|camel}}::NAME)),
{% else %}
wire::Arg::{{arg.protocol_type|camel}}({{arg.name}}
{% if arg.protocol_type == 'new_id' %}
.id()
{% endif %}
.into()),
{% endif %}
{% endfor -%}
];
self.0.request({{outgoing.opcode}}, args);
{% if outgoing.is_destructor %}
self.0.backend_weak().remove_id(self.0.id());
{% endif %}
(
{%- for arg in outgoing.arguments %}
{% if arg.protocol_type == 'new_id' %}
{% if arg.interface %}
{{arg_type(arg, true, false)}}({{arg.name}})
{% elif arg.interface_arg %}
{{arg.name}}.downcast_unchecked()
{% else -%}
unreachable
{% endif -%}
{% endif -%}
{% endfor -%}
)
}
{% endfor %}
}
{% for enum in interface.enums %}
pub use crate::eiproto_enum::{{interface.plainname}}::{{enum.camel_name}};
{% endfor %}
/// All {{incoming_enum|lower}}s of interface `{{interface.protocol_name}}`.
///
/// {{incoming_enum}}s are messages that come from {{opposite_actor}}s.
#[non_exhaustive]
#[derive(Debug)]
pub enum {{incoming_enum}} {
{% for incoming in interface.incoming %}
{{ message_doc_comment(incoming, opposite_actor) -}}
{{ incoming.name|camel }}
{% if incoming.arguments %}
{ {% for arg in incoming.arguments %}
{% if not (arg.version_arg_for or arg.interface_arg_for) %}
/// {{arg.summary|capitalize}}.
{{arg.name}}: {{arg_type(arg, true, false)}},
{% endif %}
{% endfor %} }
{% endif %},
{% endfor %}
}
impl {{incoming_enum}} {
pub(super) fn op_name(operand: u32) -> Option<&'static str> {
match operand {
{% for incoming in interface.incoming %}
{{incoming.opcode}} => Some("{{incoming.name}}"),
{% endfor %}
_ => None
}
}
pub(super) fn parse(operand: u32, _bytes: &mut wire::ByteStream) -> Result<Self, wire::ParseError> {
match operand {
{% for incoming in interface.incoming %}
{{incoming.opcode}} => {
{% for arg in incoming.arguments %}
let {{arg.name}} = _bytes.read_arg()?;
{% endfor %}
Ok(Self::{{ incoming.name|camel }}
{% if incoming.arguments %} {
{% for arg in incoming.arguments %}
{% if arg.version_arg_for or arg.interface_arg_for %}
{% elif arg.protocol_type == 'new_id' and arg.interface_arg %}
{{arg.name}}: _bytes.backend().new_peer_object({{arg.name}}, {{arg.interface_arg.name}}, {{arg.version_arg.name}})?,
{% elif arg.protocol_type == 'new_id' %}
{{arg.name}}: _bytes.backend().new_peer_interface({{arg.name}}, {{arg.version_arg.name}})?,
{% else %}
{{arg.name}},
{% endif %}
{% endfor %} }
{% endif %} )
}
{% endfor %}
opcode => Err(wire::ParseError::InvalidOpcode("{{interface.plainname}}", opcode)),
}
}
#[allow(unused_imports, unused_mut, unused_variables, unreachable_code, unreachable_patterns)]
pub(super) fn args(&self) -> Vec<wire::Arg<'_>> {
use crate::{wire::OwnedArg, Interface};
let mut args = Vec::new();
match self {
{% for incoming in interface.incoming %}
{% if incoming.arguments %}
Self::{{ incoming.name|camel }} {
{% for arg in incoming.arguments %}
{% if not (arg.version_arg_for or arg.interface_arg_for) %}
{{arg.name}},
{% endif %}
{% endfor %}
} => {
{% for arg in incoming.arguments %}
{% if not (arg.version_arg_for or arg.interface_arg_for) %}
args.push({{arg.name}}.as_arg());
{% endif %}
{% endfor %}
}
{% else %}
Self::{{ incoming.name|camel }} => {}
{% endif %}
{% endfor %}
_ => unreachable!()
}
args
}
}
}
pub use {{interface.plainname}}::{{interface.plainname|camel}};
{% endfor %}
/// All {{incoming_enum|lower}}s of all interfaces.
///
/// {{incoming_enum}}s are messages that come from {{opposite_actor}}s.
#[non_exhaustive]
#[derive(Debug)]
pub enum {{incoming_enum}} {
{% for interface in interfaces %}
{{interface.plainname|camel}}({{interface.plainname}}::{{interface.plainname|camel}}, {{interface.plainname}}::{{incoming_enum}}),
{% endfor %}
}
impl {{incoming_enum}} {
pub(crate) fn op_name(interface: &str, operand: u32) -> Option<&'static str> {
match interface {
{% for interface in interfaces %}
"{{interface.protocol_name}}" =>
{{interface.plainname}}::{{incoming_enum}}::op_name(operand),
{% endfor %}
_ => None,
}
}
pub(crate) fn parse(object: crate::Object, operand: u32, bytes: &mut wire::ByteStream) -> Result<Self, wire::ParseError> {
match object.interface() {
{% for interface in interfaces %}
"{{interface.protocol_name}}" => Ok(Self::{{interface.plainname|camel}}(
object.downcast_unchecked(),
{{interface.plainname}}::{{incoming_enum}}::parse(operand, bytes)?)
),
{% endfor %}
intr => Err(wire::ParseError::InvalidInterface(intr.to_owned())),
}
}
}
impl wire::MessageEnum for {{incoming_enum}} {
fn args(&self) -> Vec<wire::Arg<'_>> {
match self {
{% for interface in interfaces %}
Self::{{interface.plainname|camel}}(_, x) => x.args(),
{% endfor %}
}
}
}