Skip to content

Commit

Permalink
Add iter and iter_mut to LanguageRange
Browse files Browse the repository at this point in the history
  • Loading branch information
vodik committed Feb 6, 2022
1 parent e361b11 commit efe6ea4
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 6 deletions.
123 changes: 121 additions & 2 deletions src/language/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,35 @@ use crate::headers::HeaderValue;
use std::{
borrow::Cow,
fmt::{self, Display},
slice,
str::FromStr,
};

/// An RFC 4647 language range.
#[derive(Debug, Clone, PartialEq)]
pub struct LanguageRange {
pub(crate) tags: Vec<Cow<'static, str>>,
pub(crate) subtags: Vec<Cow<'static, str>>,
}

impl LanguageRange {
/// An iterator visiting all entries.
pub fn iter(&self) -> Iter<'_> {
Iter {
inner: self.subtags.iter(),
}
}

/// An iterator visiting all entries.
pub fn iter_mut(&mut self) -> IterMut<'_> {
IterMut {
inner: self.subtags.iter_mut(),
}
}
}

impl Display for LanguageRange {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut tags = self.tags.iter();
let mut tags = self.subtags.iter();
if let Some(tag) = tags.next() {
write!(f, "{}", tag)?;

Expand All @@ -31,6 +48,95 @@ impl Display for LanguageRange {
}
}

/// A borrowing iterator over entries in `LanguageRange`.
#[derive(Debug)]
pub struct IntoIter {
inner: std::vec::IntoIter<Cow<'static, str>>,
}

impl Iterator for IntoIter {
type Item = Cow<'static, str>;

fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}

/// A lending iterator over entries in `LanguageRange`.
#[derive(Debug)]
pub struct Iter<'a> {
inner: slice::Iter<'a, Cow<'static, str>>,
}

impl<'a> Iterator for Iter<'a> {
type Item = &'a Cow<'static, str>;

fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}

/// A mutable iterator over entries in `LanguageRange`.
#[derive(Debug)]
pub struct IterMut<'a> {
inner: slice::IterMut<'a, Cow<'static, str>>,
}

impl<'a> Iterator for IterMut<'a> {
type Item = &'a mut Cow<'static, str>;

fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}

impl IntoIterator for LanguageRange {
type Item = Cow<'static, str>;
type IntoIter = IntoIter;

#[inline]
fn into_iter(self) -> Self::IntoIter {
IntoIter {
inner: self.subtags.into_iter(),
}
}
}

impl<'a> IntoIterator for &'a LanguageRange {
type Item = &'a Cow<'static, str>;
type IntoIter = Iter<'a>;

#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}

impl<'a> IntoIterator for &'a mut LanguageRange {
type Item = &'a mut Cow<'static, str>;
type IntoIter = IterMut<'a>;

#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}

impl From<LanguageRange> for HeaderValue {
fn from(language: LanguageRange) -> Self {
let s = language.to_string();
Expand All @@ -51,3 +157,16 @@ impl<'a> From<&'a str> for LanguageRange {
Self::from_str(value).unwrap()
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_iter() -> crate::Result<()> {
let range: LanguageRange = "en-CA".parse().unwrap();
let subtags: Vec<_> = range.iter().collect();
assert_eq!(&subtags, &["en", "CA"]);
Ok(())
}
}
8 changes: 4 additions & 4 deletions src/language/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,20 @@ pub(crate) fn parse(input: &str) -> crate::Result<LanguageRange> {
input = rest;
}

Ok(LanguageRange { tags })
Ok(LanguageRange { subtags: tags })
}

#[test]
fn test() {
let range = parse("en").unwrap();
assert_eq!(&range.tags, &["en"]);
assert_eq!(&range.subtags, &["en"]);

let range = parse("en-CA").unwrap();
assert_eq!(&range.tags, &["en", "CA"]);
assert_eq!(&range.subtags, &["en", "CA"]);

let range = parse("zh-Hant-CN-x-private1-private2").unwrap();
assert_eq!(
&range.tags,
&range.subtags,
&["zh", "Hant", "CN", "x", "private1", "private2"]
);
}

0 comments on commit efe6ea4

Please sign in to comment.