mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
option_parser: Add documentation strings
Autogenerated with Claude Opus 4.6 and reviewed with human eyes. Signed-off-by: Rob Bradford <rbradford@meta.com>
This commit is contained in:
@@ -3,6 +3,29 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
//! A parser for comma-separated `key=value` option strings.
|
||||
//!
|
||||
//! This crate provides [`OptionParser`], which parses strings of the form
|
||||
//! `"key1=value1,key2=value2,..."` into a set of named options that can then
|
||||
//! be retrieved and converted to various types.
|
||||
//!
|
||||
//! Values may be quoted with `"` to embed commas and other special characters,
|
||||
//! and brackets `[` `]` are tracked so that list-valued options like
|
||||
//! `topology=[1,2,3]` are not split at inner commas.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use option_parser::OptionParser;
|
||||
//!
|
||||
//! let mut parser = OptionParser::new();
|
||||
//! parser.add("size").add("mergeable");
|
||||
//! parser.parse("size=128M,mergeable=on").unwrap();
|
||||
//!
|
||||
//! assert_eq!(parser.get("size"), Some("128M".to_owned()));
|
||||
//! assert_eq!(parser.get("mergeable"), Some("on".to_owned()));
|
||||
//! ```
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{Display, Write};
|
||||
use std::num::ParseIntError;
|
||||
@@ -27,6 +50,12 @@ mod private_trait {
|
||||
}
|
||||
use private_trait::Parseable;
|
||||
|
||||
/// A parser for comma-separated `key=value` option strings.
|
||||
///
|
||||
/// Options must be registered with [`add`](Self::add) or
|
||||
/// [`add_valueless`](Self::add_valueless) before parsing. After calling
|
||||
/// [`parse`](Self::parse), values can be retrieved with [`get`](Self::get)
|
||||
/// or converted to a specific type with [`convert`](Self::convert).
|
||||
#[derive(Default)]
|
||||
pub struct OptionParser {
|
||||
options: HashMap<String, OptionParserValue>,
|
||||
@@ -37,14 +66,19 @@ struct OptionParserValue {
|
||||
requires_value: bool,
|
||||
}
|
||||
|
||||
/// Errors returned when parsing or converting options.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum OptionParserError {
|
||||
/// An option name was not previously registered with [`OptionParser::add`].
|
||||
#[error("unknown option: {0}")]
|
||||
UnknownOption(String),
|
||||
/// The input string has invalid syntax (unbalanced quotes/brackets, missing `=`).
|
||||
#[error("unknown option: {0}")]
|
||||
InvalidSyntax(String),
|
||||
/// A value could not be converted to the requested type.
|
||||
#[error("unable to convert {1} for {0}")]
|
||||
Conversion(String /* field */, String /* value */),
|
||||
/// A value was syntactically valid but semantically wrong.
|
||||
#[error("invalid value: {0}")]
|
||||
InvalidValue(String),
|
||||
}
|
||||
@@ -87,6 +121,7 @@ fn split_commas(s: &str) -> OptionParserResult<Vec<String>> {
|
||||
}
|
||||
|
||||
impl OptionParser {
|
||||
/// Creates an empty `OptionParser` with no registered options.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
options: HashMap::new(),
|
||||
@@ -122,14 +157,30 @@ impl OptionParser {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Parses a comma-separated `key=value` string, updating registered options.
|
||||
///
|
||||
/// Returns an error if the input contains an unknown option name, has
|
||||
/// unbalanced quotes or brackets, or a value-requiring option lacks `=`.
|
||||
pub fn parse(&mut self, input: &str) -> OptionParserResult<()> {
|
||||
self.parse_inner(input, false)
|
||||
}
|
||||
|
||||
/// Like [`parse`](Self::parse), but silently ignores unknown option names.
|
||||
///
|
||||
/// This is useful when multiple parsers share the same input string and
|
||||
/// each only cares about a subset of the options.
|
||||
pub fn parse_subset(&mut self, input: &str) -> OptionParserResult<()> {
|
||||
self.parse_inner(input, true)
|
||||
}
|
||||
|
||||
/// Registers a named option that requires a value (i.e. `key=value`).
|
||||
///
|
||||
/// Option names must not contain `"`, `[`, `]`, `=`, or `,`.
|
||||
/// Returns `&mut Self` for chaining.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the option name contains a forbidden character.
|
||||
pub fn add(&mut self, option: &str) -> &mut Self {
|
||||
// Check that option=value has balanced
|
||||
// quotes and brackets iff value does.
|
||||
@@ -148,6 +199,9 @@ impl OptionParser {
|
||||
self
|
||||
}
|
||||
|
||||
/// Registers multiple value-requiring options at once.
|
||||
///
|
||||
/// Equivalent to calling [`add`](Self::add) for each element in the slice.
|
||||
pub fn add_all(&mut self, options: &[&str]) -> &mut Self {
|
||||
for option in options {
|
||||
self.add(option);
|
||||
@@ -156,6 +210,10 @@ impl OptionParser {
|
||||
self
|
||||
}
|
||||
|
||||
/// Registers a flag-style option that does not take a value.
|
||||
///
|
||||
/// When this option appears in the input string (without `=`), it is
|
||||
/// marked as set. Use [`is_set`](Self::is_set) to query it.
|
||||
pub fn add_valueless(&mut self, option: &str) -> &mut Self {
|
||||
self.options.insert(
|
||||
option.to_owned(),
|
||||
@@ -168,6 +226,10 @@ impl OptionParser {
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns the raw string value of an option, or `None` if the option was
|
||||
/// not set or if its value is an empty string (e.g. `key=`).
|
||||
///
|
||||
/// Surrounding double-quotes in the value are removed.
|
||||
pub fn get(&self, option: &str) -> Option<String> {
|
||||
self.options
|
||||
.get(option)
|
||||
@@ -181,6 +243,9 @@ impl OptionParser {
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns `true` if the option was present in the parsed input.
|
||||
///
|
||||
/// This works for both value-requiring and valueless options.
|
||||
pub fn is_set(&self, option: &str) -> bool {
|
||||
self.options
|
||||
.get(option)
|
||||
@@ -188,6 +253,14 @@ impl OptionParser {
|
||||
.is_some()
|
||||
}
|
||||
|
||||
/// Retrieves and converts an option value to type `T`.
|
||||
///
|
||||
/// Returns `Ok(None)` if the option was not set or its value is empty.
|
||||
/// Returns `Err` if the value cannot be converted to `T`.
|
||||
///
|
||||
/// `T` can be any type that implements `FromStr` (e.g. `u32`, `String`),
|
||||
/// or one of this crate's types such as [`Toggle`], [`IntegerList`],
|
||||
/// [`Tuple`], or [`StringList`].
|
||||
pub fn convert<T: Parseable>(&self, option: &str) -> OptionParserResult<Option<T>> {
|
||||
match self.options.get(option).and_then(|v| v.value.as_ref()) {
|
||||
None => Ok(None),
|
||||
@@ -204,6 +277,9 @@ impl OptionParser {
|
||||
}
|
||||
}
|
||||
|
||||
/// A boolean-like value that accepts `"on"`, `"true"`, `"off"`, `"false"`, or `""`.
|
||||
///
|
||||
/// An empty string is treated as `false`.
|
||||
pub struct Toggle(pub bool);
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@@ -227,6 +303,10 @@ impl Parseable for Toggle {
|
||||
}
|
||||
}
|
||||
|
||||
/// A byte size parsed from a human-readable string with optional `K`, `M`, or `G` suffix.
|
||||
///
|
||||
/// The suffix is binary (1K = 1024, 1M = 1048576, 1G = 1073741824).
|
||||
/// A bare integer is treated as bytes.
|
||||
pub struct ByteSized(pub u64);
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@@ -259,6 +339,9 @@ impl FromStr for ByteSized {
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of integers parsed from a bracket-enclosed, comma-separated string.
|
||||
///
|
||||
/// Ranges are supported with `-`: `"[0,2-4,6]"` produces `[0, 2, 3, 4, 6]`.
|
||||
pub struct IntegerList(pub Vec<u64>);
|
||||
|
||||
impl Display for IntegerList {
|
||||
@@ -324,7 +407,11 @@ impl Parseable for IntegerList {
|
||||
}
|
||||
}
|
||||
|
||||
/// Types that can appear as the second element of a [`Tuple`] pair.
|
||||
///
|
||||
/// Implemented for `u64`, `Vec<u8>`, `Vec<u64>`, and `Vec<usize>`.
|
||||
pub trait TupleValue {
|
||||
/// Parses the value portion of a `key@value` tuple element.
|
||||
fn parse_value(input: &str) -> Result<Self, TupleError>
|
||||
where
|
||||
Self: Sized;
|
||||
@@ -366,6 +453,10 @@ impl TupleValue for Vec<usize> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of `key@value` pairs parsed from a bracket-enclosed string.
|
||||
///
|
||||
/// The format is `[key1@value1,key2@value2,...]` where `@` separates each
|
||||
/// pair's elements. `S` is the key type and `T` is the value type.
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub struct Tuple<S, T>(pub Vec<(S, T)>);
|
||||
|
||||
@@ -421,6 +512,9 @@ impl<S: Parseable, T: TupleValue> Parseable for Tuple<S, T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of strings parsed from a bracket-enclosed, comma-separated string.
|
||||
///
|
||||
/// The format is `[str1,str2,...]`. Brackets are optional.
|
||||
#[derive(Default)]
|
||||
pub struct StringList(pub Vec<String>);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user