Skip to main content

DataStore

Trait DataStore 

Source
pub trait DataStore: Send + Sync {
Show 28 methods // Required methods fn read_coils( &self, address: u16, quantity: u16, buf: &mut [bool], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send; fn write_coil( &self, address: u16, value: bool, ) -> impl Future<Output = Result<(), ExceptionCode>> + Send; fn write_coils( &self, address: u16, values: &[bool], ) -> impl Future<Output = Result<(), ExceptionCode>> + Send; fn read_discrete_inputs( &self, address: u16, quantity: u16, buf: &mut [bool], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send; fn read_holding_registers( &self, address: u16, quantity: u16, buf: &mut [u16], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send; fn write_register( &self, address: u16, value: u16, ) -> impl Future<Output = Result<(), ExceptionCode>> + Send; fn write_registers( &self, address: u16, values: &[u16], ) -> impl Future<Output = Result<(), ExceptionCode>> + Send; fn read_input_registers( &self, address: u16, quantity: u16, buf: &mut [u16], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send; // Provided methods fn read_coils_packed( &self, address: u16, quantity: u16, out: &mut [u8], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send { ... } fn write_coils_packed( &self, address: u16, quantity: u16, packed_values: &[u8], ) -> impl Future<Output = Result<(), ExceptionCode>> + Send { ... } fn read_discrete_inputs_packed( &self, address: u16, quantity: u16, out: &mut [u8], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send { ... } fn read_holding_registers_be( &self, address: u16, quantity: u16, out: &mut [u8], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send { ... } fn write_registers_be( &self, address: u16, quantity: u16, value_bytes: &[u8], ) -> impl Future<Output = Result<(), ExceptionCode>> + Send { ... } fn read_input_registers_be( &self, address: u16, quantity: u16, out: &mut [u8], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send { ... } fn read_file_record( &self, file_number: u16, record_number: u16, record_length: u16, buf: &mut [u16], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send { ... } fn read_file_record_be( &self, file_number: u16, record_number: u16, record_length: u16, out: &mut [u8], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send { ... } fn write_file_record( &self, file_number: u16, record_number: u16, values: &[u16], ) -> impl Future<Output = Result<(), ExceptionCode>> + Send { ... } fn write_file_record_be( &self, file_number: u16, record_number: u16, record_length: u16, value_bytes: &[u8], ) -> impl Future<Output = Result<(), ExceptionCode>> + Send { ... } fn read_fifo_queue( &self, address: u16, ) -> impl Future<Output = Result<Vec<u16>, ExceptionCode>> + Send { ... } fn read_fifo_queue_be( &self, address: u16, out: &mut [u8], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send { ... } fn read_exception_status( &self, ) -> impl Future<Output = Result<u8, ExceptionCode>> + Send { ... } fn get_comm_event_counter( &self, ) -> impl Future<Output = Result<(u16, u16), ExceptionCode>> + Send { ... } fn get_comm_event_log( &self, ) -> impl Future<Output = Result<CommEventLog, ExceptionCode>> + Send { ... } fn append_comm_event_log( &self, out: &mut Vec<u8>, ) -> impl Future<Output = Result<CommEventLogMeta, ExceptionCode>> + Send { ... } fn report_server_id( &self, ) -> impl Future<Output = Result<Vec<u8>, ExceptionCode>> + Send { ... } fn append_server_id( &self, out: &mut Vec<u8>, ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send { ... } fn diagnostic( &self, sub_function: DiagnosticSubFunction, data: &[u8], ) -> impl Future<Output = Result<Option<Vec<u8>>, ExceptionCode>> + Send { ... } fn append_diagnostic_response( &self, sub_function: DiagnosticSubFunction, data: &[u8], out: &mut Vec<u8>, ) -> impl Future<Output = Result<Option<usize>, ExceptionCode>> + Send { ... }
}
Expand description

Async trait abstracting the four Modbus data tables (Spec V1.1b3 §4.3).

All methods are async to support database-backed and remote-proxied stores. Return types use impl Future<...> + Send to ensure compatibility with tokio::spawn in the server runtime.

Read methods take &mut [T] buffers to avoid heap allocation per request.

The eight methods covering the four core data tables (coils, discrete inputs, holding/input registers) are required. The remaining methods — file records, FIFO queues, and the serial-line diagnostics family — are optional: each has a default body returning the spec-correct exception for an unsupported capability, so existing implementations keep compiling and only override the capabilities they actually serve.

Required Methods§

Source

fn read_coils( &self, address: u16, quantity: u16, buf: &mut [bool], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send

Read coil statuses into buf. Returns number of coils written.

§Errors

Returns IllegalDataAddress if address + quantity exceeds the address space.

Source

fn write_coil( &self, address: u16, value: bool, ) -> impl Future<Output = Result<(), ExceptionCode>> + Send

Write a single coil.

Source

fn write_coils( &self, address: u16, values: &[bool], ) -> impl Future<Output = Result<(), ExceptionCode>> + Send

Write multiple coils.

Source

fn read_discrete_inputs( &self, address: u16, quantity: u16, buf: &mut [bool], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send

Read discrete input statuses into buf.

Source

fn read_holding_registers( &self, address: u16, quantity: u16, buf: &mut [u16], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send

Read holding registers into buf. Returns number of registers written.

Source

fn write_register( &self, address: u16, value: u16, ) -> impl Future<Output = Result<(), ExceptionCode>> + Send

Write a single holding register.

Source

fn write_registers( &self, address: u16, values: &[u16], ) -> impl Future<Output = Result<(), ExceptionCode>> + Send

Write multiple holding registers.

Source

fn read_input_registers( &self, address: u16, quantity: u16, buf: &mut [u16], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send

Read input registers into buf.

Provided Methods§

Source

fn read_coils_packed( &self, address: u16, quantity: u16, out: &mut [u8], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send

Read coil statuses directly into the Modbus packed-bit wire format.

The default implementation delegates to Self::read_coils through a bounded scratch buffer. Stores with direct table access can override this method to avoid the intermediate bool slice and response repacking.

Source

fn write_coils_packed( &self, address: u16, quantity: u16, packed_values: &[u8], ) -> impl Future<Output = Result<(), ExceptionCode>> + Send

Write multiple coils from the Modbus packed-bit wire representation.

The default implementation unpacks into a bounded stack buffer and then delegates to Self::write_coils. Stores with direct table access can override this method to avoid the intermediate bool slice entirely.

Source

fn read_discrete_inputs_packed( &self, address: u16, quantity: u16, out: &mut [u8], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send

Read discrete input statuses directly into the Modbus packed-bit wire format.

The default implementation delegates to Self::read_discrete_inputs through a bounded scratch buffer. Stores with direct table access can override this method to avoid the intermediate bool slice.

Source

fn read_holding_registers_be( &self, address: u16, quantity: u16, out: &mut [u8], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send

Read holding registers directly into big-endian Modbus wire bytes.

The default implementation delegates to Self::read_holding_registers through a bounded scratch buffer. Stores with direct table access can override this method to avoid the intermediate register slice and response encoding pass.

Source

fn write_registers_be( &self, address: u16, quantity: u16, value_bytes: &[u8], ) -> impl Future<Output = Result<(), ExceptionCode>> + Send

Write multiple holding registers from big-endian Modbus wire bytes.

The default implementation unpacks into a bounded stack buffer and then delegates to Self::write_registers. Stores with direct table access can override this method to avoid the intermediate register slice.

Source

fn read_input_registers_be( &self, address: u16, quantity: u16, out: &mut [u8], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send

Read input registers directly into big-endian Modbus wire bytes.

The default implementation delegates to Self::read_input_registers through a bounded scratch buffer. Stores with direct table access can override this method to avoid the intermediate register slice.

Source

fn read_file_record( &self, file_number: u16, record_number: u16, record_length: u16, buf: &mut [u16], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send

Read one file sub-record (record_length registers from record_number in file file_number) into buf; returns the number of registers written (Spec V1.1b3 §6.14).

The default returns ExceptionCode::IllegalFunction — a store that does not maintain file records reports 0x01 for FC 0x14.

Source

fn read_file_record_be( &self, file_number: u16, record_number: u16, record_length: u16, out: &mut [u8], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send

Read one file sub-record directly into big-endian Modbus wire bytes.

The default implementation delegates to Self::read_file_record with a bounded scratch buffer and then packs that scratch into out. Stores with direct file access can override this method to avoid the intermediate register slice.

Source

fn write_file_record( &self, file_number: u16, record_number: u16, values: &[u16], ) -> impl Future<Output = Result<(), ExceptionCode>> + Send

Write values to record_number in file file_number (Spec V1.1b3 §6.15).

The default returns ExceptionCode::IllegalFunction.

Source

fn write_file_record_be( &self, file_number: u16, record_number: u16, record_length: u16, value_bytes: &[u8], ) -> impl Future<Output = Result<(), ExceptionCode>> + Send

Write one file sub-record from big-endian Modbus wire bytes.

The default implementation unpacks the wire bytes and delegates to Self::write_file_record. Stores with direct file access can override this method to avoid the intermediate register vector.

Source

fn read_fifo_queue( &self, address: u16, ) -> impl Future<Output = Result<Vec<u16>, ExceptionCode>> + Send

Return a non-destructive snapshot of the FIFO queue whose pointer is at address (at most 31 values; Spec V1.1b3 §6.18 — reading the queue MUST NOT drain it).

The default returns ExceptionCode::IllegalDataAddress — there is no FIFO at the requested address (Figure 28).

Source

fn read_fifo_queue_be( &self, address: u16, out: &mut [u8], ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send

Read a FIFO queue snapshot directly into big-endian Modbus wire bytes.

The default implementation delegates to Self::read_fifo_queue and packs the returned values. Stores with direct queue access can override this method to avoid cloning the queue and allocating an intermediate byte buffer.

Source

fn read_exception_status( &self, ) -> impl Future<Output = Result<u8, ExceptionCode>> + Send

Read the eight device-specific exception-status coils as one byte (FC 0x07, §6.7). The default returns ExceptionCode::IllegalFunction.

Source

fn get_comm_event_counter( &self, ) -> impl Future<Output = Result<(u16, u16), ExceptionCode>> + Send

Get the comm event counter as (status, event_count) (FC 0x0B, §6.9). The default returns ExceptionCode::IllegalFunction.

Source

fn get_comm_event_log( &self, ) -> impl Future<Output = Result<CommEventLog, ExceptionCode>> + Send

Get the communications event log (FC 0x0C, §6.10). The default returns ExceptionCode::IllegalFunction.

Source

fn append_comm_event_log( &self, out: &mut Vec<u8>, ) -> impl Future<Output = Result<CommEventLogMeta, ExceptionCode>> + Send

Append FC 0x0C communication event bytes to out.

The default delegates to Self::get_comm_event_log. Direct-access stores can override this method to avoid materializing the event list in an intermediate Vec before response construction.

Source

fn report_server_id( &self, ) -> impl Future<Output = Result<Vec<u8>, ExceptionCode>> + Send

Report a device-specific server-identification blob (FC 0x11, §6.13).

The returned bytes become the response’s data field (the handler prepends the byte count). The default returns ExceptionCode::IllegalFunction.

Source

fn append_server_id( &self, out: &mut Vec<u8>, ) -> impl Future<Output = Result<usize, ExceptionCode>> + Send

Append the FC 0x11 server-identification data bytes to out.

The default delegates to Self::report_server_id. Direct-access stores can override this method to avoid cloning the identification blob before the handler copies it into the final response PDU.

Source

fn diagnostic( &self, sub_function: DiagnosticSubFunction, data: &[u8], ) -> impl Future<Output = Result<Option<Vec<u8>>, ExceptionCode>> + Send

Execute a Diagnostics sub-function (FC 0x08, §6.8).

Ok(Some(data)) echoes data back in the response; Ok(None) suppresses the response entirely (per the spec, e.g. Force Listen Only Mode); Err returns an exception.

The default loops back Return Query Data (0x0000) and reports every other sub-function as ExceptionCode::IllegalFunction (Figure 18: an unsupported sub-function is an illegal function, not an illegal data value).

Source

fn append_diagnostic_response( &self, sub_function: DiagnosticSubFunction, data: &[u8], out: &mut Vec<u8>, ) -> impl Future<Output = Result<Option<usize>, ExceptionCode>> + Send

Append Diagnostics response data bytes to out.

The default delegates to Self::diagnostic. Stores that can produce a response from borrowed request bytes can override this method to avoid an intermediate owned Vec before the handler builds the final response PDU.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§