mikrotik-proto
Sans-IO protocol implementation for the MikroTik RouterOS API.
This crate provides a runtime-agnostic, #![no_std]-compatible implementation of the MikroTik wire protocol. It handles encoding, decoding, command building, response parsing, and connection state management.
If you just want to talk to a router, use mikrotik-rs instead. This crate is for building your own runtime adapter or embedding the protocol in constrained environments.
Highlights
#![no_std]— only depends onalloc. Nostd, no OS, no runtime.- Zero-copy parsing — words are parsed lazily from the receive buffer with byte-level dispatch (no redundant UTF-8 validation).
- Typestate command builder — the compiler enforces correct command construction order.
- Compile-time validation — the
command!macro validates RouterOS command paths at compile time. - Connection state machine — multiplexes concurrent commands over a single connection via tags.
- Typestate login handshake — the type system enforces that authentication completes before commands can be sent.
- No
unsafecode —unsafe_code = "forbid"is enforced at the workspace level.
Usage pattern
The Connection type mirrors the design of quinn-proto: you feed it bytes, poll for outbound data, and poll for application events.
use ;
use CommandBuilder;
let mut conn = new;
// Build and send a command
let cmd = new
.command
.build;
let tag = conn.send_command.unwrap;
// In your event loop:
// 1. Drain outbound data and write it to your transport
while let Some = conn.poll_transmit
// 2. Feed incoming bytes from the transport
// conn.receive(&incoming_bytes).unwrap();
// 3. Process application events
while let Some = conn.poll_event
Login handshake
The Handshaking / Authenticated typestate enforces that you cannot send commands before logging in:
use ;
let mut hs = new.unwrap;
// 1. Send login bytes
while let Some = hs.poll_transmit
// 2. Feed response bytes and advance
// hs.receive(&response_bytes).unwrap();
// match hs.advance().unwrap() {
// LoginProgress::Pending(h) => hs = h,
// LoginProgress::Complete(auth) => {
// let conn = auth.into_connection();
// // now you can send_command()
// }
// }
Architecture
┌─────────────────────────────────────────┐
│ mikrotik-proto │
│ │
&[u8] from ───────────┤ ┌───────────────────┐ ┌──────┐│
transport │ │ codec │────────▶│ word ││
│ │ (RawSentence + │ └──────┘│
│ │ typed_words()) │ │ │
│ └───────────────────┘ │ │
│ │ │ │
│ │ decode ┌──────────┐ │parse│
│ ├───────────▶│ response │◀───┘ │
│ │ └──────────┘ │
│ │ │ │
│ │ encode ┌─────▼──────┐ │
│ ◀────────────┤ connection │ │
│ ┌───────┐ │ │ │
│ │command│───────▶│ state mgmt │ │
│ └───────┘ │ mux/demux │ │
│ └─────┬──────┘ │
│ │ │
│ ┌─────────┐ wraps │ │
│ │handshake│◀───────────┘ │
│ └─────────┘ │
│ │ │
├──────┼──────────────────────────────────┤
│ ▼ │
│ poll_transmit() ──▶ Vec<u8> to transport
│ poll_event() ──▶ Event to application
└─────────────────────────────────────────┘
License
Licensed under either of MIT or Apache-2.0 at your option.