pub mod ada;
pub mod ada83;
pub mod c;
pub mod cpp;
pub mod csharp;
pub mod d;
pub mod decode;
pub mod elixir;
pub mod encode;
pub mod fsharp;
pub mod go;
pub mod interface_cpp;
pub mod interface_java;
pub mod interface_rust;
pub mod interface_typescript;
pub mod java;
pub mod julia;
pub mod kotlin;
pub mod lua;
pub mod nim;
pub mod node;
pub mod ocaml;
pub mod python;
pub mod swift;
pub mod type_pair_cpp;
pub mod type_pair_java;
pub mod type_pair_rust;
pub mod typescript;
pub mod zig;
use crate::encode::EncodeError;
use zerodds_ast::{Ast, MemberNode, TypeNode};
use zerodds_ast_core::Id;
use zerodds_lang_cst::common::{Doc, Literal};
pub(crate) fn resolves_to_enumeration(ast: &Ast, id: Id<TypeNode>) -> bool {
const MAX_ALIAS_DEPTH: usize = 64;
let mut current = id;
for _ in 0..MAX_ALIAS_DEPTH {
match ast.type_(current).map(|node| &node.kind) {
Ok(zerodds_ast::TypeKind::Enumeration { .. }) => return true,
Ok(zerodds_ast::TypeKind::Alias { aliased }) => match aliased.resolved() {
Some(target) => current = target,
None => return false,
},
_ => return false,
}
}
false
}
pub(crate) fn reached_externally<T: CodecTarget>(
ast: &Ast,
member: &zerodds_ast::MemberNode,
) -> bool {
if T::holds_a_cycle_externally() {
if T::optionals_are_pointers()
&& member.facets.is_optional()
&& !crate::adapter::annotated_external(member)
{
return false;
}
crate::adapter::held_externally(ast, member)
} else {
crate::adapter::annotated_external(member)
}
}
pub(crate) fn behind_pointer<T: CodecTarget>(
ast: &Ast,
enclosing: Id<TypeNode>,
member_type: Id<TypeNode>,
external: bool,
optional: bool,
) -> bool {
zerodds_ast_layout::member_held_inline_closes_a_cycle(ast, enclosing, member_type)
|| (((external && T::externals_are_pointers())
|| (optional && !external && T::optionals_are_pointers()))
&& !T::value_is_pointer(ast, member_type))
}
pub(crate) struct Reach {
pub field: String,
pub holder: Id<TypeNode>,
}
pub(crate) fn inheritance_depth(
ast: &Ast,
aggregate: Id<TypeNode>,
member: zerodds_ast_core::NodeId,
) -> usize {
let mut current = aggregate;
for depth in 0..64 {
let declares = ast
.members_of(current)
.iter()
.any(|handle| ast.member(*handle).is_ok_and(|node| node.node_id == member));
if declares {
return depth;
}
match ast.type_(current).map(|node| &node.kind) {
Ok(zerodds_ast::TypeKind::Structure {
base: Some(base), ..
}) => match base.resolved() {
Some(next) => current = next,
None => return 0,
},
_ => return 0,
}
}
0
}
pub(crate) fn base_at(ast: &Ast, aggregate: Id<TypeNode>, depth: usize) -> Id<TypeNode> {
let mut current = aggregate;
for _ in 0..depth {
match ast.type_(current).map(|node| &node.kind) {
Ok(zerodds_ast::TypeKind::Structure {
base: Some(base), ..
}) => match base.resolved() {
Some(next) => current = next,
None => return aggregate,
},
_ => return aggregate,
}
}
current
}
#[must_use]
pub fn inherited_member_names(
ast: &Ast,
aggregate: Id<TypeNode>,
) -> Option<(Id<TypeNode>, Vec<String>)> {
let base = crate::adapter::c::struct_base(ast, aggregate)?;
let names = ast
.all_members_of(base)
.iter()
.filter_map(|id| ast.member(*id).ok())
.map(|member| member.name.clone())
.collect();
Some((base, names))
}
#[must_use]
pub fn member_field<T: CodecTarget>(
ast: &Ast,
aggregate: Id<TypeNode>,
member: zerodds_ast_core::NodeId,
name: &str,
) -> String {
reach::<T>(ast, aggregate, member, name).field
}
pub(crate) fn reach<T: CodecTarget>(
ast: &Ast,
aggregate: Id<TypeNode>,
member: zerodds_ast_core::NodeId,
name: &str,
) -> Reach {
let escaped = T::escape(name);
let depth = inheritance_depth(ast, aggregate, member);
match (depth, T::inherited_path(depth)) {
(0, _) | (_, None) => Reach {
field: escaped,
holder: aggregate,
},
(depth, Some(path)) => Reach {
field: format!("{path}{escaped}"),
holder: base_at(ast, aggregate, depth),
},
}
}
#[must_use]
pub fn default_enumerator_name(ast: &Ast, id: Id<TypeNode>) -> Option<String> {
let mut first = None;
for enumerator in ast.enumerators_of(id) {
let Ok(node) = ast.enumerator(*enumerator) else {
continue;
};
if node
.facets
.xtypes
.as_ref()
.is_some_and(|x| x.is_default_literal)
{
return Some(node.name.clone());
}
if first.is_none() {
first = Some(node.name.clone());
}
}
first
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Scalar {
Index,
Size,
Bool,
Char,
Int8,
Int16,
Int32,
Int64,
UInt8,
UInt16,
UInt32,
UInt64,
Float,
Double,
LongDouble,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Handle {
DHeader,
EmHeader,
Pid,
TryConstruct,
ReaderMark,
PidRead,
EmHeaderRead,
}
pub struct Routine<T: CodecTarget + ?Sized> {
pub doc: Doc,
pub name: String,
pub sample: T::Type,
pub held: Handoff,
pub writing: bool,
pub tolerate_unused: bool,
pub extra: Vec<(T::Type, String)>,
pub body: Option<T::Block>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Constant {
WcharWidth2,
WcharWidth4,
WcharFixed,
WcharGiopLengthPrefixed,
WstringUnitsStream,
WstringUnitsBigEndianAlways,
WstringUnitsByteOrderMark,
WstringUnitsHostUnswapped,
WstringSpecification,
WstringCharacterCount,
WstringCharacterCountTerminated,
WstringSpecificationWideUnits,
WstringRosTypeSupport,
WstringOctetsTerminated2,
WstringOctetsTerminated4,
WstringCharactersTerminated2,
FixedDeclared,
FixedValuePrecision,
FixedValueStringDigits,
ParameterMember,
ParameterOptional,
TryConstructDiscard,
TryConstructTrim,
TryConstructUseDefault,
StatusOk,
StatusDiscarded,
StatusImpossibleLength,
StatusOutOfRange,
StatusTruncated,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Handoff {
Array,
Value,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BitPatternSource {
Int {
octets: u8,
},
Bool,
Float32,
Float64,
}
pub trait CodecTarget {
type Expr: Clone;
type Stmt: Clone;
type Block: Clone;
type Type: Clone;
type Decl;
fn scalar(kind: Scalar) -> Self::Type;
fn named(name: &str) -> Self::Type;
fn handle(kind: Handle) -> Self::Type;
fn constant(which: Constant) -> Self::Expr;
fn code_point(value: Self::Expr, narrow: bool) -> Self::Expr;
fn unsigned_less(octets: u8, left: Self::Expr, right: Self::Expr) -> Self::Expr {
let _ = octets;
Self::binary("<", left, right)
}
fn bool_less(left: Self::Expr, right: Self::Expr) -> Self::Expr {
Self::binary("<", left, right)
}
fn bit_pattern(source: BitPatternSource, value: Self::Expr) -> Self::Expr {
match source {
BitPatternSource::Int { octets } => Self::runtime_static(
"bit_pattern_int",
vec![value, Self::int(i128::from(octets))],
),
BitPatternSource::Bool => Self::runtime_static("bit_pattern_bool", vec![value]),
BitPatternSource::Float32 => Self::runtime_static("bit_pattern_f32", vec![value]),
BitPatternSource::Float64 => Self::runtime_static("bit_pattern_f64", vec![value]),
}
}
fn unsigned_holder(bits: u16) -> Self::Type;
fn runtime_static(method: &str, args: Vec<Self::Expr>) -> Self::Expr;
fn nothing() -> Self::Type;
fn name(text: &str) -> Self::Expr;
fn int(value: i128) -> Self::Expr;
fn literal(value: Literal) -> Self::Expr;
fn call(callee: &str, args: Vec<Self::Expr>) -> Self::Expr;
fn runtime(receiver: &str, method: &str, args: Vec<Self::Expr>) -> Self::Expr;
fn carries_hdds_axes() -> bool {
false
}
fn member(base: &str, field: &str) -> Self::Expr;
fn whole(base: &str) -> Self::Expr;
fn wide_int(value: i128) -> Self::Expr;
fn unsigned_int(value: i128) -> Self::Expr {
Self::literal(Literal::Int(format!("{value}u")))
}
fn wide_unsigned(value: u64) -> Self::Expr {
Self::literal(Literal::Int(format!("UINT64_C({value})")))
}
fn wide_signed(value: i128) -> Self::Expr {
Self::literal(Literal::Int(format!("INT64_C({value})")))
}
fn field_of(value: Self::Expr, field: &str) -> Self::Expr;
fn index(value: Self::Expr, at: Self::Expr) -> Self::Expr;
fn count_of(base: &str, fixed: Option<u64>) -> Self::Expr;
fn binary(op: &'static str, lhs: Self::Expr, rhs: Self::Expr) -> Self::Expr;
fn unary(op: &'static str, value: Self::Expr) -> Self::Expr;
fn paren(value: Self::Expr) -> Self::Expr;
fn cast(type_: Self::Type, value: Self::Expr) -> Self::Expr;
fn handoff(value: Self::Expr, form: Handoff) -> Self::Expr;
fn bulk_octets_write(base: &str, count: Self::Expr) -> Option<Self::Stmt> {
let _ = (base, count);
None
}
fn bulk_octets_read(base: &str, count: Self::Expr) -> Option<Self::Stmt> {
let _ = (base, count);
None
}
fn declare(type_: Self::Type, name: &str, value: Option<Self::Expr>) -> Self::Stmt;
fn perform(value: Self::Expr) -> Self::Stmt;
fn give_back(value: Option<Self::Expr>) -> Self::Stmt;
fn when(condition: Self::Expr, then: Self::Block, otherwise: Option<Self::Block>)
-> Self::Stmt;
fn count_up(counter: &str, bound: Self::Expr, body: Self::Block) -> Self::Stmt;
fn until(condition: Self::Expr, body: Self::Block) -> Self::Stmt;
fn leave() -> Self::Stmt;
fn note(doc: Doc) -> Self::Stmt;
fn drop_value(value: Self::Expr) -> Self::Stmt {
Self::perform(Self::cast(Self::nothing(), value))
}
fn mark_used(name: &str) -> Vec<Self::Stmt> {
vec![Self::perform(Self::cast(Self::nothing(), Self::name(name)))]
}
fn read_call(
callee: &str,
place: Self::Expr,
form: Handoff,
behaviour: Self::Expr,
) -> Self::Stmt {
Self::perform(Self::call(
callee,
vec![Self::name("r"), Self::handoff(place, form), behaviour],
))
}
fn read_forward(callee: &str) -> Self::Stmt {
Self::perform(Self::call(
callee,
vec![Self::name("r"), Self::name("v"), Self::name("zd_tc")],
))
}
fn make_room(
base: &str,
element: Self::Type,
count: Self::Expr,
assigned_whole: bool,
fill: Vec<Self::Stmt>,
) -> Vec<Self::Stmt>;
fn make_room_of(
_ast: &Ast,
_element_id: Id<TypeNode>,
base: &str,
element: Self::Type,
count: Self::Expr,
assigned_whole: bool,
fill: Vec<Self::Stmt>,
) -> Vec<Self::Stmt> {
Self::make_room(base, element, count, assigned_whole, fill)
}
fn store(place: Self::Expr, type_: Self::Type, value: Self::Expr) -> Self::Stmt {
let _ = type_;
Self::perform(Self::binary("=", place, value))
}
fn storage(type_: Self::Type, name: &str) -> Self::Stmt {
Self::declare(type_, name, None)
}
fn header_field(value: Self::Expr, field: &str) -> Self::Expr {
Self::field_of(value, field)
}
fn sequence_element(
base: &str,
index: Self::Expr,
element: Self::Type,
) -> (Vec<Self::Stmt>, Self::Expr, Vec<Self::Stmt>);
fn keep_first(base: &str, count: Self::Expr) -> Vec<Self::Stmt>;
fn present(base: &str, field: &str) -> Self::Expr;
fn set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt>;
fn clear_union_cases(base: &str, fields: &[String]) -> Vec<Self::Stmt> {
let _ = (base, fields);
Vec::new()
}
fn open_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt> {
let _ = (base, lengths);
Vec::new()
}
fn close_array(base: &str, lengths: &[i128]) -> Vec<Self::Stmt> {
let _ = (base, lengths);
Vec::new()
}
fn case_member(base: &str, field: &str) -> Self::Expr;
fn discriminant(base: &str) -> Self::Expr {
Self::member(base, "_d")
}
fn enumerator_ordinal(ast: &Ast, id: Id<TypeNode>, value: Self::Expr) -> Self::Expr {
let _ = (ast, id);
value
}
fn case_label(ast: &Ast, discriminator: Id<TypeNode>, value: i128) -> Self::Expr {
Self::cast(Self::value_type(ast, discriminator), Self::wide_int(value))
}
fn entry_half(entry: Self::Expr, key: bool) -> Self::Expr;
fn behind_indirection(ast: &Ast, id: Id<TypeNode>, place: Self::Expr) -> Self::Expr {
let _ = (ast, id);
place
}
fn make_indirection(
ast: &Ast,
id: Id<TypeNode>,
place: Self::Expr,
) -> (Vec<Self::Stmt>, Self::Expr) {
let _ = (ast, id);
(Vec::new(), place)
}
fn optional_destination(base: &str, field: &str) -> (Vec<Self::Stmt>, Self::Expr);
fn optional_value(ast: &Ast, id: Id<TypeNode>, base: &str, field: &str) -> Self::Expr;
fn holds_by_reference(
ast: &Ast,
aggregate: Id<TypeNode>,
member_type: Id<TypeNode>,
optional: bool,
external: bool,
) -> bool {
let _ = (ast, aggregate, member_type, optional, external);
false
}
fn reference_present(base: &str, field: &str) -> Self::Expr {
Self::present(base, field)
}
fn reference_value(ast: &Ast, id: Id<TypeNode>, base: &str, field: &str) -> Self::Expr {
Self::optional_value(ast, id, base, field)
}
fn reference_destination(
ast: &Ast,
id: Id<TypeNode>,
base: &str,
field: &str,
) -> (Vec<Self::Stmt>, Self::Expr) {
let _ = (ast, id);
Self::optional_destination(base, field)
}
fn reference_absent(base: &str, field: &str) -> Vec<Self::Stmt> {
Self::set_present(base, field, false)
}
fn holds_a_cycle_externally() -> bool {
false
}
fn externals_are_pointers() -> bool {
false
}
fn optionals_are_pointers() -> bool {
false
}
fn value_is_pointer(ast: &Ast, id: Id<TypeNode>) -> bool {
crate::adapter::c::value_is_pointer(ast, id)
}
fn refuse_unset_external(present: Self::Expr) -> Vec<Self::Stmt> {
let _ = present;
Vec::new()
}
fn external_value(
ast: &Ast,
id: Id<TypeNode>,
base: &str,
field: &str,
optional: bool,
) -> Self::Expr {
if optional {
return Self::optional_value(ast, id, base, field);
}
Self::member(base, field)
}
fn external_destination(
base: &str,
field: &str,
optional: bool,
) -> (Vec<Self::Stmt>, Self::Expr) {
if optional {
return Self::optional_destination(base, field);
}
(Vec::new(), Self::member(base, field))
}
fn external_present(base: &str, field: &str) -> Self::Expr {
Self::present(base, field)
}
fn external_set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt> {
Self::set_present(base, field, present)
}
fn external_case_value(ast: &Ast, id: Id<TypeNode>, base: &str, field: &str) -> Self::Expr {
let _ = (ast, id);
Self::case_member(base, field)
}
fn external_case_destination(base: &str, field: &str) -> (Vec<Self::Stmt>, Self::Expr) {
(Vec::new(), Self::case_member(base, field))
}
fn elements(base: &str) -> Self::Expr;
fn materialised(value: Self::Expr) -> Option<Self::Expr>;
fn absent() -> Self::Expr;
fn block(statements: Vec<Self::Stmt>) -> Self::Block;
fn into_statements(block: Self::Block) -> Vec<Self::Stmt>;
fn published_name(name: String) -> String {
name
}
fn routine(spec: Routine<Self>) -> Option<Self::Decl>;
fn initialized_reader(_spec: Routine<Self>, _initializer: Self::Stmt) -> Option<Self::Decl> {
None
}
fn value_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type;
fn bitmask_value(ast: &Ast, id: Id<TypeNode>, value: Self::Expr) -> Self::Expr {
Self::cast(Self::value_type(ast, id), value)
}
fn default_into(
ast: &Ast,
id: Id<TypeNode>,
place: Self::Expr,
) -> Result<Self::Stmt, EncodeError>;
fn member_default(
ast: &Ast,
node: &MemberNode,
type_: Id<TypeNode>,
place: Self::Expr,
) -> Result<Vec<Self::Stmt>, EncodeError>;
fn escape(name: &str) -> String;
fn inherited_path(depth: usize) -> Option<String> {
let _ = depth;
None
}
fn map_entry_name(ast: &Ast, id: Id<TypeNode>) -> String;
fn map_entry_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type {
Self::named(&Self::map_entry_name(ast, id))
}
fn enumerator_constant(ast: &Ast, id: Id<TypeNode>, enumerator: &str) -> Self::Expr {
Self::name(&format!(
"{}{}",
Self::module_prefix(ast, id),
Self::escape(enumerator)
))
}
fn module_prefix(ast: &Ast, id: Id<TypeNode>) -> String;
fn type_name(ast: &Ast, id: Id<TypeNode>) -> String;
}