use super::*;
use crate::adapter::interface::{EnhancedMemberType, EnhancedOperation, EnhancedStruct};
pub(super) fn holder_type(
ast: &Ast,
here: zerodds_ast_core::Id<zerodds_ast::ModuleNode>,
module: zerodds_ast_core::Id<zerodds_ast::ModuleNode>,
name: &str,
) -> Result<java::Type, BindingError> {
if here == module {
return Ok(local(name));
}
let mut segments: Vec<String> = vec![OUTER.to_string()];
segments.extend(
interface::module_chain(ast, module)?
.into_iter()
.map(|(_, module)| java::escape_keyword(&module)),
);
segments.push(name.to_string());
let borrowed: Vec<&str> = segments.iter().map(String::as_str).collect();
Ok(java::Type::named(Path::new(&borrowed)))
}
fn annotations_doc(structure: &EnhancedStruct, what: &str) -> Doc {
let mut marks = Vec::new();
if structure.choice {
marks.push("@Choice");
}
if structure.autoid {
marks.push("@Autoid");
}
if structure.empty {
marks.push("@Empty");
}
if structure.mutable {
marks.push("@Extensibility(MUTABLE_EXTENSIBILITY)");
}
Doc::lines(&[what, "", &marks.join(" ")])
}
fn choice_field(
ast: &Ast,
here: zerodds_ast_core::Id<zerodds_ast::ModuleNode>,
owner: Option<&EnhancedOperation>,
member: &crate::adapter::interface::EnhancedMember,
) -> Result<java::Member, BindingError> {
let type_ = match &member.type_ {
EnhancedMemberType::Struct(name) => holder_type(
ast,
here,
owner.map_or(here, |operation| operation.module),
name,
)?,
EnhancedMemberType::Exception(raise) => exception_type(ast, raise)?,
EnhancedMemberType::RemoteException => qualified(RPC, "RemoteExceptionCode"),
EnhancedMemberType::Dummy | EnhancedMemberType::Idl(_) => {
return Err(BindingError::Codec(format!(
"member `{}` is not a member of a choice structure",
member.name
)));
}
};
Ok(field(type_, &java::escape_keyword(&member.name)))
}
pub(super) fn members(ast: &Ast, service: &Service) -> Result<Vec<java::Member>, BindingError> {
let module = service.module;
let name = java::escape_keyword(&service.name);
let model = interface::enhanced_service(ast, service, service.mapping.empty_style())?;
let mut out = Vec::new();
for operation in model
.operations
.iter()
.filter(|operation| operation.module == module && operation.interface == service.name)
{
let op = &operation.operation;
out.push(holder(
&operation.in_struct.name,
if operation.in_struct.members.is_empty() {
Vec::new()
} else {
request_fields(ast, service, op)?
},
annotations_doc(
&operation.in_struct,
"The `in` and `inout` parameters of one call. DDS-RPC 1.0 §7.5.1.2.2.",
),
));
out.push(holder(
&operation.out_struct.name,
if operation.out_struct.members.is_empty() {
Vec::new()
} else {
reply_fields(ast, service, op)?
},
annotations_doc(
&operation.out_struct,
"The return value and the `out` and `inout` parameters of one call. DDS-RPC \
1.0 §7.5.1.2.3 rule 1.",
),
));
let mut fields = Vec::new();
for member in &operation.result_struct.members {
fields.push(choice_field(ast, module, None, member)?);
}
out.push(holder(
&operation.result_struct.name,
fields,
annotations_doc(
&operation.result_struct,
"The outcome of one operation: the result or an exception it raises. DDS-RPC \
1.0 §7.5.1.2.3.",
),
));
}
for (structure, doc) in [
(
&model.request,
"The request topic type: one member per operation, the inherited ones included. \
DDS-RPC 1.0 §7.5.1.2.4.",
),
(
&model.reply,
"The reply topic type: one member per operation, and `remoteEx`. DDS-RPC 1.0 \
§7.5.1.2.5.",
),
] {
let mut fields = Vec::new();
for member in &structure.members {
let owner = model
.operations
.iter()
.find(|operation| operation.operation.name == member.name);
fields.push(choice_field(ast, module, owner, member)?);
}
out.push(holder(
&structure.name,
fields,
annotations_doc(structure, doc),
));
}
let scope: Vec<String> = interface::module_chain(ast, module)?
.into_iter()
.map(|(_, module)| module)
.collect();
let descriptions =
crate::emit::interface_rust::type_information::service_type_objects(ast, service, &model)
.ok()
.and_then(|objects| {
crate::emit::interface_rust::type_information::java_descriptions(&objects)
});
out.push(support_class_with(
service,
&name,
&scope,
true,
descriptions.as_ref(),
));
out.push(sync_interface(ast, service, &name)?);
out.push(async_interface(ast, service, &name)?);
if service.is_remote() {
out.push(endpoint(
&format!("{name}Requester"),
"Requester",
&name,
"The service's `Requester`, over its two topic types. DDS-RPC 1.0 §7.11.2.2.1.",
));
out.push(endpoint(
&format!("{name}Replier"),
"Replier",
&name,
"The service's `Replier`, over its two topic types. DDS-RPC 1.0 §7.11.2.2.1.",
));
out.extend(super::enhanced_calls::members(ast, service, &name, &model)?);
out.push(client_interface(&name));
out.push(service_interface(&name));
}
Ok(out)
}