Skip to content

Latest commit

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

no-std-repl

Minimal no_std building blocks for serial REPL interfaces on MCUs.

This crate does not provide I/O, command dispatch, or editing beyond single-byte backspace handling. It focuses on the byte-to-line and line-to-parts steps that are awkward to rewrite in every embedded project.

Usage

# use core::fmt;
# traitSerial: fmt::Write{
# fntry_read(&mutself) -> Option<u8>;
# fnwrite(&mutself,byte:u8);
# }use no_std_repl::{LineBuffer,Outcome,Parts};fnrepl_loop(serial:&mutimplSerial){letmut line = LineBuffer::<128>::new();loop{write!(serial,"> ").ok();// Read until newlineloop{ifletSome(byte) = serial.try_read(){
serial.write(byte);// echomatch line.push(byte){Outcome::Continue => {}Outcome::LineComplete => {writeln!(serial).ok();break;}Outcome::BufferFull => {writeln!(serial,"\r\nline too long").ok();
line.clear();break;}}}}let s = match line.as_str(){Some(s) => s,None => {writeln!(serial,"invalid input").ok();
line.clear();continue;}};// Pattern match on command partslet parts = Parts::<8>::parse(s);if parts.is_truncated(){writeln!(serial,"too many arguments").ok();
line.clear();continue;}match parts.as_slice(){["ping"] => {writeln!(serial,"pong").ok();}["ping", n] => {ifletOk(v) = n.parse::<u32>(){writeln!(serial,"ping {v}").ok();}else{writeln!(serial,"bad number: {n}").ok();}}["set", key, value] => {writeln!(serial,"setting {key} = {value}").ok();}["help"] => {writeln!(serial,"commands: ping, set <key> <value>, help").ok();}[] => {}
other => {writeln!(serial,"unknown: {other:?}").ok();}}
line.clear();}}
# fnmain(){}

Design

Three types, zero dependencies, zero allocations:

  • LineBuffer<N> - Accumulates bytes until newline, handles backspace and CR+LF coalescing
  • Parts<'a, N> - Parses a line into parts for slice pattern matching
  • Outcome - Push result: Continue, LineComplete, or BufferFull

The pattern matching syntax (["cmd", arg1, arg2]) is standard Rust slice patterns.

Behavior Notes

  • Line endings: \r, \n, and \r\n all terminate the line. The terminator is not stored in the buffer.
  • Backspace: both 0x08 and 0x7F remove one buffered byte if present.
  • UTF-8: LineBuffer::as_str() returns None for invalid UTF-8, but LineBuffer::as_bytes() always exposes the raw bytes.
  • Part limit: Parts::<N>::parse() keeps at most N whitespace-separated parts. If additional parts were present, Parts::is_truncated() returns true.

Example

Run the host-side demo:

cargo run --example host_repl

See examples/host_repl.rs for a complete byte-by-byte REPL loop.

About

Minimal `no_std` building blocks for serial REPL interfaces on MCUs.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages