<commit_before>pub mod error;
pub mod helpers;
#[cfg(test)]
mod test;

use self::error::Error;

use std::result::Result as StdResult;

use serde::de::{self, Deserialize, IntoDeserializer};
use serde::de::value::SeqDeserializer;

macro_rules! forward_parsed_values {
  ($($ty:ident => $method:ident,)*) => {
    $(
      fn $method<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
      {
        match self.parts.remove(0).parse::<$ty>() {
          Ok(val) => val.into_deserializer().$method(visitor),
          Err(e) => Err(de::Error::custom(e))
        }
      }
    )*
  }
}

pub type Result<T> = StdResult<T, Error>;

struct Deserializer<'de> {
  parts: Vec<&'de str>,
  count: usize
}

pub fn from_str<'a, T>(input: &'a str) -> Result<T>
  where T: Deserialize<'a>
{
  let parts: Vec<&str> = input.split_whitespace().collect();
  let mut deserializer = Deserializer { parts: parts, count: 0 };
  let t = T::deserialize(&mut deserializer)?;
  if deserializer.parts.is_empty() {
    Ok(t)
  } else {
    Err(Error::Custom("trailing characters".to_owned()))
  }
}

impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
  type Error = Error;

  fn deserialize_struct<V>(self, _name: &'static str, fields: &'static [&'static str], visitor: V) -> Result<V::Value>
    where V: de::Visitor<'de>
  {
    self.deserialize_tuple(fields.len(), visitor)
  }

  fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
    where V: de::Visitor<'de><commit_msg>docs: add docs to from_str parser<commit_after>pub mod error;
pub mod helpers;
#[cfg(test)]
mod test;

use self::error::Error;

use std::result::Result as StdResult;

use serde::de::{self, Deserialize, IntoDeserializer};
use serde::de::value::SeqDeserializer;

macro_rules! forward_parsed_values {
  ($($ty:ident => $method:ident,)*) => {
    $(
      fn $method<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
      {
        match self.parts.remove(0).parse::<$ty>() {
          Ok(val) => val.into_deserializer().$method(visitor),
          Err(e) => Err(de::Error::custom(e))
        }
      }
    )*
  }
}

pub type Result<T> = StdResult<T, Error>;

struct Deserializer<'de> {
  parts: Vec<&'de str>,
  count: usize
}

/// Parse a command-line parameter string into a Rust type, most often a struct.
///
/// The order that fields are declared in the struct is the order in which they are parsed.
///
/// Note that this handles certain types in radically different ways than what you would expect.
///
/// `Option<T>` will only ever result in `None` if it is at the end of a string of parameters.
/// `Options`s can be chained at the end of a struct, but as soon as a `None` is hit, the rest are
/// guaranteed to be `None`, as well.
///
/// `Vec<T>` will consume every parameter except the ones before it. If you want a list of a
/// specific number of parts, use a fixed-length slice, e.g. `[String; 2]`.
pub fn from_str<'a, T>(input: &'a str) -> Result<T>
  where T: Deserialize<'a>
{
  let parts: Vec<&str> = input.split_whitespace().collect();
  let mut deserializer = Deserializer { parts: parts, count: 0 };
  let t = T::deserialize(&mut deserializer)?;
  if deserializer.parts.is_empty() {
    Ok(t)
  } else {
    Err(Error::Custom("trailing characters".to_owned()))
  }
}

impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
  type Error = Error;

  fn deserialize_struct<V>(self, _name: &'static str, fields: &'static [&'static str], visitor: V) -> Result<V::Value>
    where V: de::Visitor<'de>
  {
    self.deserialize_tuple(fields.len(), visitor)
  }

  fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
    where V: de::Visitor<'de>
{'fraction_non_alphanumeric': 0.1718038059501474, 'fraction_numerical': 0.0013401232913428035, 'mean_word_length': 3.7300380228136882, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3681705', 'n_tokens_mistral': 1303, 'n_tokens_neox': 1322, 'n_words': 362}