DMSCFrameParser

Struct DMSCFrameParser 

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

Frame parser for reading and assembling protocol frames from stream data.

The DMSCFrameParser handles the incremental parsing of frame data from network streams or byte sources. Network protocols often deliver data in chunks that may not align with protocol frame boundaries. This parser accumulates incoming data in an internal buffer and extracts complete frames when sufficient data is available. It also manages sequence number validation to ensure frame ordering integrity.

§Parser Operation Model

Incoming Data:  [partial][complete][partial][complete][partial]
                     |         |        |         |
                     v         v        v         v
Parser Buffer:  [======][==========][=========][=======]
                     |         |        |
                     v         v        v
Extracted:      [Frame1] [Frame2] [Frame3]

§Sequence Number Validation

The parser maintains an expected sequence number counter. Each extracted frame must have a sequence number matching the expected value. This detects missing frames (gaps in sequence numbers) which may indicate packet loss. Use reset_sequence() to set a new expected sequence number, such as after reconnection.

§Buffer Management

The parser maintains an internal buffer that grows as data is added. For long-running connections, periodically check buffer_len() and consider calling clear_buffer() if buffer accumulation indicates parsing issues. The parser automatically removes parsed data from the buffer.

§Python Bindings

When compiled with the pyo3 feature, this struct provides Python bindings:

from dmsc import DMSCFrameParser

# Create parser for incoming stream data
parser = DMSCFrameParser.new()

# Simulate receiving data chunks
chunks = [
    frame1_bytes[:20],
    frame1_bytes[20:] + frame2_bytes[:30],
    frame2_bytes[30:] + frame3_bytes
]

for chunk in chunks:
    parser.add_data(chunk)
    while True:
        frame = parser.parse_frame()
        if frame is None:
            break
        print(f"Received frame: {frame.sequence_number()}")

print(f"Buffer contains {parser.buffer_len()} bytes")

§Examples

Basic frame parsing from stream data:

use dmsc::protocol::frames::{DMSCFrameParser, DMSCFrame};

let mut parser = DMSCFrameParser::new();

// Simulate receiving frame data in chunks
let frame1 = DMSCFrame::data_frame(b"First message".to_vec(), 0)
    .expect("Failed to create frame");
let frame2 = DMSCFrame::data_frame(b"Second message".to_vec(), 1)
    .expect("Failed to create frame");

let bytes1 = frame1.to_bytes().expect("Failed to serialize");
let bytes2 = frame2.to_bytes().expect("Failed to serialize");

// Add first chunk (partial frame)
parser.add_data(&bytes1[..20]);
assert!(parser.parse_frame().unwrap().is_none());

// Add second chunk (completes frame1, starts frame2)
parser.add_data(&bytes1[20..]);
let parsed = parser.parse_frame().unwrap().expect("Should have complete frame");
assert_eq!(parsed.sequence_number(), 0);

// Add remaining data
parser.add_data(&bytes2);
let parsed = parser.parse_frame().unwrap().expect("Should have complete frame");
assert_eq!(parsed.sequence_number(), 1);

Handling sequence number reset:

use dmsc::protocol::frames::DMSCFrameParser;

let mut parser = DMSCFrameParser::new();

// Parse some frames
parser.add_data(&some_data);
while let Ok(Some(frame)) = parser.parse_frame() {
    // Process frames
}

// Reset sequence number for new session
parser.reset_sequence();
parser.clear_buffer();

// Now expecting sequence 0 again
assert_eq!(parser.next_sequence, 0);

§Thread Safety

This struct is not thread-safe. Multiple threads should not concurrently access the same parser instance without external synchronization. For concurrent parsing, either use separate parser instances per thread or wrap access with a Mutex or RwLock.

§Performance Considerations

  • The parser uses Vec::extend_from_slice for efficient buffer appending
  • Frame extraction uses slice operations to avoid unnecessary copying
  • Buffer memory is only reclaimed when frames are successfully parsed
  • Large frames may cause temporary buffer growth; configure appropriate limits

Implementations§

Source§

impl DMSCFrameParser

Source

pub fn new() -> Self

Source

pub fn add_data(&mut self, data: &[u8])

Source

pub fn parse_frame(&mut self) -> DMSCResult<Option<DMSCFrame>>

Source

pub fn buffer_len(&self) -> usize

Source

pub fn clear_buffer(&mut self)

Source

pub fn reset_sequence(&mut self)

Trait Implementations§

Source§

impl<'py> IntoPyObject<'py> for DMSCFrameParser

Source§

type Target = DMSCFrameParser

The Python output type
Source§

type Output = Bound<'py, <DMSCFrameParser as IntoPyObject<'py>>::Target>

The smart pointer type to use. Read more
Source§

type Error = PyErr

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

fn into_pyobject( self, py: Python<'py>, ) -> Result<<Self as IntoPyObject<'_>>::Output, <Self as IntoPyObject<'_>>::Error>

Performs the conversion.
Source§

impl PyClass for DMSCFrameParser

Source§

type Frozen = False

Whether the pyclass is frozen. Read more
Source§

impl PyClassImpl for DMSCFrameParser

Source§

const IS_BASETYPE: bool = false

#[pyclass(subclass)]
Source§

const IS_SUBCLASS: bool = false

#[pyclass(extends=…)]
Source§

const IS_MAPPING: bool = false

#[pyclass(mapping)]
Source§

const IS_SEQUENCE: bool = false

#[pyclass(sequence)]
Source§

const IS_IMMUTABLE_TYPE: bool = false

#[pyclass(immutable_type)]
Source§

const RAW_DOC: &'static CStr = c"Frame parser for reading and assembling protocol frames from stream data.\n\nThe DMSCFrameParser handles the incremental parsing of frame data from network\nstreams or byte sources. Network protocols often deliver data in chunks that\nmay not align with protocol frame boundaries. This parser accumulates incoming\ndata in an internal buffer and extracts complete frames when sufficient data\nis available. It also manages sequence number validation to ensure frame\nordering integrity.\n\n## Parser Operation Model\n\n```\nIncoming Data: [partial][complete][partial][complete][partial]\n | | | |\n v v v v\nParser Buffer: [======][==========][=========][=======]\n | | |\n v v v\nExtracted: [Frame1] [Frame2] [Frame3]\n```\n\n## Sequence Number Validation\n\nThe parser maintains an expected sequence number counter. Each extracted frame\nmust have a sequence number matching the expected value. This detects missing\nframes (gaps in sequence numbers) which may indicate packet loss. Use\n`reset_sequence()` to set a new expected sequence number, such as after\nreconnection.\n\n## Buffer Management\n\nThe parser maintains an internal buffer that grows as data is added. For\nlong-running connections, periodically check `buffer_len()` and consider\ncalling `clear_buffer()` if buffer accumulation indicates parsing issues.\nThe parser automatically removes parsed data from the buffer.\n\n## Python Bindings\n\nWhen compiled with the `pyo3` feature, this struct provides Python bindings:\n```python\nfrom dmsc import DMSCFrameParser\n\n# Create parser for incoming stream data\nparser = DMSCFrameParser.new()\n\n# Simulate receiving data chunks\nchunks = [\n frame1_bytes[:20],\n frame1_bytes[20:] + frame2_bytes[:30],\n frame2_bytes[30:] + frame3_bytes\n]\n\nfor chunk in chunks:\n parser.add_data(chunk)\n while True:\n frame = parser.parse_frame()\n if frame is None:\n break\n print(f\"Received frame: {frame.sequence_number()}\")\n\nprint(f\"Buffer contains {parser.buffer_len()} bytes\")\n```\n\n# Examples\n\nBasic frame parsing from stream data:\n```rust,ignore\nuse dmsc::protocol::frames::{DMSCFrameParser, DMSCFrame};\n\nlet mut parser = DMSCFrameParser::new();\n\n// Simulate receiving frame data in chunks\nlet frame1 = DMSCFrame::data_frame(b\"First message\".to_vec(), 0)\n .expect(\"Failed to create frame\");\nlet frame2 = DMSCFrame::data_frame(b\"Second message\".to_vec(), 1)\n .expect(\"Failed to create frame\");\n\nlet bytes1 = frame1.to_bytes().expect(\"Failed to serialize\");\nlet bytes2 = frame2.to_bytes().expect(\"Failed to serialize\");\n\n// Add first chunk (partial frame)\nparser.add_data(&bytes1[..20]);\nassert!(parser.parse_frame().unwrap().is_none());\n\n// Add second chunk (completes frame1, starts frame2)\nparser.add_data(&bytes1[20..]);\nlet parsed = parser.parse_frame().unwrap().expect(\"Should have complete frame\");\nassert_eq!(parsed.sequence_number(), 0);\n\n// Add remaining data\nparser.add_data(&bytes2);\nlet parsed = parser.parse_frame().unwrap().expect(\"Should have complete frame\");\nassert_eq!(parsed.sequence_number(), 1);\n```\n\nHandling sequence number reset:\n```rust,ignore\nuse dmsc::protocol::frames::DMSCFrameParser;\n\nlet mut parser = DMSCFrameParser::new();\n\n// Parse some frames\nparser.add_data(&some_data);\nwhile let Ok(Some(frame)) = parser.parse_frame() {\n // Process frames\n}\n\n// Reset sequence number for new session\nparser.reset_sequence();\nparser.clear_buffer();\n\n// Now expecting sequence 0 again\nassert_eq!(parser.next_sequence, 0);\n```\n\n# Thread Safety\n\nThis struct is not thread-safe. Multiple threads should not concurrently\naccess the same parser instance without external synchronization. For\nconcurrent parsing, either use separate parser instances per thread or\nwrap access with a Mutex or RwLock.\n\n# Performance Considerations\n\n- The parser uses `Vec::extend_from_slice` for efficient buffer appending\n- Frame extraction uses slice operations to avoid unnecessary copying\n- Buffer memory is only reclaimed when frames are successfully parsed\n- Large frames may cause temporary buffer growth; configure appropriate limits\x00"

Docstring for the class provided on the struct or enum. Read more
Source§

const DOC: &'static CStr

Fully rendered class doc, including the text_signature if a constructor is defined. Read more
Source§

type BaseType = PyAny

Base class
Source§

type ThreadChecker = SendablePyClass<DMSCFrameParser>

This handles following two situations: Read more
Source§

type PyClassMutability = <<PyAny as PyClassBaseType>::PyClassMutability as PyClassMutability>::MutableChild

Immutable or mutable
Source§

type Dict = PyClassDummySlot

Specify this class has #[pyclass(dict)] or not.
Source§

type WeakRef = PyClassDummySlot

Specify this class has #[pyclass(weakref)] or not.
Source§

type BaseNativeType = PyAny

The closest native ancestor. This is PyAny by default, and when you declare #[pyclass(extends=PyDict)], it’s PyDict.
Source§

fn items_iter() -> PyClassItemsIter

Source§

fn lazy_type_object() -> &'static LazyTypeObject<Self>

§

fn dict_offset() -> Option<isize>

§

fn weaklist_offset() -> Option<isize>

Source§

impl PyTypeInfo for DMSCFrameParser

Source§

const NAME: &'static str = "DMSCFrameParser"

Class name.
Source§

const MODULE: Option<&'static str> = ::core::option::Option::None

Module name, if any.
Source§

fn type_object_raw(py: Python<'_>) -> *mut PyTypeObject

Returns the PyTypeObject instance for this type.
§

fn type_object(py: Python<'_>) -> Bound<'_, PyType>

Returns the safe abstraction over the type object.
§

fn is_type_of(object: &Bound<'_, PyAny>) -> bool

Checks if object is an instance of this type or a subclass of this type.
§

fn is_exact_type_of(object: &Bound<'_, PyAny>) -> bool

Checks if object is an instance of this type.
Source§

impl DerefToPyAny for DMSCFrameParser

Source§

impl ExtractPyClassWithClone for DMSCFrameParser

Auto Trait Implementations§

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
§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

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.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<'py, T> IntoPyObjectExt<'py> for T
where T: IntoPyObject<'py>,

§

fn into_bound_py_any(self, py: Python<'py>) -> Result<Bound<'py, PyAny>, PyErr>

Converts self into an owned Python object, dropping type information.
§

fn into_py_any(self, py: Python<'py>) -> Result<Py<PyAny>, PyErr>

Converts self into an owned Python object, dropping type information and unbinding it from the 'py lifetime.
§

fn into_pyobject_or_pyerr(self, py: Python<'py>) -> Result<Self::Output, PyErr>

Converts self into a Python object. Read more
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> PyErrArguments for T
where T: for<'py> IntoPyObject<'py> + Send + Sync,

§

fn arguments(self, py: Python<'_>) -> Py<PyAny>

Arguments for exception
§

impl<T> PyTypeCheck for T
where T: PyTypeInfo,

§

const NAME: &'static str = T::NAME

👎Deprecated since 0.27.0: Use ::classinfo_object() instead and format the type name at runtime. Note that using built-in cast features is often better than manual PyTypeCheck usage.
Name of self. This is used in error messages, for example.
§

fn type_check(object: &Bound<'_, PyAny>) -> bool

Checks if object is an instance of Self, which may include a subtype. Read more
§

fn classinfo_object(py: Python<'_>) -> Bound<'_, PyAny>

Returns the expected type as a possible argument for the isinstance and issubclass function. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

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

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<T> Ungil for T
where T: Send,