Skip to main content

Ast

Struct Ast 

Source
pub struct Ast { /* private fields */ }
Expand description

The common AST.

Nodes live in per-kind generational arenas; handles are the fast access path, NodeId the stable one. Spec §1, §3.

Implementations§

Source§

impl Ast

Source

pub fn begin(&mut self) -> AstTransaction<'_>

Open a transaction.

Mutations made through it are published as one changeset when it commits, and reversed entirely if it does not. Spec §5.1.

Source

pub fn remove(&mut self, any: AnyId) -> Result<(), AstError>

Remove a node, cascading to the parts it owns and breaking every reference that pointed at it.

A dangling resolved handle must not survive a delete; incoming references become Broken(NotFound) so the loss is visible rather than silent. Spec §5.2.

§Errors

AstError::NotFound when the identity is not in the model, AstError::Invariant when the resulting model breaks a structural rule, in which case nothing was removed.

Source§

impl Ast

Source

pub fn new() -> Self

A model containing the root module and the built-in declarations.

Built-in identities come from IdSpace::BUILTIN and are allocated in a fixed order, so they are identical in every model and snapshots from different processes compare. Spec §3.6, §9.

Source

pub const fn root_module(&self) -> Id<ModuleNode>

The anonymous global scope.

Source

pub const fn builtin_module(&self) -> Id<ModuleNode>

The module holding the built-in declarations.

Source

pub fn builtin_annotation(&self, name: &str) -> Option<Id<AnnotationDefNode>>

A built-in annotation by name, without the @.

Source

pub fn resolve_node_id(&self, node: NodeId) -> Option<AnyId>

Map a stable identity back to its handle and kind.

Source

pub fn observers_mut(&mut self) -> &mut ObserverRegistry

The observer registry, for registering change consumers.

Source

pub fn node_count(&self) -> usize

Total number of live nodes across every arena.

Source

pub const fn commit_sequence(&self) -> u64

The sequence number of the last committed changeset.

Zero on a fresh model; every commit increments it, so a consumer can tell whether it has seen every changeset. Spec §5.2.

Source

pub fn allocate_synthetic_id(&mut self) -> Result<NodeId, AstError>

Allocate an identity in IdSpace::SYNTHETIC.

For nodes a tool fabricates that correspond to nothing in any source — an implicit wrapper, a generated helper type. Keeping them in their own namespace means a diff between a parsed model and a fabricated one never confuses the two. Spec §1.2.

§Errors

AstError::Core when the synthetic counter is exhausted.

Source

pub fn take_commit_error(&mut self) -> Option<AstError>

The error of the most recent auto-committed mutation, if it was rejected.

A mutation made outside an explicit transaction validates on the spot; when it fails, the model is rolled back and the failure is recorded here rather than lost. Taking it clears it.

Source

pub fn module(&self, id: Id<ModuleNode>) -> Result<&ModuleNode, AstError>

Borrow a module.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn ensure_module( &mut self, parent: Id<ModuleNode>, name: &str, ) -> Result<Id<ModuleNode>, AstError>

Create the named child module, or return the existing one.

This is what makes reopening a module across translation units converge on one node. Spec §3.1.

§Errors

AstError::Core if the parent handle is stale or identity space is exhausted.

Source

pub fn modules(&self) -> impl Iterator<Item = (Id<ModuleNode>, &ModuleNode)>

Iterate every module in the model, in arena order.

Source

pub fn module_by_path(&self, path: &ScopedName) -> Option<Id<ModuleNode>>

Look a module up by its path from the root.

Source

pub fn type_(&self, id: Id<TypeNode>) -> Result<&TypeNode, AstError>

Borrow a type.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_type( &mut self, module: Id<ModuleNode>, name: &str, kind: TypeKind, ) -> Result<Id<TypeNode>, AstError>

Declare a type in a module.

§Errors

AstError::Core if the module handle is stale or identity space is exhausted.

Source

pub fn add_forward_type( &mut self, module: Id<ModuleNode>, name: &str, kind: TypeKind, ) -> Result<Id<TypeNode>, AstError>

Declare a type whose body has not arrived yet.

Not a separate node kind: completing it later is an update, so handles taken now stay valid. Spec §3.2.

§Errors

As Ast::add_type.

Source

pub fn complete_type( &mut self, id: Id<TypeNode>, kind: TypeKind, ) -> Result<(), AstError>

Give a forward-declared type its body.

An update of the existing node, not a second one: every reference taken while only the forward declaration existed stays valid, which is why forwardness is a state rather than a kind. Spec §3.2.

§Errors

AstError::AlreadyComplete if the type already has a body — two definitions of one name are a duplicate, not a completion. AstError::Core on a stale handle.

Source

pub fn types(&self) -> impl Iterator<Item = (Id<TypeNode>, &TypeNode)>

Iterate every type in the model, in arena order.

Source

pub fn member(&self, id: Id<MemberNode>) -> Result<&MemberNode, AstError>

Borrow a member.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn members(&self) -> impl Iterator<Item = (Id<MemberNode>, &MemberNode)>

Iterate every member in the model, in arena order.

Source

pub fn add_member( &mut self, aggregate: Id<TypeNode>, spec: MemberSpec, ) -> Result<Id<MemberNode>, AstError>

Add a member to a struct or valuetype.

§Errors

AstError::WrongKind if the target is not an aggregate that holds members, AstError::Core on a stale handle.

Source

pub fn add_member_at( &mut self, aggregate: Id<TypeNode>, spec: MemberSpec, index: usize, ) -> Result<Id<MemberNode>, AstError>

Self::add_member at a position among the aggregate’s members.

DDS-XTypes 1.3 §7.5.2.7.6: “any value greater than the current largest index value in the type shall be taken to indicate that the new member will become the last member”; a member at index and those after it “shall be shifted up by a single index value”.

§Errors

As Self::add_member.

Source

pub fn add_case_at( &mut self, union: Id<TypeNode>, labels: Vec<CaseLabel>, spec: MemberSpec, index: usize, ) -> Result<Id<CaseNode>, AstError>

Self::add_case at a position among the union’s cases, with the rule of Self::add_member_at.

§Errors

As Self::add_case.

Source

pub fn add_exception_member( &mut self, exception: Id<ExceptionNode>, spec: MemberSpec, ) -> Result<Id<MemberNode>, AstError>

Add a member to an exception.

§Errors

AstError::Core on a stale handle.

Source

pub fn case(&self, id: Id<CaseNode>) -> Result<&CaseNode, AstError>

Borrow a union case.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn cases(&self) -> impl Iterator<Item = (Id<CaseNode>, &CaseNode)>

Iterate every cases node in the model, in arena order.

Source

pub fn add_case( &mut self, union: Id<TypeNode>, labels: Vec<CaseLabel>, spec: MemberSpec, ) -> Result<Id<CaseNode>, AstError>

Add a case to a union.

A case carrying CaseLabel::Default is also recorded as the union’s default case.

§Errors

AstError::NotAnAggregate if the target is not a union.

Source

pub fn enumerator( &self, id: Id<EnumeratorNode>, ) -> Result<&EnumeratorNode, AstError>

Borrow an enumerator.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn enumerators( &self, ) -> impl Iterator<Item = (Id<EnumeratorNode>, &EnumeratorNode)>

Iterate every enumerator in the model, in arena order.

Source

pub fn enumerator_mut( &mut self, id: Id<EnumeratorNode>, ) -> Result<&mut EnumeratorNode, AstError>

Borrow an enumerator mutably.

For @value(n), which a frontend applies after the enumerator exists.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_enumerator( &mut self, enumeration: Id<TypeNode>, name: &str, value: Option<Id<ConstExprNode>>, ) -> Result<Id<EnumeratorNode>, AstError>

Add an enumerator to an enumeration.

value is None for a positional enumerator and Some for an explicit @value(n); the two encode differently. Spec §3.3.

§Errors

AstError::NotAnAggregate if the target is not an enumeration.

Source

pub fn bit_value(&self, id: Id<BitValueNode>) -> Result<&BitValueNode, AstError>

Borrow a bitmask bit.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn bit_value_mut( &mut self, id: Id<BitValueNode>, ) -> Result<&mut BitValueNode, AstError>

Borrow a bitmask bit mutably.

For @position(k), which a frontend applies after the bit exists.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn bit_values( &self, ) -> impl Iterator<Item = (Id<BitValueNode>, &BitValueNode)>

Iterate every bit values node in the model, in arena order.

Source

pub fn add_bit_value( &mut self, bitmask: Id<TypeNode>, name: &str, position: Option<u16>, ) -> Result<Id<BitValueNode>, AstError>

Add a bit to a bitmask.

position is None for a positional bit and Some for an explicit @position(k). Spec §3.3.

§Errors

AstError::NotAnAggregate if the target is not a bitmask.

Source

pub fn bitfield(&self, id: Id<BitfieldNode>) -> Result<&BitfieldNode, AstError>

Borrow a bitset field.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_bitfield( &mut self, bitset: Id<TypeNode>, name: Option<&str>, bits: u16, holder_type: Option<Ref<TypeNode>>, ) -> Result<Id<BitfieldNode>, AstError>

Add a field to a bitset. name is None for anonymous padding.

§Errors

AstError::NotAnAggregate if the target is not a bitset.

Source

pub fn expr(&self, id: Id<ConstExprNode>) -> Result<&ConstExprNode, AstError>

Borrow an expression node.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_expr( &mut self, expr: ConstExpr, ) -> Result<Id<ConstExprNode>, AstError>

Add an expression node.

§Errors

AstError::Core when identity or slot space is exhausted.

Source

pub fn add_int_expr( &mut self, value: i128, ) -> Result<Id<ConstExprNode>, AstError>

Add an integer literal expression, the common case.

§Errors

As Ast::add_expr.

Source

pub fn constant(&self, id: Id<ConstNode>) -> Result<&ConstNode, AstError>

Borrow a constant.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn constants(&self) -> impl Iterator<Item = (Id<ConstNode>, &ConstNode)>

Iterate every constants node in the model, in arena order.

Source

pub fn add_const( &mut self, module: Id<ModuleNode>, name: &str, type_: Ref<TypeNode>, expr: Id<ConstExprNode>, ) -> Result<Id<ConstNode>, AstError>

Declare a constant in a module.

§Errors

AstError::Core on a stale module handle.

Source

pub fn eval_integral(&self, expr: Id<ConstExprNode>) -> Result<i128, EvalError>

Evaluate an expression to an integral value.

The tree is not mutated: evaluation is a query, so the written form stays available to the formatter and the linter. Spec §3.5.

§Errors

EvalError::Unresolved when the tree reaches a reference that is not resolved — a partially discovered model fails loudly rather than substituting a default. Also EvalError::DivisionByZero, EvalError::Overflow, EvalError::InvalidShift, EvalError::NotIntegral, EvalError::DanglingExpr and EvalError::TooDeep.

Source

pub fn eval_const( &self, expr: Id<ConstExprNode>, ) -> Result<ConstValue, EvalError>

Evaluate an expression to its value, whatever kind that is.

Self::eval_integral is the right question wherever the wire needs a number, and the wrong one wherever a backend only needs to know what a constant says. const string MODULE_ID = "…"; is evaluated and has no integer, so an integral evaluator reports NotIntegral and a caller that has nothing else to ask cannot emit the constant at all.

An expression with an operator in it is integral and comes back as ConstValue::Integer, unless a floating-point operand stands in it: then it is evaluated in double as IDL 4.2 §7.4.1.4.2 says and comes back as ConstValue::Float; a fixed-point operand makes it exact decimal arithmetic after Table 7-11, back as ConstValue::Fixed.

§Errors

As Self::eval_integral; for floating arithmetic also EvalError::MixedOperands, EvalError::NotFloatingOperator and EvalError::LongDouble, for fixed-point arithmetic EvalError::NotFixedOperator. A literal alone always has a value.

Source

pub fn interface( &self, id: Id<InterfaceNode>, ) -> Result<&InterfaceNode, AstError>

Borrow an interface.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_interface( &mut self, module: Id<ModuleNode>, name: &str, kind: InterfaceKind, bases: Vec<Ref<InterfaceNode>>, ) -> Result<Id<InterfaceNode>, AstError>

Declare an interface in a module.

§Errors

AstError::Core on a stale module handle.

Source

pub fn add_forward_interface( &mut self, module: Id<ModuleNode>, name: &str, kind: InterfaceKind, ) -> Result<Id<InterfaceNode>, AstError>

Declare an interface whose body has not arrived.

interface I; — IDL 4.2 §7.4.3, rule (75). The same shape Self::add_forward_type gives a struct or a union, and for the same reason: forwardness is a state of one node, so a reference taken against the declaration stays valid when the definition completes it.

§Errors

As Self::add_interface.

Source

pub fn complete_interface( &mut self, id: Id<InterfaceNode>, kind: InterfaceKind, bases: Vec<Ref<InterfaceNode>>, ) -> Result<(), AstError>

Give a forward-declared interface its body.

An update of the existing node, not a second one — the reason Self::complete_type gives.

§Errors

AstError::AlreadyComplete if the interface already has a body: two definitions of one name are a duplicate, not a completion. AstError::Core on a stale handle.

Source

pub fn interfaces( &self, ) -> impl Iterator<Item = (Id<InterfaceNode>, &InterfaceNode)>

Iterate every interface in the model, in arena order.

Source

pub fn operations( &self, ) -> impl Iterator<Item = (Id<OperationNode>, &OperationNode)>

Iterate every operation in the model, in arena order.

An operation’s owner is OperationNode::parent, which is an AnyId because a valuetype declares operations too. There is no list on the valuetype for the exported ones — only for its initialisers, which is what rule (105) distinguishes — so this is how a consumer finds them.

Source

pub fn set_interface_form( &mut self, id: Id<InterfaceNode>, kind: InterfaceKind, bases: Vec<Ref<InterfaceNode>>, ) -> Result<(), AstError>

Rewrite an interface’s form and base list.

Distinct from Self::complete_interface, which gives a forward declaration the body it was still waiting for. This restates a declaration that already has one: CCM 4.0 §6.2’s equivalent interface is the component declaration with a different form and a different base list, and the identity has to survive the change so that references taken against the component keep pointing at it.

The waiter index is rebuilt, because the old bases’ pending keys have to go and the new ones have to be seen.

§Errors

AstError::Core on a stale handle.

Source

pub fn add_valuetype_base( &mut self, id: Id<TypeNode>, base: Ref<TypeNode>, ) -> Result<(), AstError>

Add a base to a valuetype.

A method rather than mutable access to the list, for the reason Self::add_raises gives: a reference added behind the model’s back is never indexed, and an unindexed pending reference is one that never resolves.

§Errors

AstError::NotAnAggregate when the type is not a valuetype, AstError::Core on a stale handle.

Source

pub fn object_reference_to( &mut self, interface: Id<InterfaceNode>, ) -> Result<Id<TypeNode>, AstError>

The type that is an object reference to interface.

An interface name written where a type is expected is an object reference — OMG IDL 4.2 §7.4.6 — and struct S { I x; } is the ordinary way to write one. The reference in S::x is a Ref<TypeNode> and an interface is not a type, so the model needs a type node standing for “a reference to I”; this returns it, creating it the first time and returning the same one after.

It carries the interface’s own name so a backend renders I, and it is deliberately left out of the name index: the name in the scope belongs to the interface, and indexing both would make every use of it ambiguous.

§Errors

AstError::Core on a stale interface handle.

Source

pub fn operation( &self, id: Id<OperationNode>, ) -> Result<&OperationNode, AstError>

Borrow an operation.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_operation( &mut self, interface: Id<InterfaceNode>, name: &str, return_type: Option<Ref<TypeNode>>, oneway: bool, ) -> Result<Id<OperationNode>, AstError>

Add an operation to an interface.

§Errors

AstError::Core on a stale handle.

Source

pub fn add_valuetype_operation( &mut self, valuetype: Id<TypeNode>, name: &str, return_type: Option<Ref<TypeNode>>, initializer: bool, ) -> Result<Id<OperationNode>, AstError>

Add an initialiser or an exported operation to a valuetype.

OMG IDL 4.2 rule (105): a valuetype body holds factory initialisers and ordinary operations alongside its state. TypeKind::Valuetype::initializers was in the model from the start and nothing could fill it — Self::add_operation takes an Id<InterfaceNode>, so every factory in every IDL file this tree read was parsed, kept in the CST and dropped at the model boundary with no diagnostic.

initializer decides which list the operation joins: an initialiser goes into initializers, an exported operation is reachable through its parent and is not one.

§Errors

AstError::Core on a stale handle, and AstError::Core when the type is not a valuetype.

Source

pub fn set_oneway( &mut self, id: Id<OperationNode>, oneway: bool, ) -> Result<(), AstError>

Mark an operation oneway.

@oneway writes the same flag as the keyword form; both reach the operation through here.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_raises( &mut self, id: Id<OperationNode>, exception: Ref<ExceptionNode>, ) -> Result<(), AstError>

Add an exception to an operation’s raises clause.

A method rather than mutable access to the list: a reference added behind the model’s back is never indexed, and an unindexed pending reference is one that never resolves.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_context( &mut self, id: Id<OperationNode>, context: &str, ) -> Result<(), AstError>

Add a context identifier to an operation.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn param(&self, id: Id<ParamNode>) -> Result<&ParamNode, AstError>

Borrow a parameter.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_param( &mut self, operation: Id<OperationNode>, name: &str, direction: ParamDirection, type_: Ref<TypeNode>, ) -> Result<Id<ParamNode>, AstError>

Add a parameter to an operation.

§Errors

AstError::Core on a stale handle.

Source

pub fn attribute( &self, id: Id<AttributeNode>, ) -> Result<&AttributeNode, AstError>

Borrow an attribute.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_attribute_raises( &mut self, id: Id<AttributeNode>, exception: Ref<ExceptionNode>, on_set: bool, ) -> Result<(), AstError>

Add an exception to an attribute’s getraises or setraises clause.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_attribute( &mut self, interface: Id<InterfaceNode>, name: &str, type_: Ref<TypeNode>, readonly: bool, ) -> Result<Id<AttributeNode>, AstError>

Add an attribute to an interface.

§Errors

AstError::Core on a stale handle.

Source

pub fn exception( &self, id: Id<ExceptionNode>, ) -> Result<&ExceptionNode, AstError>

Borrow an exception.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn exceptions( &self, ) -> impl Iterator<Item = (Id<ExceptionNode>, &ExceptionNode)>

Iterate every exceptions node in the model, in arena order.

Source

pub fn set_declaration_scope( &mut self, any: AnyId, scope: &str, ) -> Result<(), AstError>

Record that a type, constant or exception is declared inside the interface or value type scope rather than directly in its module.

§Errors

AstError::Core on a stale handle; AstError::WrongKind for a node of another kind, which no interface body declares.

Source

pub fn add_exception( &mut self, module: Id<ModuleNode>, name: &str, ) -> Result<Id<ExceptionNode>, AstError>

Declare an exception in a module.

§Errors

AstError::Core on a stale module handle.

Source

pub fn annotation_defs( &self, ) -> impl Iterator<Item = (Id<AnnotationDefNode>, &AnnotationDefNode)>

Every annotation declaration in the model, in arena order.

The counterpart of Ast::types for the other declaration kind that has a TypeObject: Annex B gives MinimalTypeObject a case TK_ANNOTATION: MinimalAnnotationType annotation_type;, and an @annotation declaration is not a TypeNode in this model, so a caller that wants to build one had no way to reach it.

Source

pub fn annotation_def( &self, id: Id<AnnotationDefNode>, ) -> Result<&AnnotationDefNode, AstError>

Borrow an annotation declaration.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_annotation_def( &mut self, module: Id<ModuleNode>, name: &str, ) -> Result<Id<AnnotationDefNode>, AstError>

Declare an annotation in a module.

§Errors

AstError::Core on a stale module handle.

Source

pub fn annotation_member( &self, id: Id<AnnotationMemberNode>, ) -> Result<&AnnotationMemberNode, AstError>

Borrow an annotation member.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_annotation_member( &mut self, annotation: Id<AnnotationDefNode>, name: &str, type_: Ref<TypeNode>, default: Option<Id<ConstExprNode>>, ) -> Result<Id<AnnotationMemberNode>, AstError>

Add a member to an annotation declaration.

§Errors

AstError::Core on a stale handle.

Source

pub fn library(&self, id: Id<LibraryNode>) -> Result<&LibraryNode, AstError>

Borrow a library.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_library(&mut self, name: &str) -> Result<Id<LibraryNode>, AstError>

Declare a deployment library.

§Errors

AstError::Core when identity space is exhausted.

Source

pub fn domain(&self, id: Id<DomainNode>) -> Result<&DomainNode, AstError>

Borrow a domain.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_domain( &mut self, library: Id<LibraryNode>, name: &str, domain_id: u32, ) -> Result<Id<DomainNode>, AstError>

Declare a domain in a library.

§Errors

AstError::Core on a stale handle.

Source

pub fn topic(&self, id: Id<TopicNode>) -> Result<&TopicNode, AstError>

Borrow a topic.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_topic( &mut self, domain: Id<DomainNode>, name: &str, type_: Ref<TypeNode>, qos: Option<Ref<QosProfileNode>>, ) -> Result<Id<TopicNode>, AstError>

Declare a topic in a domain.

§Errors

AstError::Core on a stale handle.

Source

pub fn qos_profile( &self, id: Id<QosProfileNode>, ) -> Result<&QosProfileNode, AstError>

Borrow a QoS profile.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_qos_profile( &mut self, library: Id<LibraryNode>, name: &str, base: Option<Ref<QosProfileNode>>, policies: Vec<QosPolicy>, ) -> Result<Id<QosProfileNode>, AstError>

Declare a QoS profile in a library.

§Errors

AstError::Core on a stale handle.

Source

pub fn participant( &self, id: Id<ParticipantNode>, ) -> Result<&ParticipantNode, AstError>

Borrow a participant.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_participant( &mut self, library: Id<LibraryNode>, name: &str, domain: Ref<DomainNode>, qos: Option<Ref<QosProfileNode>>, ) -> Result<Id<ParticipantNode>, AstError>

Declare a participant in a library.

§Errors

AstError::Core on a stale handle.

Source

pub fn endpoint(&self, id: Id<EndpointNode>) -> Result<&EndpointNode, AstError>

Borrow an endpoint.

§Errors

AstError::Core with a stale or unknown handle.

Source

pub fn add_endpoint( &mut self, participant: Id<ParticipantNode>, name: &str, role: EndpointRole, topic: Ref<TopicNode>, qos: Option<Ref<QosProfileNode>>, ) -> Result<Id<EndpointNode>, AstError>

Declare an endpoint on a participant.

§Errors

AstError::Core on a stale handle.

Source

pub fn facets(&self, any: AnyId) -> Option<&Facets>

The facets of any node.

Source

pub fn facets_mut(&mut self, any: AnyId) -> Option<&mut Facets>

The facets of any node, mutably.

Source

pub fn any_of_type(&self, id: Id<TypeNode>) -> Result<AnyId, AstError>

The AnyId for a type handle.

§Errors

AstError::Core with a stale handle.

Source

pub fn any_of_member(&self, id: Id<MemberNode>) -> Result<AnyId, AstError>

The AnyId for a member handle.

§Errors

AstError::Core with a stale handle.

Source§

impl Ast

Source

pub fn drop_outside_profile( &mut self, profile: Profile, ) -> Result<Vec<Dropped>, AstError>

Remove the data types that reach a construct profile has no type for, and return what was removed.

A type is removed when it is, or reaches through members, cases, aliases, collection elements, map keys and values, bases or a discriminator, a construct construct_verdict(profile, …) rejects among any, ValueBase, native and an object reference. The construct’s own node stays in the model (it is the shared node every any points at).

A type that a constant, an operation, a parameter, an attribute, an annotation member or a topic names is kept: removing it would leave that declaration with a reference to nothing, and the caller would then be told about a broken reference instead of the construct. Such a type stays in the model and a code generator reports the construct by name, as before.

Nothing is removed under a profile that admits all four.

§Errors

AstError when a removal breaks a structural rule of the model; the types removed before it stay removed, so a caller treats the model as spoilt.

Source§

impl Ast

Source

pub fn validate(&self, profile: Profile) -> Result<(), Vec<ProfileViolation>>

Measure the model against a profile.

Drives the construct table in verdict, so every type kind and every facet property has an explicit ruling. Profile-specific checks that are not a simple yes/no on a construct — bit bounds, topic resolvability, plain-type reachability — run alongside it.

§Errors

Every violation found, never only the first.

Source

pub fn validate_complete(&self) -> Result<(), Vec<ProfileViolation>>

Check the completeness rules: nothing left pending, nothing broken, every forward declaration given a body.

Deliberately separate from the commit gate: a partially discovered model passes every structural invariant and fails this. Spec §8.2.

§Errors

Every incompleteness found.

Source§

impl Ast

Source

pub fn find_by_scoped_name( &self, name: &ScopedName, ) -> Result<AnyId, IndexLookup>

Find any node by its full scoped name.

§Errors

IndexLookup::Missing when nothing carries the name, IndexLookup::Ambiguous with every candidate when several do.

Source

pub fn find_by_type_identifier( &self, key: &TypeIdentifierKey, ) -> Result<Id<TypeNode>, IndexLookup>

Find a type by its XTypes type identifier.

§Errors

As Ast::find_by_scoped_name.

Source

pub fn find_by_ros_name( &self, name: &RosTypeName, ) -> Result<Id<TypeNode>, IndexLookup>

Find a type by its ROS 2 interface name.

§Errors

As Ast::find_by_scoped_name.

Source

pub fn find_by_repository_id( &self, id: &RepositoryId, ) -> Result<AnyId, IndexLookup>

Find any node by its CORBA repository identifier.

§Errors

As Ast::find_by_scoped_name.

Source

pub fn scoped_name_of(&self, any: AnyId) -> Option<ScopedName>

The full scoped name of a node, if it has one.

Nodes that live inside a type rather than a module — members, cases, parameters — have no scoped name of their own.

Source

pub fn members_of(&self, type_: Id<TypeNode>) -> &[Id<MemberNode>]

The members of an aggregate, empty for every other kind.

Source

pub fn all_members_of(&self, type_: Id<TypeNode>) -> Vec<Id<MemberNode>>

The members of an aggregate, its bases’ members first.

Ast::members_of answers what a type declares; this answers what it has, which is what every wire consumer needs. DDS-XTypes 1.3 §7.4.1.1.5.1: “The members defined by the base type, if any, shall be serialized before the members of their derived types. The representation shall be exactly as if all of the members had been defined, in the same order, in the most-derived type.”

The chain is walked to a fixed depth and a base already seen is not walked again: an inheritance cycle is invalid IDL, and looping here would hang instead of reporting it.

Source

pub fn base_of(&self, type_: Id<TypeNode>) -> Option<Id<TypeNode>>

The base an aggregate extends, if it has one.

A valuetype may name several; only a single base is a structure on the wire, so the first is what the layout follows.

A bitset counts: IDL 4.2 §7.4.13.4.3.2 gives bitset “an optional single inheritance specification”, and the inherited bitfields are part of what the derived bitset packs. Ast::members_of is empty for a bitset either way, so Ast::all_members_of is unaffected by the extra arm.

Source

pub fn bitfields_of(&self, type_: Id<TypeNode>) -> &[Id<BitfieldNode>]

The bitfields a bitset declares, empty for every other kind.

Source

pub fn all_bitfields_of(&self, type_: Id<TypeNode>) -> Vec<Id<BitfieldNode>>

The bitfields a bitset has, its bases’ bitfields first.

The bitset counterpart of Ast::all_members_of, and needed for the same reason: a plan that leaves the inherited bitfields out sizes the anchor as if they did not exist, and every emitter behind it writes short.

§Why base-first, when no specification says so

DDS-XTypes 1.3 has no serialisation rule for a bitset — see the note above wire_probe::encode::write_bitset. The order is therefore taken from the one implementation that serialises the construct at all. Measured on 2026-08-09, eProsima Fast DDS 3.6.1 flattens bitset B3 : B2 : B1 with bitfield<8> a, bitfield<8> b, bitfield<4> c into a std::bitset<20> and packs a at bits 0..8, b at 8..16 and c at 16..20 — the base’s bitfields at the least significant end, in declaration order. Cyclone’s idlc and RTI’s rtiddsgen do not parse bitset at all, so Fast DDS is the only oracle there is.

The chain is walked to the same fixed depth as Ast::all_members_of, and a base already seen is not walked again: an inheritance cycle is invalid IDL, and looping here would hang instead of reporting it.

Source

pub fn enumerators_of(&self, type_: Id<TypeNode>) -> &[Id<EnumeratorNode>]

The enumerators of an enumeration, empty for every other kind.

Source

pub fn bits_of(&self, type_: Id<TypeNode>) -> &[Id<BitValueNode>]

The bits of a bitmask, empty for every other kind.

Source

pub fn attributes_of( &self, interface: Id<InterfaceNode>, ) -> &[Id<AttributeNode>]

The attributes an interface declares directly.

Source

pub fn effective_extensibility(&self, type_: Id<TypeNode>) -> Extensibility

The extensibility a type has, written or defaulted.

The facet keeps None for a type whose source said nothing, so what was written stays distinguishable from what the rule gives. This is the rule: @final/@appendable/@mutable, else @extensibility(...), else — for a structure that derives from another — its base’s, else appendable. DDS-XTypes 1.3 §7.2.4.4, §7.2.2.4.5.

Appendable, not final: a consumer that assumed final would emit types that cannot evolve, and no DHEADER where one belongs.

The base’s, not appendable: §7.2.2.4.5 lets a derived structure leave its extensibility unspecified or give the base’s, so an unspecified one has the base’s. Cyclone DDS 11.0.1 frames struct Derived : Base of a @mutable base as mutable (DDS_OP_PLC, measured); falling back to appendable here framed it with a DHEADER and no EMHEADERs.

Source

pub fn effective_autoid(&self, type_: Id<TypeNode>) -> Option<AutoId>

The @autoid policy of a type: its own, else the nearest enclosing module’s.

DDS-XTypes 1.3 §7.3.1.2.1.1 and Table 21 apply @autoid to “Module declarations, Structure declarations, Union declarations”; on a module it governs every aggregated type declared in it that does not carry its own. None is “nothing said”, which numbers the members sequentially.

Source

pub fn effective_data_representation( &self, type_: Id<TypeNode>, ) -> Option<DataRepresentationMask>

The @data_representation mask of a type: its own, else the nearest enclosing module’s.

DDS-XTypes 1.3 §7.3.1.2.1.15: the annotation “may be applied to modules and to types”; a module’s value is the default for the types in it. None is “nothing said”, which §7.6.3.1.1 reads as every representation the implementation supports.

Source

pub fn data_representation_mask( &self, type_: Id<TypeNode>, ) -> DataRepresentationMask

The DataRepresentationMask a type has, with the annotation-less case resolved: a type and its modules that carry no @data_representation are “interpreted as if the DataRepresentationMask value was set to 0xffffffff” (DDS-XTypes 1.3 §7.3.1.2.1.15), which is crate::DataRepresentationMask::ALL.

Source

pub fn effective_bit_bound(&self, type_: Id<TypeNode>) -> u16

The bit bound an enum or bitmask has, written or defaulted. DDS-XTypes 1.3 §7.3.1.2.1.9.

Source

pub fn effective_try_construct( &self, written: Option<TryConstruct>, used: Option<Id<TypeNode>>, ) -> TryConstruct

The try_construct behaviour that governs one use of a type.

written is the annotation at the use site — a member’s own @try_construct, or the collection’s element_try_construct / key_try_construct, or the union’s discriminator_try_construct. used is the type being used there.

The order is: what the use site wrote, else what the alias chain of the used type declares nearest-first, else TryConstruct::ABSENT — DISCARD, which §7.2.2.7 names as the default when the annotation is not used.

§Why an alias may carry one

The clause does not list aliases among the positions (§7.3.1.2.1.12 names members, the discriminator, array and sequence elements, and map keys and values), and both Cyclone and RTI refuse @try_construct on a typedef by name. Neither of those is a statement about what an alias-borne annotation would mean; they are front ends declining to accept it, and the two implementations that do accept it — Fast DDS and OpenDDS — say nothing about it either. With the specification silent, the reading here is the broader one: an alias states the behaviour that uses of it take by default, and any use site that writes its own overrides it. Nothing an author wrote can be lost that way, and typedef string<5> String5 — the very declaration §7.3.1.2.1.12.4 builds its example on — becomes able to carry the behaviour it exists to give its uses.

A peer built by Cyclone or RTI will not compile such a declaration at all; crates/ast-layout/tests/fixtures/try_construct_behaviour.md records that.

Source

pub fn element_try_construct( &self, collection: Id<TypeNode>, member_wrote: Option<TryConstruct>, ) -> TryConstruct

The behaviour that governs the elements of one collection.

collection is a sequence, an array or a map — for a map this is the value slot. member_wrote is the @try_construct on the member whose type this collection is, if any.

§Why a member’s annotation can reach an array’s elements

An array cannot be trimmed and cannot overflow: Table 17 requires T1.bounds[] == T2.bounds[], so the only way an array fails to construct is that one of its elements does. Its row accordingly speaks of nothing but “the TryConstruct behavior associated with T1 element type” — an array has no member-level behaviour to carry. There is also no template syntax to annotate an array’s element with: @try_construct(TRIM) String5 m[3] writes the annotation in front of the member, which is where OpenDDS reads its array_element_try_construct from as well.

A sequence or a map has both, and they are different questions — the member’s governs a length the receiver’s bound cannot hold (§7.3.1.2.1.12.3), the element’s governs one element that will not construct (§7.3.1.2.1.12.4) — so a member’s annotation never reaches their elements.

Source

pub fn key_try_construct(&self, map: Id<TypeNode>) -> TryConstruct

The behaviour that governs a map’s keys.

Table 17 gives a key no escape — a key that cannot construct fails the whole map — so this is DISCARD unless a declaration wrote DISCARD explicitly, which the front end is the only thing that admits. It reads the slot rather than returning a constant so that a future revision of the clause has one place to change.

Source

pub fn effective_nested(&self, type_: Id<TypeNode>) -> bool

Whether a type is @nested — its own annotation, else the @default_nested of the nearest enclosing module that carries one.

DDS-XTypes 1.3 §7.3.1.2.1.7: “@default_nested … applied to a module … indicates whether the types defined within it are nested by default … value defaults to that of the enclosing module. If a top-level module is not annotated, the default is FALSE.”

A type’s own @nested wins over the module’s. @default_nested used to reach nothing at all: the annotation parsed, the model dropped it, and a whole module declared nested emitted IS_NESTED-free TypeObjects — which is a topic type per endpoint that the author said should be none.

The walk is bounded by the module chain, which the model builds acyclically; the counter is there so a handle that somehow points at its own ancestor ends the loop rather than the process.

Source

pub fn element_is_external(&self, collection: Id<TypeNode>) -> bool

Whether the elements of a collection are @external — the sequence or array element, or the value of a map (DDS-XTypes 1.3 §7.3.1.2.1.4).

Source

pub fn element_annotations( &self, collection: Id<TypeNode>, ) -> &[AppliedAnnotation]

The user-declared annotations written on the element type of a collection (DDS-XTypes 1.3 §7.2.2.6), in the order they were written. For a map, the value’s.

Source

pub fn key_annotations(&self, map: Id<TypeNode>) -> &[AppliedAnnotation]

The user-declared annotations written on the key type of a map.

Source

pub fn discriminator_annotations( &self, union_: Id<TypeNode>, ) -> &[AppliedAnnotation]

The user-declared annotations written on the discriminator type of a union (DDS-XTypes 1.3 §7.3.1.2.5).

Source

pub fn key_is_external(&self, map: Id<TypeNode>) -> bool

Whether the key of a map is @external.

Source

pub fn discriminator_try_construct(&self, union: Id<TypeNode>) -> TryConstruct

The behaviour that governs a union’s discriminator. DDS-XTypes 1.3 §7.3.1.2.1.12.5, Table 19.

Source

pub fn discriminator_is_key(&self, union: Id<TypeNode>) -> bool

Whether a union’s discriminator carries @key.

DDS-XTypes 1.3 Table 21 lists @key against “Structure Members, Union discriminator” and §7.2.2.4.4.4.8’s example is union MyCommand switch (@key CommandKind). A union that answers true here is a keyed topic type whose key holder is the discriminator alone, and §7.2.4.4.4.5 — Table 19’s UNION_TYPE row, “Either the discriminators of both T1 and T2 are keys or neither are keys” — makes it unassignable to a union that answers false.

False for anything that is not a union, and false for a union whose front end was not asked to carry the annotation — see zerodds_idl_lower::KeyOnUnionDiscriminator.

Source

pub fn effective_enumerator_value(&self, id: Id<EnumeratorNode>) -> Option<i128>

The value an enumerator has, written or positional.

@value(n), else the previous enumerator’s value plus one, starting at 0. OMG IDL 4.2 §7.4.13.

Returns None only when the handle is stale or an explicit expression does not evaluate — never a substituted 0, which would give two enumerators the same value without saying so.

Source

pub fn effective_bit_position(&self, id: Id<BitValueNode>) -> Option<u16>

The position a bitmask bit has, written or positional. DDS-XTypes 1.3 §7.3.1.2.1.10.

Source

pub fn cases_of(&self, type_: Id<TypeNode>) -> &[Id<CaseNode>]

The cases of a union, empty for every other kind.

Source

pub fn operations_of( &self, interface: Id<InterfaceNode>, ) -> &[Id<OperationNode>]

The operations an interface declares directly.

Not the whole answer. InterfaceNode.bases exists and OMG IDL 4.2 §7.4.3 gives a derived interface every operation of its bases, so this list is short by exactly those. Only a caller that writes the base into the target language — a Java extends, a C++ base clause, a TypeScript extends — wants it; every caller that emits a flat declaration wants Ast::all_operations_of, and one that took this instead emitted a type the source did not describe with nothing to report it.

Source

pub fn all_operations_of( &self, interface: Id<InterfaceNode>, ) -> Vec<Id<OperationNode>>

Every operation an interface has, its bases’ before its own.

Ast::operations_of answers what an interface declares; this answers what it has. OMG IDL 4.2 §7.4.3: a derived interface “inherits all the operations and attributes of its base interfaces”, and a client holding a Derived may call every one of them. A generated binding that carries only the declared ones is a type the source did not describe, and nothing reports it — the operation is simply not there.

Multiple inheritance is a graph and not a chain, so bases are walked in declaration order — the order §7.4.3 resolves an operation lookup along — and an interface reached twice through a diamond contributes its operations once. The depth bound and the seen list are Ast::all_members_of’s, for the same reason: an inheritance cycle is invalid IDL and looping here would hang instead of reporting it.

Source

pub fn descendants(&self, root: AnyId) -> Vec<AnyId>

Every node reachable from root, itself included, in pre-order.

Terminates on recursive types: a struct containing sequence<Self> appears once. Spec §6.

Source

pub fn all_nodes(&self) -> impl Iterator<Item = AnyId> + '_

Every node the model holds, in identity order.

Source

pub fn reachable_types(&self, type_: Id<TypeNode>) -> VisitSet

Every type reachable from type_, itself included.

The layout cache uses this to know which cached plans a change invalidates. Spec §7.

Source

pub fn reindex(&mut self)

Rebuild every index from the model’s current content.

Called after loading a snapshot; ordinary editing maintains the indices from the changeset instead. Spec §6, §9.

Source

pub fn set_type_identifier( &mut self, type_: Id<TypeNode>, key: TypeIdentifierKey, ) -> Result<(), AstError>

Register a type identifier for a type.

The identifier is computed by the XTypes runtime, not here; the model only indexes it. Spec §1.2.

§Errors

crate::AstError::Core with a stale handle.

Source§

impl Ast

Source

pub fn pending_slots(&self, any: AnyId) -> Vec<PendingSlot>

Every pending reference a node holds.

The one place that knows where references live, so adding a reference to a node kind is one edit rather than four.

Source§

impl Ast

Source

pub fn pending_waiters(&self, key: &PendingRef) -> &[NodeId]

Every node waiting on a given lookup key.

Source

pub fn pending_count(&self) -> usize

How many references are still pending.

Source

pub fn resolve_pending( &mut self, key: &PendingRef, target: Id<TypeNode>, ) -> Result<usize, AstError>

Resolve every waiter on key to target.

Returns how many references changed. Each one emits an Updated change carrying both the old and the new reference state.

§Errors

AstError::WrongKind when the target cannot satisfy the waiters — a member’s type reference pointing at an interface, for instance.

Source

pub fn resolve_pending_to( &mut self, key: &PendingRef, target: AnyId, ) -> Result<usize, AstError>

Resolve every waiter on key to any kind of node.

The general form of Ast::resolve_pending: a constant named in an array dimension, an exception in a raises clause and a base interface all resolve through here.

§Errors

AstError::Core on an arena failure while rewriting.

Source

pub fn break_pending( &mut self, key: &PendingRef, cause: BreakCause, ) -> Result<usize, AstError>

Mark every waiter on key broken, with a cause.

§Errors

Never fails today; the signature matches Ast::resolve_pending so callers can treat both the same way.

Source

pub fn resolve_all_by_name(&mut self) -> Result<ResolveReport, AstError>

§Errors

AstError::Core on an arena failure while rewriting.

Source

pub fn reindex_pending(&mut self, any: AnyId)

Rebuild a node’s entries in the waiter index.

For a mutation that replaced or added references: the old keys go and the current ones are indexed. An unindexed pending reference never resolves.

Source§

impl Ast

Source

pub fn to_snapshot(&self) -> Result<Vec<u8>, AstError>

Serialise the model.

§Errors

AstError::Core when a name or payload exceeds what the length prefix can express.

Source

pub fn from_snapshot(bytes: &[u8]) -> Result<Self, AstError>

Load a model from a snapshot.

Every NodeId is preserved and the indices are rebuilt, so the loaded model is usable immediately.

§Errors

AstError::Core with AstCoreError::MalformedSnapshot on a wrong magic, an unknown version, truncation or an out-of-range handle. Never panics; this is a fuzz target.

Trait Implementations§

Source§

impl Default for Ast

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl !RefUnwindSafe for Ast

§

impl !UnwindSafe for Ast

§

impl Freeze for Ast

§

impl Send for Ast

§

impl Sync for Ast

§

impl Unpin for Ast

§

impl UnsafeUnpin for Ast

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.