ControlLine

Struct ControlLine 

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

A single line from a control protocol response with parsing utilities.

ControlLine provides methods for parsing space-delimited entries from control protocol response lines. It maintains internal state to track the unparsed remainder, allowing sequential extraction of values.

§Parsing Model

The line is treated as a sequence of space-separated entries that can be “popped” from left to right. Each pop operation:

  1. Extracts the next entry (optionally handling quotes and escapes)
  2. Updates the internal remainder to exclude the extracted entry
  3. Returns the extracted value

§Entry Types

  • Simple values: Space-separated tokens (e.g., PROTOCOLINFO 1)
  • Quoted values: Values enclosed in double quotes (e.g., "hello world")
  • Key-value mappings: KEY=VALUE pairs (e.g., Tor="0.4.7.8")
  • Escaped values: Values with backslash escapes (e.g., "path\\to\\file")

§Thread Safety

ControlLine uses internal synchronization (Mutex) for its mutable parsing state, making it safe to share across threads. However, concurrent pops from multiple threads will produce unpredictable results.

§Example

use stem_rs::response::ControlLine;

let mut line = ControlLine::new("AUTH METHODS=COOKIE,PASSWORD VERSION=\"1.0\"");

// Pop simple value
assert_eq!(line.pop(false, false).unwrap(), "AUTH");

// Pop key-value mapping
let (key, value) = line.pop_mapping(false, false).unwrap();
assert_eq!(key, "METHODS");
assert_eq!(value, "COOKIE,PASSWORD");

// Pop quoted key-value mapping
let (key, value) = line.pop_mapping(true, false).unwrap();
assert_eq!(key, "VERSION");
assert_eq!(value, "1.0");

assert!(line.is_empty());

Implementations§

Source§

impl ControlLine

Source

pub fn new(content: &str) -> Self

Creates a new ControlLine from the given content.

The entire content is initially available as the remainder for parsing.

§Arguments
  • content - The line content to parse
§Example
use stem_rs::response::ControlLine;

let line = ControlLine::new("KEY=value more data");
assert_eq!(line.remainder(), "KEY=value more data");
Source

pub fn remainder(&self) -> String

Returns the unparsed remainder of the line.

This is the portion of the line that hasn’t been consumed by pop or pop_mapping calls.

§Returns

The remaining unparsed content as a string.

§Example
use stem_rs::response::ControlLine;

let mut line = ControlLine::new("first second third");
assert_eq!(line.remainder(), "first second third");

line.pop(false, false).unwrap();
assert_eq!(line.remainder(), "second third");
Source

pub fn is_empty(&self) -> bool

Checks if there is no remaining content to parse.

§Returns

true if the remainder is empty, false otherwise.

§Example
use stem_rs::response::ControlLine;

let mut line = ControlLine::new("single");
assert!(!line.is_empty());

line.pop(false, false).unwrap();
assert!(line.is_empty());
Source

pub fn is_next_quoted(&self, escaped: bool) -> bool

Checks if the next entry is a quoted value.

A quoted value starts with a double quote (") and has a matching closing quote.

§Arguments
  • escaped - If true, handles backslash-escaped quotes within the value
§Returns

true if the next entry can be parsed as a quoted value, false otherwise.

§Example
use stem_rs::response::ControlLine;

let line = ControlLine::new("\"quoted value\" unquoted");
assert!(line.is_next_quoted(false));

let line = ControlLine::new("unquoted \"quoted\"");
assert!(!line.is_next_quoted(false));
Source

pub fn is_next_mapping( &self, key: Option<&str>, quoted: bool, escaped: bool, ) -> bool

Checks if the next entry is a KEY=VALUE mapping.

§Arguments
  • key - If Some, checks that the key matches this specific value
  • quoted - If true, checks that the value is quoted
  • escaped - If true, handles backslash escapes in quoted values
§Returns

true if the next entry is a valid KEY=VALUE mapping matching the criteria.

§Example
use stem_rs::response::ControlLine;

let line = ControlLine::new("KEY=value OTHER=stuff");

// Check for any mapping
assert!(line.is_next_mapping(None, false, false));

// Check for specific key
assert!(line.is_next_mapping(Some("KEY"), false, false));
assert!(!line.is_next_mapping(Some("OTHER"), false, false));

// Check for quoted value
let line = ControlLine::new("KEY=\"quoted\"");
assert!(line.is_next_mapping(Some("KEY"), true, false));
Source

pub fn peek_key(&self) -> Option<String>

Returns the key of the next entry without consuming it.

If the next entry is a KEY=VALUE mapping, returns the key portion. Otherwise returns None.

§Returns

Some(key) if the next entry is a mapping, None otherwise.

§Example
use stem_rs::response::ControlLine;

let line = ControlLine::new("MYKEY=myvalue");
assert_eq!(line.peek_key(), Some("MYKEY".to_string()));

let line = ControlLine::new("no_equals_here");
assert!(line.peek_key().is_none());
Source

pub fn pop(&mut self, quoted: bool, escaped: bool) -> Result<String, Error>

Removes and returns the next space-separated entry.

This method extracts the next entry from the remainder, handling optional quoting and escape sequences.

§Arguments
  • quoted - If true, parses the entry as a quoted value (removes quotes)
  • escaped - If true, processes backslash escape sequences
§Escape Sequences

When escaped is true, the following sequences are processed:

  • \\n → newline
  • \\r → carriage return
  • \\t → tab
  • \\\\ → backslash
  • \\" → double quote
§Errors

Returns Error::Protocol if:

  • No remaining content to parse
  • quoted is true but the next entry isn’t quoted
§Example
use stem_rs::response::ControlLine;

let mut line = ControlLine::new("\"We're all mad here.\" says the cat.");

// Pop quoted value
assert_eq!(line.pop(true, false).unwrap(), "We're all mad here.");

// Pop unquoted value
assert_eq!(line.pop(false, false).unwrap(), "says");

// Check remainder
assert_eq!(line.remainder(), "the cat.");
Source

pub fn pop_mapping( &mut self, quoted: bool, escaped: bool, ) -> Result<(String, String), Error>

Removes and returns the next entry as a KEY=VALUE mapping.

Parses the next entry expecting a KEY=VALUE format and returns both the key and value as separate strings.

§Arguments
  • quoted - If true, the value is expected to be quoted
  • escaped - If true, processes backslash escape sequences in the value
§Errors

Returns Error::Protocol if:

  • No remaining content to parse
  • The next entry isn’t a KEY=VALUE mapping
  • quoted is true but the value isn’t quoted
§Example
use stem_rs::response::ControlLine;

let mut line = ControlLine::new("Tor=\"0.4.7.8\" other=value");

// Pop quoted mapping
let (key, value) = line.pop_mapping(true, false).unwrap();
assert_eq!(key, "Tor");
assert_eq!(value, "0.4.7.8");

// Pop unquoted mapping
let (key, value) = line.pop_mapping(false, false).unwrap();
assert_eq!(key, "other");
assert_eq!(value, "value");
Source

pub fn pop_mapping_bytes( &mut self, quoted: bool, escaped: bool, ) -> Result<(String, Vec<u8>), Error>

Removes and returns the next entry as a KEY=VALUE mapping with raw bytes.

Similar to pop_mapping, but returns the value as raw bytes instead of a string. Useful when the value may contain binary data or when exact byte preservation is required.

§Arguments
  • quoted - If true, the value is expected to be quoted
  • escaped - If true, processes backslash escape sequences in the value
§Errors

Returns Error::Protocol if:

  • No remaining content to parse
  • The next entry isn’t a KEY=VALUE mapping
  • quoted is true but the value isn’t quoted
§Example
use stem_rs::response::ControlLine;

let mut line = ControlLine::new("DATA=binary_content");
let (key, value_bytes) = line.pop_mapping_bytes(false, false).unwrap();
assert_eq!(key, "DATA");
assert_eq!(value_bytes, b"binary_content");

Trait Implementations§

Source§

impl AsRef<str> for ControlLine

Source§

fn as_ref(&self) -> &str

Converts this type into a shared reference of the (usually inferred) input type.
Source§

impl Clone for ControlLine

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ControlLine

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ControlLine

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

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
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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
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.