Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 49 additions & 4 deletions crates/kernel_cmdline/src/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ use anyhow::Result;
#[derive(Clone, Debug, Default)]
pub struct Cmdline<'a>(Cow<'a, [u8]>);

/// An owned Cmdline. Alias for `Cmdline<'static>`.
pub type CmdlineOwned = Cmdline<'static>;

impl<'a, T: AsRef<[u8]> + ?Sized> From<&'a T> for Cmdline<'a> {
/// Creates a new `Cmdline` from any type that can be referenced as bytes.
///
Expand All @@ -27,7 +30,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> From<&'a T> for Cmdline<'a> {
}
}

impl<'a> From<Vec<u8>> for Cmdline<'a> {
impl From<Vec<u8>> for CmdlineOwned {
/// Creates a new `Cmdline` from an owned `Vec<u8>`.
fn from(input: Vec<u8>) -> Self {
Self(Cow::Owned(input))
Expand Down Expand Up @@ -85,7 +88,7 @@ impl<'a> Cmdline<'a> {
/// Creates a new empty owned `Cmdline`.
///
/// This is equivalent to `Cmdline::default()` but makes ownership explicit.
pub fn new() -> Cmdline<'static> {
pub fn new() -> CmdlineOwned {
Cmdline::default()
}

Expand Down Expand Up @@ -294,6 +297,29 @@ impl<'a> Cmdline<'a> {
removed
}

/// Remove all parameters that exactly match the given parameter
/// from the command line
///
/// Returns `true` if parameter(s) were removed.
pub fn remove_exact(&mut self, param: &Parameter) -> bool {
let mut removed = false;
let mut new_params = Vec::new();

for p in self.iter() {
if p == *param {
removed = true;
} else {
new_params.push(p.parameter);
}
}

if removed {
self.0 = Cow::Owned(new_params.join(b" ".as_slice()));
}

removed
}

#[cfg(test)]
pub(crate) fn is_owned(&self) -> bool {
matches!(self.0, Cow::Owned(_))
Expand Down Expand Up @@ -647,8 +673,8 @@ mod tests {
assert_eq!(kargs.iter().next(), None);
assert!(kargs.is_owned());

// Verify we can store it in a 'static context
let _static_kargs: Cmdline<'static> = Cmdline::new();
// Verify we can store it in an owned ('static) context
let _static_kargs: CmdlineOwned = Cmdline::new();
}

#[test]
Expand Down Expand Up @@ -904,6 +930,25 @@ mod tests {
assert_eq!(iter.next(), None);
}

#[test]
fn test_remove_exact() {
let mut kargs = Cmdline::from(b"foo foo=bar foo=baz");

// remove existing
assert!(kargs.remove_exact(&param("foo=bar")));
let mut iter = kargs.iter();
assert_eq!(iter.next(), Some(param("foo")));
assert_eq!(iter.next(), Some(param("foo=baz")));
assert_eq!(iter.next(), None);

// doesn't exist? returns false and doesn't modify anything
assert!(!kargs.remove_exact(&param("foo=wuz")));
iter = kargs.iter();
assert_eq!(iter.next(), Some(param("foo")));
assert_eq!(iter.next(), Some(param("foo=baz")));
assert_eq!(iter.next(), None);
}

#[test]
fn test_extend() {
let mut kargs = Cmdline::from(b"foo=bar baz");
Expand Down
38 changes: 34 additions & 4 deletions crates/kernel_cmdline/src/utf8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ use anyhow::Result;
#[derive(Clone, Debug, Default)]
pub struct Cmdline<'a>(bytes::Cmdline<'a>);

/// An owned `Cmdline`. Alias for `Cmdline<'static>`.
pub type CmdlineOwned = Cmdline<'static>;

impl<'a, T: AsRef<str> + ?Sized> From<&'a T> for Cmdline<'a> {
/// Creates a new `Cmdline` from any type that can be referenced as `str`.
///
Expand All @@ -26,7 +29,7 @@ impl<'a, T: AsRef<str> + ?Sized> From<&'a T> for Cmdline<'a> {
}
}

impl From<String> for Cmdline<'static> {
impl From<String> for CmdlineOwned {
/// Creates a new `Cmdline` from a `String`.
///
/// Takes ownership of input and maintains it for internal owned data.
Expand Down Expand Up @@ -72,7 +75,7 @@ impl<'a> Cmdline<'a> {
/// Creates a new empty owned `Cmdline`.
///
/// This is equivalent to `Cmdline::default()` but makes ownership explicit.
pub fn new() -> Cmdline<'static> {
pub fn new() -> CmdlineOwned {
Cmdline::default()
}

Expand Down Expand Up @@ -191,6 +194,14 @@ impl<'a> Cmdline<'a> {
self.0.remove(&key.0)
}

/// Remove all parameters that exactly match the given parameter
/// from the command line
///
/// Returns `true` if parameter(s) were removed.
pub fn remove_exact(&mut self, param: &Parameter) -> bool {
self.0.remove_exact(&param.0)
}

#[cfg(test)]
pub(crate) fn is_owned(&self) -> bool {
self.0.is_owned()
Expand Down Expand Up @@ -569,8 +580,8 @@ mod tests {
assert_eq!(kargs.iter().next(), None);
assert!(kargs.is_owned());

// Verify we can store it in a 'static context
let _static_kargs: Cmdline<'static> = Cmdline::new();
// Verify we can store it in an owned ('static) context
let _static_kargs: CmdlineOwned = Cmdline::new();
}

#[test]
Expand Down Expand Up @@ -829,6 +840,25 @@ mod tests {
assert_eq!(iter.next(), None);
}

#[test]
fn test_remove_exact() {
let mut kargs = Cmdline::from("foo foo=bar foo=baz");

// remove existing
assert!(kargs.remove_exact(&param("foo=bar")));
let mut iter = kargs.iter();
assert_eq!(iter.next(), Some(param("foo")));
assert_eq!(iter.next(), Some(param("foo=baz")));
assert_eq!(iter.next(), None);

// doesn't exist? returns false and doesn't modify anything
assert!(!kargs.remove_exact(&param("foo=wuz")));
iter = kargs.iter();
assert_eq!(iter.next(), Some(param("foo")));
assert_eq!(iter.next(), Some(param("foo=baz")));
assert_eq!(iter.next(), None);
}

#[test]
fn test_extend() {
let mut kargs = Cmdline::from("foo=bar baz");
Expand Down
Loading
Loading