Skip to content

Instantly share code, notes, and snippets.

@zombiezen
Created February 12, 2018 16:53
Show Gist options
  • Save zombiezen/802979e9d64bd82ad76760ad9675a3de to your computer and use it in GitHub Desktop.
Save zombiezen/802979e9d64bd82ad76760ad9675a3de to your computer and use it in GitHub Desktop.
use std::convert::AsRef;
use std::ffi::OsStr;
#[derive(Clone, Debug)]
#[must_use = "join_args is lazy and does nothing unless consumed"]
pub struct JoinArgs<A, B> {
a: A,
b: B,
state: JoinState,
}
#[derive(Clone, Debug)]
enum JoinState {
Both,
Front,
Back,
}
/// Chains two iterable argument lists.
pub fn join_args<I1, I2>(iter1: I1, iter2: I2) -> JoinArgs<I1::IntoIter, I2::IntoIter>
where
I1: IntoIterator,
I2: IntoIterator,
{
JoinArgs {
a: iter1.into_iter(),
b: iter2.into_iter(),
state: JoinState::Both,
}
}
impl<'a, 'b, A, B, S1, S2> Iterator for JoinArgs<A, B>
where
'b: 'a,
A: Iterator<Item = &'a S1>,
S1: AsRef<OsStr> + 'a,
B: Iterator<Item = &'b S2>,
S2: AsRef<OsStr> + 'b,
{
type Item = &'a OsStr;
fn next(&mut self) -> Option<Self::Item> {
match self.state {
JoinState::Both => match self.a.next() {
Some(x) => Some(x.as_ref()),
None => {
self.state = JoinState::Back;
self.b.next().map(AsRef::as_ref)
}
},
JoinState::Front => self.a.next().map(AsRef::as_ref),
JoinState::Back => self.b.next().map(AsRef::as_ref),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::ffi::OsString;
#[test]
fn test_join_args() {
let a = &[OsStr::new("abc"), OsStr::new("def")];
let b = vec![OsString::from("ghi")];
let result: Vec<&OsStr> = join_args(a, &b).collect();
assert_eq!(
result,
[OsStr::new("abc"), OsStr::new("def"), OsStr::new("ghi"),]
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment