Trait texlang::vm::HasComponent

source ·
pub trait HasComponent<C>: TexlangState {
    // Required methods
    fn component(&self) -> &C;
    fn component_mut(&mut self) -> &mut C;
}
Expand description

Helper trait for implementing the component pattern in Texlang.

The component pattern is a ubiquitous design pattern in Texlang. It is used when implementing TeX commands that require state. An example of a stateful TeX command is \year, which needs to store the current year somewhere.

When the component pattern is used, a stateful TeX command can have a single implementation that is used by multiple TeX engines built with Texlang. Additionally, a specific TeX engine can compose many different stateful TeX commands together without worrying about conflicts between their state. The component pattern is Texlang’s main solution to the problem of global mutable state that is pervasive in the original implementation of TeX.

In the component pattern, the state needed by a specific command like \year is isolated in a component, which is a concrete Rust type like a struct. This Rust type is the generic type C in the trait. The stateful command (e.g. \year) is defined in the same Rust module as the component. The internals of the component are made private to the module it is defined in. This means the state can only be mutated by the command (or commands) implemented in the module.

In order to function, the command needs to have access to an instance of the component in which the command will maintain its state. The HasComponent trait enforces this. Any VM state type that contains the component can implement the trait. The Rust code defining the command specifies the trait in its trait bounds, and uses the trait to access the component.

The pattern enables Texlang code to be composed as follows. Different VM states can include the same component and thus reuse the same commands. Combining multiple commands into one state just involves having the VM state include all of the relevant components.

Notes:

  • In general state is shared by multiple commands. Such commands must be defined in the same Rust module to support this. For example, \countdef shares state with \count, and they are implemented together.

  • Commands don’t necessarily have state: for example, \def, \advance and \the. These commands are defined without trait bounds on the state, and work automatically with any TeX software built with Texlang.

  • The easiest way to include a component in the state is to make it a direct field of the state. In this case the implement_has_component macro can be used to easily implement the trait. The Texlang standard library uses this approach.

The TexlangState requirement

This trait requires that the type also implements TexlangState. This is only to reduce the number of trait bounds that need to be explicitly specified when implementing TeX commands. In general every command needs to have a bound of the form S: TexlangState. Commands that have a HasComponent bound don’t need to include this other bound explicitly.

Required Methods§

source

fn component(&self) -> &C

Return a immutable reference to the component.

source

fn component_mut(&mut self) -> &mut C

Return a mutable reference to the component.

Implementors§