<commit_before>use std::default::Default;
use std::io;
use serde_json::ser::CharEscape;
use serde_json::ser::CompactFormatter;

struct SafeFormatter(CompactFormatter);

impl Default for SafeFormatter {
    fn default() -> Self {
        SafeFormatter(CompactFormatter)
    }
}

impl serde_json::ser::Formatter for SafeFormatter {
    fn write_string_fragment<W: ?Sized>(&mut self, writer: &mut W, fragment: &str) -> io::Result<()>
    where
        W: io::Write,
    {
        let mut start = 0;

        for (i, ch) in fragment.chars().enumerate() {
            let escape = match ch {
                '<' | '>' | '&' => CharEscape::AsciiControl(ch as u8),
                _ => continue,
            };

            if start < i {
                self.0.write_string_fragment(writer, &fragment[start..i])?;
            }

            self.write_char_escape(writer, escape)?;

            start = i + 1;
        }

        if start < fragment.len() {
            self.0.write_string_fragment(writer, &fragment[start..])?;
        }
        Ok(())
    }
}

pub fn to_string_safe<T: serde::Serialize + ?Sized>(value: &T) -> Result<String, String> {
    let mut writer = Vec::new();
    let mut ser = serde_json::Serializer::with_formatter(&mut writer, SafeFormatter::default());
    value.serialize(&mut ser).map_err(|e| e.to_string())?;
    let string = String::from_utf8(writer).map_err(|e| e.to_string())?;
    Ok(string)
}

#[cfg(test)]
mod tests {
    use serde_json::{self, json};
    use super::*;

    #[test]
    fn test_json_without_html() {
        let x = json!({
            "a": 1,
            "b": "c",
            "d": "text with \"quotes\" inside",
        });
        assert_eq!(to_string_safe(&x).unwrap(), serde_json::to_string(&x).unwrap());
    }

    #[test]
    fn test_json_with_html() {
        let x = json!({
            "a": 1,
            "b": "c",
            "d": "text with \"quotes\" inside",
            "h": "some <script>alert(\"Alert\")</script> html",
        });
        assert_eq!(
            to_string_safe(&x).unwrap().as_str(),
            r#"{"a":1,"b":"c","d":"text with \"quotes\" inside","h":"some \u003cscript\u003ealert(\"Alert\")\u003c/script\u003e html"}"#
        );
    }
}
<commit_msg>Fixes #236<commit_after>use std::default::Default;
use std::io;
use serde_json::ser::CharEscape;
use serde_json::ser::CompactFormatter;

struct SafeFormatter(CompactFormatter);

impl Default for SafeFormatter {
    fn default() -> Self {
        SafeFormatter(CompactFormatter)
    }
}

impl serde_json::ser::Formatter for SafeFormatter {
    fn write_string_fragment<W: ?Sized>(&mut self, writer: &mut W, fragment: &str) -> io::Result<()>
    where
        W: io::Write,
    {
        let mut start = 0;
        let mut code_length = 0;
        for ch in fragment.chars() {
            code_length += ch.len_utf8();
            let escape = match ch {
                '<' | '>' | '&' => CharEscape::AsciiControl(ch as u8),
                _ => continue,
            };
            if start < code_length - 1 {
                self.0.write_string_fragment(writer, &fragment[start..code_length-1])?;
            }

            self.write_char_escape(writer, escape)?;

            start = code_length;
        }

        if start < code_length {
            self.0.write_string_fragment(writer, &fragment[start..])?;
        }
        Ok(())
    }
}

pub fn to_string_safe<T: serde::Serialize + ?Sized>(value: &T) -> Result<String, String> {
    let mut writer = Vec::new();
    let mut ser = serde_json::Serializer::with_formatter(&mut writer, SafeFormatter::default());
    value.serialize(&mut ser).map_err(|e| e.to_string())?;
    let string = String::from_utf8(writer).map_err(|e| e.to_string())?;
    Ok(string)
}

#[cfg(test)]
mod tests {
    use serde_json::{self, json};
    use super::*;

    #[test]
    fn test_json_without_html() {
        let x = json!({
            "a": 1,
            "b": "c",
            "d": "text with \"quotes\" inside",
        });
        assert_eq!(to_string_safe(&x).unwrap(), serde_json::to_string(&x).unwrap());
    }

    #[test]
    fn test_json_with_html() {
        let x = json!({
            "a": 1,
            "b": "c",
            "d": "text with \"quotes\" inside",
            "h": "some <script>alert(\"Alert\")</script> html",
        });
        assert_eq!(
            to_string_safe(&x).unwrap().as_str(),
            r#"{"a":1,"b":"c","d":"text with \"quotes\" inside","h":"some \u003cscript\u003ealert(\"Alert\")\u003c/script\u003e html"}"#
        );
    }

    #[test]
    fn test_json_unicode() {
        let x = json!({
            "a": 1,
            "b": "a<❌>b",
        });
        assert_eq!(
            to_string_safe(&x).unwrap().as_str(),
            r#"{"a":1,"b":"a\u003c❌\u003eb"}"#
        );
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use git::Config;
use helpers;
use error::PartnersError;
use author::Author;
use author_selection::AuthorSelection;
use Result;

pub fn initial(config_path: &Path) -> Result<Config> {
    let partners_config = Config::File(config_path);

    if !config_path.exists() {
        println!("config file not found at {:?}", config_path);

        if helpers::confirm("do you want to create it?")? {
            helpers::create_config_file(&config_path)?;

            let domain = helpers::query_with_default("Email Domain", &partners_config.domain())?;
            partners_config.set_domain(&domain)?;

            let prefix = helpers::query_with_default("Email Prefix", &partners_config.prefix())?;
            partners_config.set_prefix(&prefix)?;

            let separator = helpers::query_with_default("Separator", &partners_config.separator())?;
            partners_config.set_separator(&separator)?;
        } else {
            Err(PartnersError::CannotProcede)?;
        }
    }

    let author = match Config::Local.current_author() {
        Ok(author) => author,
        Err(_) => {
            let nick = Config::Local.nick().or_else(|_| {
                println!("Please enter a nickname you would like to use");
                helpers::query_required("Nick")
            })?;

            let name = Config::Local.user_name().or_else(|_| {
                println!("Unable to determine your name from git configuration");
                helpers::query_required("Name")
            })?;

            let email = Config::Local.user_email().ok().or_else(|| {
                println!("Unable to determine your email address from git configuration");
                helpers::query_optional("Email").ok().and_then(|v| v)
            });

            let author = Author { nick: nick, name: name, email: email };

            let selection = AuthorSelection::new(&partners_config, vec![author.clone()])?;
            Config::Global.set_current_author(&selection)?;

            author
        }
    };

    if partners_config.find_author(&author.nick).is_none() {
        partners_config.add_author(&author)?;
    }

    Ok(partners_config)
}<commit_msg>Don’t run setup on initial config<commit_after>use std::path::Path;
use git::Config;
use helpers;
use error::PartnersError;
use author::Author;
use author_selection::AuthorSelection;
use Result;

pub fn initial(config_path: &Path) -> Result<Config> {
    let partners_config = Config::File(config_path);

    if !config_path.exists() {
        println!("config file not found at {:?}", config_path);

        if helpers::confirm("do you want to create it?")? {
            helpers::create_config_file(&config_path)?;
        } else {
            Err(PartnersError::CannotProcede)?;
        }
    }

    let author = match Config::Local.current_author() {
        Ok(author) => author,
        Err(_) => {
            let nick = Config::Local.nick().or_else(|_| {
                println!("Please enter a nickname you would like to use");
                helpers::query_required("Nick")
            })?;

            let name = Config::Local.user_name().or_else(|_| {
                println!("Unable to determine your name from git configuration");
                helpers::query_required("Name")
            })?;

            let email = Config::Local.user_email().ok().or_else(|| {
                println!("Unable to determine your email address from git configuration");
                helpers::query_optional("Email").ok().and_then(|v| v)
            });

            let author = Author { nick: nick, name: name, email: email };

            let selection = AuthorSelection::new(&partners_config, vec![author.clone()])?;
            Config::Global.set_current_author(&selection)?;

            author
        }
    };

    if partners_config.find_author(&author.nick).is_none() {
        partners_config.add_author(&author)?;
    }

    Ok(partners_config)
}<|endoftext|>


<commit_before>#![doc = r#"Profiling stuff.

In `bench` mode, `Profiler` is a unit structure. Also, all macros are
deactivated, so all profiling is completely removed.
"#]

#[warn(unused_imports)]
use std::time::{ Instant, Duration } ;

use common::* ;

/// Extends duration with a pretty printing.
pub trait DurationExt {
  /// Nice string representation.
  fn to_str(& self) -> String ;
}
impl DurationExt for Duration {
  fn to_str(& self) -> String {
    format!("{}.{:0>9}", self.as_secs(), self.subsec_nanos())
  }
}

/// Profile Tree.
#[derive(PartialEq, Eq)]
pub struct ProfileTree {
  /// Duration stored at this level.
  duration: Option<Duration>,
  /// Sub-branches.
  branches: HashMap<& 'static str, ProfileTree>,
}
impl ProfileTree {
  /// Tree with nothing but the top level.
  pub fn top(top: Duration) -> Self {
    ProfileTree {
      duration: Some(top),
      branches: HashMap::new(),
    }
  }

  /// Empty tree, not visible outside.
  fn empty() -> Self {
    ProfileTree { duration: None, branches: HashMap::new() }
  }

  /// Forces a scope to be equal to the sum of its sub branches.
  ///
  /// Only legal if the scope exists and its duration is `None`.
  pub fn lift(& mut self, scope: Vec<& 'static str>) -> Res<()> {
    let mut current = self ;
    for scp in & scope {
      let tmp = current ;
      current = if let Some(current) = tmp.branches.get_mut(scp) {
        current
      } else { return Ok(()) }
    }
    let mut sum = Duration::from_secs(0) ;
    for (_, branch) in & current.branches {
      sum = sum + branch.duration.clone().unwrap_or( Duration::from_secs(0) )
    }
    if current.duration.is_some() {
      bail!( "trying to lift scope with existing duration {:?}", scope )
    }
    current.duration = Some(sum) ;
    Ok(())
  }

  /// Inserts something in the tree.
  pub fn insert(
    & mut self, scope: Vec<& 'static str>, duration: Duration
  ) {
    let (mut current, mut last_scope) = (self, "top") ;

    for scope in scope {
      let tmp = current ;
      current = tmp.branches.entry(scope).or_insert_with(
        || ProfileTree::empty()
      ) ;
      last_scope = scope
    }
    if current.duration.is_some() {
      panic!(
        "ProfileTree: trying to insert the same scope twice `{}`",
        conf.emph(last_scope)
      )
    }
    current.duration = Some(duration)
  }

  /// Iterator on the tree.
  ///
  /// Scopes are guaranteed to follow the topological order.
  pub fn iter<F>(& self, f: F)
  where F: Fn(& [& 'static str], & Duration, Duration) {
    if let Some(duration) = self.duration.as_ref() {
      let sub_duration = self.branches.iter().fold(
        Duration::from_secs(0),
        |acc, (_, time)| acc + time.duration.unwrap_or_else(
          || Duration::from_secs(0)
        )
      ) ;
      f(&[], duration, sub_duration)
    } else {
      panic!("ProfileTree: no top duration set but already iterating")
    }
    let mut stack: Vec< (_, Vec<_>) > = vec![
      ( vec![], self.branches.iter().map(|(s, p)| (*s, p)).collect() )
    ] ;

    while let Some( (scope, mut branches) ) = stack.pop() {
      if let Some( (s, profile) ) = branches.pop() {
        let mut this_scope = scope.clone() ;
        stack.push( (scope, branches) ) ;
        this_scope.push( s ) ;
        let sub_duration = profile.branches.iter().fold(
          Duration::from_secs(0),
          |acc, (_, time)| acc + time.duration.unwrap_or_else(
            || Duration::from_secs(0)
          )
        ) ;
        if let Some(duration) = profile.duration.as_ref() {
          f(& this_scope, duration, sub_duration)
        } else {
          let mut scope_str = "".to_string() ;
          for s in & this_scope {
            scope_str.push_str("::") ; scope_str.push_str(s)
          }
          warn!{
            "no duration for scope {}, setting to sum of branches",
            conf.emph(& scope_str)
          }
          f(& this_scope, & sub_duration, sub_duration.clone())
        }
        stack.push(
          (
            this_scope,
            profile.branches.iter().map(|(s, p)| (*s, p)).collect()
          )
        )
      }
    }
  }
}

/// Maps strings to counters.
pub type Stats = HashMap<String, usize> ;
/// Provides a debug print function.
pub trait CanPrint {
  /// Debug print (multi-line).
  fn print(& self) ;
}
impl CanPrint for Stats {
  fn print(& self) {
    for (stat, count) in self {
      let stat_len = ::std::cmp::min( 30, stat.len() ) ;
      println!(
        ";   {0: >1$}{2}: {3: >5}",
        "", 30 - stat_len, conf.emph(stat), count
      )
    }
  }
}
impl CanPrint for ProfileTree {
  fn print(& self) {
    self.iter(
      |scope, time, sub_time| if let Some(last) = scope.last() {
        println!(
          "; {0: >1$}|- {2}s {3}{4}", "", 2 * scope.len(), time.to_str(), last,
          if sub_time != Duration::from_secs(0) {
            format!(" ({}s)", sub_time.to_str())
          } else {
            "".into()
          }
        )
      } else {
        println!(
          "; total {}s{}", time.to_str(),
          if sub_time != Duration::from_secs(0) {
            format!(" ({}s)", sub_time.to_str())
          } else {
            "".into()
          }
        )
      }
    )
  }
}

/// Profiling structure, only in `not(bench)`.
///
/// Maintains statistics using a hashmap indexed by strings.
///
/// Internally, the structures are wrapped in `RefCell`s so that mutation
/// does not require `& mut self`.
#[cfg( not(feature = "bench") )]
pub struct Profiler {
  /// String-indexed durations.
  map: ::std::cell::RefCell<
    HashMap< Vec<& 'static str>, (Option<Instant>, Duration)>
  >,
  /// Starting tick, for total time.
  start: Instant,
  /// Other statistics.
  stats: ::std::cell::RefCell< Stats >,
}
#[cfg(feature = "bench")]
pub struct Profiler ;
impl Profiler {
  /// Constructor.
  #[cfg( not(feature = "bench") )]
  pub fn new() -> Self {
    use std::cell::RefCell ;
    Profiler {
      map: RefCell::new( HashMap::new() ),
      start: Instant::now(),
      stats: RefCell::new( HashMap::new() ),
    }
  }
  #[cfg(feature = "bench")]
  pub fn new() -> Self { Profiler }

  /// Acts on a statistic.
  #[cfg( not(feature = "bench") )]
  pub fn stat_do<F, S>(& self, stat: S, f: F)
  where F: Fn(usize) -> usize, S: Into<String> {
    let stat = stat.into() ;
    let mut map = self.stats.borrow_mut() ;
    let val = map.get(& stat).map(|n| * n).unwrap_or(0) ;
    let _ = map.insert(stat, f(val)) ;
    ()
  }

  /// Ticks.
  #[cfg( not(feature = "bench") )]
  pub fn tick(& self, scope: Vec<& 'static str>) {
    if scope.is_empty() {
      panic!("Profile: can't use scope `total`")
    }
    let mut map = self.map.borrow_mut() ;
    let time = map.entry(scope).or_insert_with(
      || ( None, Duration::from_secs(0) )
    ) ;
    time.0 = Some( Instant::now() )
  }

  /// Registers the time since the last tick.
  ///
  /// Panics if there was no tick since the last time registration.
  #[cfg( not(feature = "bench") )]
  pub fn mark(& self, scope: Vec<& 'static str>) {
    if scope.is_empty() {
      panic!("Profile: can't use scope `total`")
    }
    let mut map = self.map.borrow_mut() ;
    if let Some(
      & mut (ref mut tick, ref mut sum)
    ) = map.get_mut(& scope) {
      let mut instant = None ;
      ::std::mem::swap(& mut instant, tick) ;
      if let Some(instant) = instant {
        * sum = (* sum) + Instant::now().duration_since(instant) ;
        * tick = None
      }
    } else {
      panic!("profiling: trying to mark the time without ticking first")
    }
  }

  /// Extracts the inner hash map.
  #[cfg( not(feature = "bench") )]
  pub fn extract(& self) -> HashMap< Vec<& 'static str>, Duration > {
    let mut map = HashMap::new() ;
    for (scope, & (ref tick, ref time)) in self.map.borrow().iter() {
      if tick.is_none() {
        let _ = map.insert(scope.clone(), * time) ;
      } else {
        panic!(
          "profiling: scope `{:?}` is still live but asked to extract", scope
        )
      }
    }
    let prev = map.insert(
      vec!["total"], Instant::now().duration_since(self.start)
    ) ;
    debug_assert!( prev.is_none() ) ;
    map
  }

  /// Extracts a profile tree.
  #[cfg( not(feature = "bench") )]
  pub fn extract_tree(self) -> (ProfileTree, Stats) {
    let mut tree = ProfileTree::top(
      Instant::now().duration_since(self.start)
    ) ;
    for (
      scope, & (ref should_be_none, ref time)
    ) in self.map.borrow().iter() {
      if should_be_none.is_some() {
        warn!(
          "Profile::extract_tree: \
          still have a live instant for {:?}", scope
        )
      }
      tree.insert( scope.clone(), * time )
    }
    ( tree, self.stats.into_inner() )
  }
}<commit_msg>Actually fixed warning in release<commit_after>#![doc = r#"Profiling stuff.

In `bench` mode, `Profiler` is a unit structure. Also, all macros are
deactivated, so all profiling is completely removed.
"#]

#[allow(unused_imports)]
use std::time::{ Instant, Duration } ;

use common::* ;

/// Extends duration with a pretty printing.
pub trait DurationExt {
  /// Nice string representation.
  fn to_str(& self) -> String ;
}
impl DurationExt for Duration {
  fn to_str(& self) -> String {
    format!("{}.{:0>9}", self.as_secs(), self.subsec_nanos())
  }
}

/// Profile Tree.
#[derive(PartialEq, Eq)]
pub struct ProfileTree {
  /// Duration stored at this level.
  duration: Option<Duration>,
  /// Sub-branches.
  branches: HashMap<& 'static str, ProfileTree>,
}
impl ProfileTree {
  /// Tree with nothing but the top level.
  pub fn top(top: Duration) -> Self {
    ProfileTree {
      duration: Some(top),
      branches: HashMap::new(),
    }
  }

  /// Empty tree, not visible outside.
  fn empty() -> Self {
    ProfileTree { duration: None, branches: HashMap::new() }
  }

  /// Forces a scope to be equal to the sum of its sub branches.
  ///
  /// Only legal if the scope exists and its duration is `None`.
  pub fn lift(& mut self, scope: Vec<& 'static str>) -> Res<()> {
    let mut current = self ;
    for scp in & scope {
      let tmp = current ;
      current = if let Some(current) = tmp.branches.get_mut(scp) {
        current
      } else { return Ok(()) }
    }
    let mut sum = Duration::from_secs(0) ;
    for (_, branch) in & current.branches {
      sum = sum + branch.duration.clone().unwrap_or( Duration::from_secs(0) )
    }
    if current.duration.is_some() {
      bail!( "trying to lift scope with existing duration {:?}", scope )
    }
    current.duration = Some(sum) ;
    Ok(())
  }

  /// Inserts something in the tree.
  pub fn insert(
    & mut self, scope: Vec<& 'static str>, duration: Duration
  ) {
    let (mut current, mut last_scope) = (self, "top") ;

    for scope in scope {
      let tmp = current ;
      current = tmp.branches.entry(scope).or_insert_with(
        || ProfileTree::empty()
      ) ;
      last_scope = scope
    }
    if current.duration.is_some() {
      panic!(
        "ProfileTree: trying to insert the same scope twice `{}`",
        conf.emph(last_scope)
      )
    }
    current.duration = Some(duration)
  }

  /// Iterator on the tree.
  ///
  /// Scopes are guaranteed to follow the topological order.
  pub fn iter<F>(& self, f: F)
  where F: Fn(& [& 'static str], & Duration, Duration) {
    if let Some(duration) = self.duration.as_ref() {
      let sub_duration = self.branches.iter().fold(
        Duration::from_secs(0),
        |acc, (_, time)| acc + time.duration.unwrap_or_else(
          || Duration::from_secs(0)
        )
      ) ;
      f(&[], duration, sub_duration)
    } else {
      panic!("ProfileTree: no top duration set but already iterating")
    }
    let mut stack: Vec< (_, Vec<_>) > = vec![
      ( vec![], self.branches.iter().map(|(s, p)| (*s, p)).collect() )
    ] ;

    while let Some( (scope, mut branches) ) = stack.pop() {
      if let Some( (s, profile) ) = branches.pop() {
        let mut this_scope = scope.clone() ;
        stack.push( (scope, branches) ) ;
        this_scope.push( s ) ;
        let sub_duration = profile.branches.iter().fold(
          Duration::from_secs(0),
          |acc, (_, time)| acc + time.duration.unwrap_or_else(
            || Duration::from_secs(0)
          )
        ) ;
        if let Some(duration) = profile.duration.as_ref() {
          f(& this_scope, duration, sub_duration)
        } else {
          let mut scope_str = "".to_string() ;
          for s in & this_scope {
            scope_str.push_str("::") ; scope_str.push_str(s)
          }
          warn!{
            "no duration for scope {}, setting to sum of branches",
            conf.emph(& scope_str)
          }
          f(& this_scope, & sub_duration, sub_duration.clone())
        }
        stack.push(
          (
            this_scope,
            profile.branches.iter().map(|(s, p)| (*s, p)).collect()
          )
        )
      }
    }
  }
}

/// Maps strings to counters.
pub type Stats = HashMap<String, usize> ;
/// Provides a debug print function.
pub trait CanPrint {
  /// Debug print (multi-line).
  fn print(& self) ;
}
impl CanPrint for Stats {
  fn print(& self) {
    for (stat, count) in self {
      let stat_len = ::std::cmp::min( 30, stat.len() ) ;
      println!(
        ";   {0: >1$}{2}: {3: >5}",
        "", 30 - stat_len, conf.emph(stat), count
      )
    }
  }
}
impl CanPrint for ProfileTree {
  fn print(& self) {
    self.iter(
      |scope, time, sub_time| if let Some(last) = scope.last() {
        println!(
          "; {0: >1$}|- {2}s {3}{4}", "", 2 * scope.len(), time.to_str(), last,
          if sub_time != Duration::from_secs(0) {
            format!(" ({}s)", sub_time.to_str())
          } else {
            "".into()
          }
        )
      } else {
        println!(
          "; total {}s{}", time.to_str(),
          if sub_time != Duration::from_secs(0) {
            format!(" ({}s)", sub_time.to_str())
          } else {
            "".into()
          }
        )
      }
    )
  }
}

/// Profiling structure, only in `not(bench)`.
///
/// Maintains statistics using a hashmap indexed by strings.
///
/// Internally, the structures are wrapped in `RefCell`s so that mutation
/// does not require `& mut self`.
#[cfg( not(feature = "bench") )]
pub struct Profiler {
  /// String-indexed durations.
  map: ::std::cell::RefCell<
    HashMap< Vec<& 'static str>, (Option<Instant>, Duration)>
  >,
  /// Starting tick, for total time.
  start: Instant,
  /// Other statistics.
  stats: ::std::cell::RefCell< Stats >,
}
#[cfg(feature = "bench")]
pub struct Profiler ;
impl Profiler {
  /// Constructor.
  #[cfg( not(feature = "bench") )]
  pub fn new() -> Self {
    use std::cell::RefCell ;
    Profiler {
      map: RefCell::new( HashMap::new() ),
      start: Instant::now(),
      stats: RefCell::new( HashMap::new() ),
    }
  }
  #[cfg(feature = "bench")]
  pub fn new() -> Self { Profiler }

  /// Acts on a statistic.
  #[cfg( not(feature = "bench") )]
  pub fn stat_do<F, S>(& self, stat: S, f: F)
  where F: Fn(usize) -> usize, S: Into<String> {
    let stat = stat.into() ;
    let mut map = self.stats.borrow_mut() ;
    let val = map.get(& stat).map(|n| * n).unwrap_or(0) ;
    let _ = map.insert(stat, f(val)) ;
    ()
  }

  /// Ticks.
  #[cfg( not(feature = "bench") )]
  pub fn tick(& self, scope: Vec<& 'static str>) {
    if scope.is_empty() {
      panic!("Profile: can't use scope `total`")
    }
    let mut map = self.map.borrow_mut() ;
    let time = map.entry(scope).or_insert_with(
      || ( None, Duration::from_secs(0) )
    ) ;
    time.0 = Some( Instant::now() )
  }

  /// Registers the time since the last tick.
  ///
  /// Panics if there was no tick since the last time registration.
  #[cfg( not(feature = "bench") )]
  pub fn mark(& self, scope: Vec<& 'static str>) {
    if scope.is_empty() {
      panic!("Profile: can't use scope `total`")
    }
    let mut map = self.map.borrow_mut() ;
    if let Some(
      & mut (ref mut tick, ref mut sum)
    ) = map.get_mut(& scope) {
      let mut instant = None ;
      ::std::mem::swap(& mut instant, tick) ;
      if let Some(instant) = instant {
        * sum = (* sum) + Instant::now().duration_since(instant) ;
        * tick = None
      }
    } else {
      panic!("profiling: trying to mark the time without ticking first")
    }
  }

  /// Extracts the inner hash map.
  #[cfg( not(feature = "bench") )]
  pub fn extract(& self) -> HashMap< Vec<& 'static str>, Duration > {
    let mut map = HashMap::new() ;
    for (scope, & (ref tick, ref time)) in self.map.borrow().iter() {
      if tick.is_none() {
        let _ = map.insert(scope.clone(), * time) ;
      } else {
        panic!(
          "profiling: scope `{:?}` is still live but asked to extract", scope
        )
      }
    }
    let prev = map.insert(
      vec!["total"], Instant::now().duration_since(self.start)
    ) ;
    debug_assert!( prev.is_none() ) ;
    map
  }

  /// Extracts a profile tree.
  #[cfg( not(feature = "bench") )]
  pub fn extract_tree(self) -> (ProfileTree, Stats) {
    let mut tree = ProfileTree::top(
      Instant::now().duration_since(self.start)
    ) ;
    for (
      scope, & (ref should_be_none, ref time)
    ) in self.map.borrow().iter() {
      if should_be_none.is_some() {
        warn!(
          "Profile::extract_tree: \
          still have a live instant for {:?}", scope
        )
      }
      tree.insert( scope.clone(), * time )
    }
    ( tree, self.stats.into_inner() )
  }
}<|endoftext|>


<commit_before>use dces::prelude::Entity;

use crate::{layout::*, render_object::*};

use super::BuildContext;

/// The `Template` trait is used to implement a particular widget type.
///
/// When a widget's `Template` is implemented, it provides three object types:
/// * a template objet (with default values for its properties, children, handlers)
/// * a render object
/// * a layout object
pub trait Template: Sized {
    /// Builds the template of the widget and returns it.
    ///
    /// # Arguments
    /// * `_id`: The id (Entity) of the instantiated widget in the Entity Store
    /// * `_context`: The BuildContext used to build and instantiate new widgets
    ///
    /// # Example
    /// Define a widget called MyWidget with min, max and val properties with
    /// type of usize, and then set default values and add a TextBlock child.
    ///
    /// ```
    /// widget!(MyWidget {
    ///     min: usize,
    ///     max: usize,
    ///     val: usize
    /// });
    ///
    /// impl Template for MyWidget {
    ///     fn template(self, _id: Entity, context: &mut BuildContext) -> Self {
    ///         self.name("MyWidget")
    ///             .min(100)
    ///             .max(1000)
    ///             .val(500)
    ///             .child(TextBlock::new().text("Set a value!").build(context))
    ///     }
    ///
    ///     fn render_object(&self) -> Box<dyn RenderObject> {
    ///         Box::new(RectangleRenderObject)
    ///     }
    ///
    ///     fn layout(&self) -> Box<dyn Layout> {
    ///        Box::new(AbsoluteLayout)
    ///     }
    /// }
    /// ```
    fn template(self, _id: Entity, _ctx: &mut BuildContext) -> Self {
        self
    }

    /// Returns a pointer to a heap allocated object.
    ///
    /// Widgets will be rendered as pixmaps inside the render buffer.
    /// For the list of available render objects, see the
    /// [`render_object`] module.
    ///
    /// [`render_object`]: ../../orbtk_core/render_object/index.html
    fn render_object(&self) -> Box<dyn RenderObject> {
        DefaultRenderObject.into()
    }

    /// Returns a pointer to a heap allocated object.
    ///
    /// The `layout` process will arrange all `box` entities of a widget
    /// in a tree, were size properties will meet the individual constraints.
    /// For the list of available layout objects, see
    /// the [`layout`] module.
    ///
    /// [`layout`]: ../../orbtk_core/layout/index.html
    fn layout(&self) -> Box<dyn Layout> {
        GridLayout::new().into()
    }
}
<commit_msg>orbtk_core: update template documentation<commit_after>use dces::prelude::Entity;

use crate::{layout::*, render_object::*};

use super::BuildContext;

/// The `Template` trait is used to implement a particular widget type.
///
/// When a widget's `Template` is implemented, it provides three object types:
/// * a template objet (with default values for its properties, children, handlers)
/// * a render object
/// * a layout object
pub trait Template: Sized {
    /// Builds the template of the widget and returns it.
    ///
    /// # Arguments
    /// * `_id`: The id (Entity) of the instantiated widget in the Entity Store
    /// * `_context`: The BuildContext used to build and instantiate new widgets
    ///
    /// # Example
    /// Define a widget called MyWidget with min, max and val properties with
    /// type of usize, and then set default values and add a TextBlock child.
    ///
    /// ```
    /// widget!(MyWidget {
    ///     min: usize,
    ///     max: usize,
    ///     val: usize
    /// });
    ///
    /// impl Template for MyWidget {
    ///     fn template(self, _id: Entity, context: &mut BuildContext) -> Self {
    ///         self.name("MyWidget")
    ///             .min(100)
    ///             .max(1000)
    ///             .val(500)
    ///             .child(TextBlock::new().text("Set a value!").build(context))
    ///     }
    ///
    ///     fn render_object(&self) -> Box<dyn RenderObject> {
    ///         Box::new(RectangleRenderObject)
    ///     }
    ///
    ///     fn layout(&self) -> Box<dyn Layout> {
    ///        Box::new(AbsoluteLayout)
    ///     }
    /// }
    /// ```
    fn template(self, _id: Entity, _ctx: &mut BuildContext) -> Self {
        self
    }

    /// Returns a pointer to a heap allocated object.
    ///
    /// Widgets will be rendered as pixmaps inside the render buffer.
    /// For the list of available render objects, see the
    /// [`render_object`] module.
    ///
    /// [`render_object`]: ../../orbtk_core/render_object/index.html
    fn render_object(&self) -> Box<dyn RenderObject> {
        DefaultRenderObject.into()
    }

    /// Returns a pointer to a heap allocated object.
    ///
    /// The `layout` process will arrange all `box` entities of a widget
=======
    /// The layout process will arrange all `box` entities of a widget
>>>>>>> fa56d7f1 (orbtk_core: update template documentation)
    /// in a tree, were size properties will meet the individual constraints.
    /// For the list of available layout objects, see
    /// the [`layout`] module.
    ///
    /// [`layout`]: ../../orbtk_core/layout/index.html
    fn layout(&self) -> Box<dyn Layout> {
        GridLayout::new().into()
    }
}
<|endoftext|>


<commit_before>extern crate gnuplot;

use std::collections::HashMap;
use std::env;

use std::path::Path;
use std::fs;
use std::u64;
use std::fs::DirEntry;

use gnuplot::*;

fn get_dir_size(direntry: &DirEntry) -> u64 {
  // Initialize with the size of the current directory
  let mut size = direntry.metadata().unwrap().len();
  // Sum up the current file children
  for subfile in get_subfiles(direntry).iter() {
    let subfile_size = subfile.metadata().unwrap().len();
    size += subfile_size;
  }
  // And recurse into subdirectories
  for subdir in get_subdirs(direntry).iter() {
    size += get_dir_size(subdir); }
  size
}

fn is_dir(direntry : &DirEntry) -> bool {
  let metadata = direntry.metadata();
  return match metadata {
    Err(_) => false,
    Ok(metadata) => metadata.is_dir()
  }
}

fn get_subdirs(direntry : &DirEntry) -> Vec<DirEntry> {
  get_path_subdirs(direntry.path().as_path())
}
fn get_subfiles(direntry : &DirEntry) -> Vec<DirEntry> {
  get_path_subfiles(direntry.path().as_path())
}

fn get_path_subdirs(path : &Path) -> Vec<DirEntry> {
  let children = fs::read_dir(path).unwrap();
  let children_entries = children.map(|c| c.unwrap()).collect::<Vec<_>>();
  children_entries.into_iter().filter(|c| is_dir(c)).collect::<Vec<_>>()
}
fn get_path_subfiles(path : &Path) -> Vec<DirEntry> {
  let children = fs::read_dir(path).unwrap();
  let children_entries = children.map(|c| c.unwrap()).collect::<Vec<_>>();
  children_entries.into_iter().filter(|c| !is_dir(c)).collect::<Vec<_>>()
}

fn main() {
  let args: Vec<_> = env::args().collect();
  let mut min_size = u64::MAX;
  let mut max_size = 0;
  let arxiv_root = &Path::new(&args[1]);
  let mut arxiv_sizes: HashMap<String, u64> = HashMap::new();
  let mut arxiv_counts: HashMap<String, u64> = HashMap::new();
  let arxiv_month_dirs = get_path_subdirs(arxiv_root);

  for month_dir in arxiv_month_dirs.iter() {
    let mut monthly_size = 0;
    let month_papers = get_subdirs(month_dir);
    // Record how many papers were submitted in that month
    arxiv_counts.insert(month_dir.file_name().to_str().unwrap().to_string(), month_papers.len() as u64);

    for paper_dir in month_papers.iter() {
      // Record the size of each paper directory
      let paper_size = get_dir_size(paper_dir);
      if paper_size > max_size {
        max_size = paper_size;
      }
      if paper_size < min_size {
        min_size = paper_size;
      }
      monthly_size += paper_size;
      arxiv_sizes.insert(paper_dir.file_name().to_str().unwrap().to_string(), paper_size as u64);
    }
    arxiv_sizes.insert(month_dir.file_name().to_str().unwrap().to_string(), monthly_size);
  }

  // Print the recorded stats
  println!("Counts: {:?}", arxiv_counts);
  println!("Sizes: {:?}", arxiv_sizes);

  // arXiv months in order
  // TODO: Only current as of 1505, you'll have to extend manually next time this is run
  let ordered_months = [
    "9107", "9108", "9109", "9110", "9111", "9112", "9201", "9202", "9203", "9204", "9205", "9206", "9207", "9208", "9209",
    "9210", "9211", "9212", "9301", "9302", "9303", "9304", "9305", "9306", "9307", "9308", "9309", "9310", "9311", "9312",
    "9401", "9402", "9403", "9404", "9405", "9406", "9407", "9408", "9409", "9410", "9411", "9412", "9501", "9502", "9503",
    "9504", "9505", "9506", "9507", "9508", "9509", "9510", "9511", "9512", "9601", "9602", "9603", "9604", "9605", "9606",
    "9607", "9608", "9609", "9610", "9611", "9612", "9701", "9702", "9703", "9704", "9705", "9706", "9707", "9708", "9709",
    "9710", "9711", "9712", "9801", "9802", "9803", "9804", "9805", "9806", "9807", "9808", "9809", "9810", "9811", "9812",
    "9901", "9902", "9903", "9904", "9905", "9906", "9907", "9908", "9909", "9910", "9911", "9912", "0001", "0002", "0003",
    "0004", "0005", "0006", "0007", "0008", "0009", "0010", "0011", "0012", "0101", "0102", "0103", "0104", "0105", "0106",
    "0107", "0108", "0109", "0110", "0111", "0112", "0201", "0202", "0203", "0204", "0205", "0206", "0207", "0208", "0209",
    "0210", "0211", "0212", "0301", "0302", "0303", "0304", "0305", "0306", "0307", "0308", "0309", "0310", "0311", "0312",
    "0401", "0402", "0403", "0404", "0405", "0406", "0407", "0408", "0409", "0410", "0411", "0412", "0501", "0502", "0503",
    "0504", "0505", "0506", "0507", "0508", "0509", "0510", "0511", "0512", "0601", "0602", "0603", "0604", "0605", "0606",
    "0607", "0608", "0609", "0610", "0611", "0612", "0701", "0702", "0703", "0704", "0705", "0706", "0707", "0708", "0709",
    "0710", "0711", "0712", "0801", "0802", "0803", "0804", "0805", "0806", "0807", "0808", "0809", "0810", "0811", "0812",
    "0901", "0902", "0903", "0904", "0905", "0906", "0907", "0908", "0909", "0910", "0911", "0912", "1001", "1002", "1003",
    "1004", "1005", "1006", "1007", "1008", "1009", "1010", "1011", "1012", "1101", "1102", "1103", "1104", "1105", "1106",
    "1107", "1108", "1109", "1110", "1111", "1112", "1201", "1202", "1203", "1204", "1205", "1206", "1207", "1208", "1209",
    "1210", "1211", "1212", "1301", "1302", "1303", "1304", "1305", "1306", "1307", "1308", "1309", "1310", "1311", "1312",
    "1401", "1402", "1403", "1404", "1405", "1406", "1407", "1408", "1409", "1410", "1411", "1412", "1501", "1502", "1503",
    "1504", "1505"];

  // Plot of paper counts by month:
  let zero = 0 as u64;
  let ordered_counts = ordered_months.iter().map(|m|
    match arxiv_counts.get(&m.to_string()) {
        Some(counts) => counts,
        None => &zero
    });
  let ordered_month_xcoords = 1..ordered_months.len()+1;

  let mut fg = Figure::new();
  fg.axes2d()
  .points(ordered_month_xcoords.clone(), ordered_counts, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("arXiv month", &[Rotate(45.0)])
  .set_y_label("Submitted papers", &[Rotate(90.0)])
  .set_title("arXiv TeX submission counts", &[]);

  fg.set_terminal("pngcairo", "arxiv_submission_counts.png");
  fg.show();

  // Plot of submission size by month:
  let ordered_sizes = ordered_months.iter().map(|m|
    match arxiv_sizes.get(&m.to_string()) {
        Some(counts) => counts / (1024 * 1024), // MB
        None => zero
    });
  fg = Figure::new();
  fg.axes2d()
  .points(ordered_month_xcoords, ordered_sizes, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("arXiv month", &[Rotate(45.0)])
  .set_y_label("Submission size in MB", &[Rotate(90.0)])
  .set_title("arXiv TeX submission sizes", &[]);

  fg.set_terminal("pngcairo", "arxiv_submission_sizes.png");
  fg.show();

}<commit_msg>adding a first draft for paper stats<commit_after>extern crate gnuplot;

use std::collections::HashMap;
use std::env;

use std::path::Path;
use std::fs;
use std::u64;
use std::fs::DirEntry;

use gnuplot::*;

fn get_dir_size(direntry: &DirEntry) -> u64 {
  // Initialize with the size of the current directory
  let mut size = direntry.metadata().unwrap().len();
  // Sum up the current file children
  for subfile in get_subfiles(direntry).iter() {
    let subfile_size = subfile.metadata().unwrap().len();
    size += subfile_size;
  }
  // And recurse into subdirectories
  for subdir in get_subdirs(direntry).iter() {
    size += get_dir_size(subdir); }
  size
}

fn is_dir(direntry : &DirEntry) -> bool {
  let metadata = direntry.metadata();
  return match metadata {
    Err(_) => false,
    Ok(metadata) => metadata.is_dir()
  }
}

fn get_subdirs(direntry : &DirEntry) -> Vec<DirEntry> {
  get_path_subdirs(direntry.path().as_path())
}
fn get_subfiles(direntry : &DirEntry) -> Vec<DirEntry> {
  get_path_subfiles(direntry.path().as_path())
}

fn get_path_subdirs(path : &Path) -> Vec<DirEntry> {
  let children = fs::read_dir(path).unwrap();
  let children_entries = children.map(|c| c.unwrap()).collect::<Vec<_>>();
  children_entries.into_iter().filter(|c| is_dir(c)).collect::<Vec<_>>()
}
fn get_path_subfiles(path : &Path) -> Vec<DirEntry> {
  let children = fs::read_dir(path).unwrap();
  let children_entries = children.map(|c| c.unwrap()).collect::<Vec<_>>();
  children_entries.into_iter().filter(|c| !is_dir(c)).collect::<Vec<_>>()
}

fn main() {
  let args: Vec<_> = env::args().collect();
  let mut min_size = u64::MAX;
  let mut max_size = 0;
  let arxiv_root = &Path::new(&args[1]);
  let mut arxiv_size_frequencies: HashMap<u64, u64> = HashMap::new();
  let mut arxiv_monthly_sizes: HashMap<String, u64> = HashMap::new();
  let mut arxiv_counts: HashMap<String, u64> = HashMap::new();
  let arxiv_month_dirs = get_path_subdirs(arxiv_root);

  for month_dir in arxiv_month_dirs.iter() {
    let mut monthly_size = 0;
    let month_papers = get_subdirs(month_dir);
    // Record how many papers were submitted in that month
    arxiv_counts.insert(month_dir.file_name().to_str().unwrap().to_string(), month_papers.len() as u64);

    for paper_dir in month_papers.iter() {
      // Record the size of each paper directory
      let paper_size = get_dir_size(paper_dir) / 1024; // In KB
      if paper_size > max_size {
        max_size = paper_size;
      }
      if paper_size < min_size {
        min_size = paper_size;
      }
      monthly_size += paper_size;

      let size_frequency = arxiv_size_frequencies.entry(paper_size).or_insert(0);
      *size_frequency += 1;
    }
    arxiv_monthly_sizes.insert(month_dir.file_name().to_str().unwrap().to_string(), monthly_size);
  }

  // Print the recorded stats
  println!("Counts: {:?}", arxiv_counts);
  println!("Sizes: {:?}", arxiv_monthly_sizes);

  // arXiv months in order
  // TODO: Only current as of 1505, you'll have to extend manually next time this is run
  let ordered_months = [
    "9107", "9108", "9109", "9110", "9111", "9112", "9201", "9202", "9203", "9204", "9205", "9206", "9207", "9208", "9209",
    "9210", "9211", "9212", "9301", "9302", "9303", "9304", "9305", "9306", "9307", "9308", "9309", "9310", "9311", "9312",
    "9401", "9402", "9403", "9404", "9405", "9406", "9407", "9408", "9409", "9410", "9411", "9412", "9501", "9502", "9503",
    "9504", "9505", "9506", "9507", "9508", "9509", "9510", "9511", "9512", "9601", "9602", "9603", "9604", "9605", "9606",
    "9607", "9608", "9609", "9610", "9611", "9612", "9701", "9702", "9703", "9704", "9705", "9706", "9707", "9708", "9709",
    "9710", "9711", "9712", "9801", "9802", "9803", "9804", "9805", "9806", "9807", "9808", "9809", "9810", "9811", "9812",
    "9901", "9902", "9903", "9904", "9905", "9906", "9907", "9908", "9909", "9910", "9911", "9912", "0001", "0002", "0003",
    "0004", "0005", "0006", "0007", "0008", "0009", "0010", "0011", "0012", "0101", "0102", "0103", "0104", "0105", "0106",
    "0107", "0108", "0109", "0110", "0111", "0112", "0201", "0202", "0203", "0204", "0205", "0206", "0207", "0208", "0209",
    "0210", "0211", "0212", "0301", "0302", "0303", "0304", "0305", "0306", "0307", "0308", "0309", "0310", "0311", "0312",
    "0401", "0402", "0403", "0404", "0405", "0406", "0407", "0408", "0409", "0410", "0411", "0412", "0501", "0502", "0503",
    "0504", "0505", "0506", "0507", "0508", "0509", "0510", "0511", "0512", "0601", "0602", "0603", "0604", "0605", "0606",
    "0607", "0608", "0609", "0610", "0611", "0612", "0701", "0702", "0703", "0704", "0705", "0706", "0707", "0708", "0709",
    "0710", "0711", "0712", "0801", "0802", "0803", "0804", "0805", "0806", "0807", "0808", "0809", "0810", "0811", "0812",
    "0901", "0902", "0903", "0904", "0905", "0906", "0907", "0908", "0909", "0910", "0911", "0912", "1001", "1002", "1003",
    "1004", "1005", "1006", "1007", "1008", "1009", "1010", "1011", "1012", "1101", "1102", "1103", "1104", "1105", "1106",
    "1107", "1108", "1109", "1110", "1111", "1112", "1201", "1202", "1203", "1204", "1205", "1206", "1207", "1208", "1209",
    "1210", "1211", "1212", "1301", "1302", "1303", "1304", "1305", "1306", "1307", "1308", "1309", "1310", "1311", "1312",
    "1401", "1402", "1403", "1404", "1405", "1406", "1407", "1408", "1409", "1410", "1411", "1412", "1501", "1502", "1503",
    "1504", "1505"];

  // Plot of paper counts by month:
  let zero = 0 as u64;
  let ordered_counts = ordered_months.iter().map(|m|
    match arxiv_counts.get(&m.to_string()) {
        Some(counts) => counts,
        None => &zero
    });
  let ordered_month_xcoords = 1..ordered_months.len()+1;

  let mut fg = Figure::new();
  fg.axes2d()
  .points(ordered_month_xcoords.clone(), ordered_counts, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("arXiv month", &[Rotate(45.0)])
  .set_y_label("Submitted papers", &[Rotate(90.0)])
  .set_title("arXiv TeX submission counts", &[]);

  fg.set_terminal("pngcairo", "arxiv_submission_counts.png");
  fg.show();

  // Plot of submission counts by month:
  let ordered_sizes = ordered_months.iter().map(|m|
    match arxiv_monthly_sizes.get(&m.to_string()) {
        Some(&counts) => counts,
        None => zero
    });
  fg = Figure::new();
  fg.axes2d()
  .points(ordered_month_xcoords.clone(), ordered_sizes, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("arXiv month", &[Rotate(45.0)])
  .set_y_label("Submission size in MB", &[Rotate(90.0)])
  .set_title("arXiv TeX submission sizes by month", &[]);

  fg.set_terminal("pngcairo", "arxiv_submission_sizes.png");
  fg.show();

  // Plot average paper size in KB
  // Plot of submission size by month:

  let freq_keys = arxiv_size_frequencies.clone().into_iter().map(|entry| entry.0);
  let freq_values = arxiv_size_frequencies.clone().into_iter().map(|entry| entry.1);

  fg = Figure::new();
  fg.axes2d()
  .points(freq_keys, freq_values, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("Paper size in KB", &[Rotate(45.0)])
  .set_y_label("Paper count", &[Rotate(90.0)])
  .set_title("arXiv TeX paper sizes", &[]);

  fg.set_terminal("pngcairo", "arxiv_paper_sizes.png");
  fg.show();

}<|endoftext|>


<commit_before>use serde;
use serde_derive::{Deserialize, Serialize};
use std::ops::Deref;

/// An object that can be incrementally updated with events.
pub trait Incremental: Sized {
    type Seed;
    type Event;

    /// Initialize the starting state from a seed value.
    fn from_seed(s: &Self::Seed) -> Self;

    /// Try to update the object with an event.
    fn update(&mut self, e: &Self::Event);
}

/// Handle that stores an `Incremental` object and the event sequence used to build it.
///
/// The full `IncrementalState` serializes itself normally with a full snapshot of the state, but
/// you can make a possibly much smaller serialization by just saving the `History` and then
/// creating a new state with `IncrmentalState::from(history)`. This will involve replaying the
/// entire history so it might be much slower than just deserializing the snapshot.
///
/// # Examples
///
/// ```
/// use calx::{Incremental, IncrementalState};
///
/// #[derive(Default)]
/// struct State(u32);
///
/// impl Incremental for State {
///     type Seed = u32;
///     type Event = u32;
///
///     fn update(&mut self, e: &Self::Event) { self.0 += *e }
///     fn from_seed(s: &Self::Seed) -> Self { State(*s) }
/// }
///
/// let mut handle: IncrementalState<State> = Default::default();
/// assert_eq!(handle.0, 0);
///
/// for x in &[1, 2, 3, 4] { handle.update(*x); }
/// assert_eq!(handle.0, 10);
///
/// // Save the history.
/// let history_copy = handle.history().clone();
///
/// handle.undo();               // Magical time travel!
/// assert_eq!(handle.0, 6);
///
/// // Create a new state just from the saved history.
/// let handle2: IncrementalState<State> = history_copy.into();
/// assert_eq!(handle2.0, 10);
/// ```
#[derive(Serialize, Deserialize)]
// Need to add extra boilerplate or serde will get confused by the dependenent types.
#[serde(bound(
    serialize = "T: serde::Serialize, T::Seed: serde::Serialize, T::Event: serde::Serialize",
    deserialize = "T: serde::Deserialize<'de>, T::Seed: serde::Deserialize<'de>, T::Event: serde::Deserialize<'de>",
))]
pub struct IncrementalState<T: Incremental> {
    state: T,
    history: History<T::Seed, T::Event>,
}

#[derive(Clone, Serialize, Deserialize)]
pub struct History<U, E> {
    pub seed: U,
    pub events: Vec<E>,
}

// Implemented manually instead of derived so that T::Event doesn't need to implement Default.
impl<T: Incremental<Seed = U>, U: Default> Default for IncrementalState<T> {
    fn default() -> Self { IncrementalState::new(T::Seed::default()) }
}

impl<T: Incremental> IncrementalState<T> {
    pub fn new(seed: T::Seed) -> Self {
        let state = T::from_seed(&seed);
        IncrementalState {
            state,
            history: History {
                seed,
                events: Vec::new(),
            },
        }
    }

    pub fn history(&self) -> &History<T::Seed, T::Event> { &self.history }

    pub fn update(&mut self, e: T::Event) {
        self.state.update(&e);
        self.history.events.push(e);
    }

    /// Do arbitrary modification on event history, then replay state to match new history.
    ///
    /// Use this if you want to undo multiple steps, replaying can be very expensive.
    pub fn edit_history<F: FnOnce(&mut History<T::Seed, T::Event>) -> U, U>(&mut self, f: F) -> U {
        let ret = f(&mut self.history);
        self.replay();
        ret
    }

    /// Cancel the last event and rewind state to the position before it.
    pub fn undo(&mut self) -> Option<T::Event> { self.edit_history(|h| h.events.pop()) }

    fn replay(&mut self) {
        let mut state = T::from_seed(&self.history.seed);

        for e in &self.history.events {
            state.update(e);
        }

        self.state = state;
    }
}

impl<T: Incremental> From<History<T::Seed, T::Event>> for IncrementalState<T> {
    fn from(history: History<T::Seed, T::Event>) -> Self {
        let state = T::from_seed(&history.seed);
        let mut ret = IncrementalState { state, history };
        ret.replay();
        ret
    }
}

impl<T: Incremental> Deref for IncrementalState<T> {
    type Target = T;

    fn deref(&self) -> &T { &self.state }
}
<commit_msg>DerefMut in Incremental<commit_after>use serde;
use serde_derive::{Deserialize, Serialize};
use std::ops::{Deref, DerefMut};

/// An object that can be incrementally updated with events.
pub trait Incremental: Sized {
    type Seed;
    type Event;

    /// Initialize the starting state from a seed value.
    fn from_seed(s: &Self::Seed) -> Self;

    /// Update the object with an event.
    fn update(&mut self, e: &Self::Event);
}

/// Handle that stores an `Incremental` object and the event sequence used to build it.
///
/// The full `IncrementalState` serializes itself normally with a full snapshot of the state, but
/// you can make a possibly much smaller serialization by just saving the `History` and then
/// creating a new state with `IncrementalState::from(history)`. This will involve replaying the
/// entire history so it might be much slower than just deserializing the snapshot.
///
/// # Examples
///
/// ```
/// use calx::{Incremental, IncrementalState};
///
/// #[derive(Default)]
/// struct State(u32);
///
/// impl Incremental for State {
///     type Seed = u32;
///     type Event = u32;
///
///     fn update(&mut self, e: &Self::Event) { self.0 += *e }
///     fn from_seed(s: &Self::Seed) -> Self { State(*s) }
/// }
///
/// let mut handle: IncrementalState<State> = Default::default();
/// assert_eq!(handle.0, 0);
///
/// for x in &[1, 2, 3, 4] { handle.update(*x); }
/// assert_eq!(handle.0, 10);
///
/// // Save the history.
/// let history_copy = handle.history().clone();
///
/// handle.undo();               // Magical time travel!
/// assert_eq!(handle.0, 6);
///
/// // Create a new state just from the saved history.
/// let handle2: IncrementalState<State> = history_copy.into();
/// assert_eq!(handle2.0, 10);
/// ```
#[derive(Serialize, Deserialize)]
// Need to add extra boilerplate or serde will get confused by the dependenent types.
#[serde(bound(
    serialize = "T: serde::Serialize, T::Seed: serde::Serialize, T::Event: serde::Serialize",
    deserialize = "T: serde::Deserialize<'de>, T::Seed: serde::Deserialize<'de>, T::Event: serde::Deserialize<'de>",
))]
pub struct IncrementalState<T: Incremental> {
    state: T,
    history: History<T::Seed, T::Event>,
}

#[derive(Clone, Serialize, Deserialize)]
pub struct History<U, E> {
    pub seed: U,
    pub events: Vec<E>,
}

// Implemented manually instead of derived so that T::Event doesn't need to implement Default.
impl<T: Incremental<Seed = U>, U: Default> Default for IncrementalState<T> {
    fn default() -> Self { IncrementalState::new(T::Seed::default()) }
}

impl<T: Incremental> IncrementalState<T> {
    pub fn new(seed: T::Seed) -> Self {
        let state = T::from_seed(&seed);
        IncrementalState {
            state,
            history: History {
                seed,
                events: Vec::new(),
            },
        }
    }

    pub fn history(&self) -> &History<T::Seed, T::Event> { &self.history }

    pub fn update(&mut self, e: T::Event) {
        self.state.update(&e);
        self.history.events.push(e);
    }

    /// Do arbitrary modification on event history, then replay state to match new history.
    ///
    /// Use this if you want to undo multiple steps, replaying can be very expensive.
    pub fn edit_history<F: FnOnce(&mut History<T::Seed, T::Event>) -> U, U>(&mut self, f: F) -> U {
        let ret = f(&mut self.history);
        self.replay();
        ret
    }

    /// Cancel the last event and rewind state to the position before it.
    pub fn undo(&mut self) -> Option<T::Event> { self.edit_history(|h| h.events.pop()) }

    fn replay(&mut self) {
        let mut state = T::from_seed(&self.history.seed);

        for e in &self.history.events {
            state.update(e);
        }

        self.state = state;
    }
}

impl<T: Incremental> From<History<T::Seed, T::Event>> for IncrementalState<T> {
    fn from(history: History<T::Seed, T::Event>) -> Self {
        let state = T::from_seed(&history.seed);
        let mut ret = IncrementalState { state, history };
        ret.replay();
        ret
    }
}

impl<T: Incremental> Deref for IncrementalState<T> {
    type Target = T;

    fn deref(&self) -> &T { &self.state }
}

impl<T: Incremental> DerefMut for IncrementalState<T> {
    fn deref_mut(&mut self) -> &mut T { &mut self.state }
}
<|endoftext|>


<commit_before>//! Store XML element attributes and their values.

use std::slice;
use std::str;

use markup5ever::{namespace_url, LocalName, Namespace, Prefix, QualName};
use string_cache::DefaultAtom;

use crate::util::{opt_utf8_cstr, utf8_cstr};

/// Type used to store attribute values.
///
/// Attribute values are often repeated in an SVG file, so we intern them using the
/// string_cache crate.
pub type AttributeValue = DefaultAtom;

/// Iterable wrapper for libxml2's representation of attribute/value.
///
/// See the [`new_from_xml2_attributes`] function for information.
///
/// [`new_from_xml2_attributes`]: #method.new_from_xml2_attributes
#[derive(Clone)]
pub struct Attributes(Vec<(QualName, AttributeValue)>);

/// Iterator from `Attributes.iter`.
pub struct AttributesIter<'a>(slice::Iter<'a, (QualName, AttributeValue)>);

impl Attributes {
    /// Creates an iterable `Attributes` from the C array of borrowed C strings.
    ///
    /// With libxml2's SAX parser, the caller's startElementNsSAX2Func
    /// callback gets passed a `xmlChar **` for attributes, which
    /// comes in groups of (localname/prefix/URI/value_start/value_end).
    /// In those, localname/prefix/URI are NUL-terminated strings;
    /// value_start and value_end point to the start-inclusive and
    /// end-exclusive bytes in the attribute's value.
    ///
    /// This function is unsafe because the caller must guarantee the following:
    ///
    /// * `attrs` is a valid pointer, with (n_attributes * 5) elements.
    ///
    /// * All strings are valid UTF-8.
    ///
    /// The lifetime of the `Attributes` should be considered the same as the lifetime of the
    /// `attrs` array, as the `Attributes` does not copy the strings - it directly stores pointers
    /// into that array's strings.
    pub unsafe fn new_from_xml2_attributes(
        n_attributes: usize,
        attrs: *const *const libc::c_char,
    ) -> Attributes {
        let mut array = Vec::new();

        if n_attributes > 0 && !attrs.is_null() {
            for attr in slice::from_raw_parts(attrs, n_attributes * 5).chunks_exact(5) {
                let localname = attr[0];
                let prefix = attr[1];
                let uri = attr[2];
                let value_start = attr[3];
                let value_end = attr[4];

                assert!(!localname.is_null());

                let localname = utf8_cstr(localname);

                let prefix = opt_utf8_cstr(prefix);
                let uri = opt_utf8_cstr(uri);
                let qual_name = QualName::new(
                    prefix.map(Prefix::from),
                    uri.map(Namespace::from)
                        .unwrap_or_else(|| namespace_url!("")),
                    LocalName::from(localname),
                );

                if !value_start.is_null() && !value_end.is_null() {
                    assert!(value_end >= value_start);

                    // FIXME: ptr::offset_from() is nightly-only.
                    // We'll do the computation of the length by hand.
                    let start = value_start as usize;
                    let end = value_end as usize;
                    let len = end - start;

                    let value_slice = slice::from_raw_parts(value_start as *const u8, len);
                    let value_str = str::from_utf8_unchecked(value_slice);
                    let value_atom = DefaultAtom::from(value_str);

                    array.push((qual_name, value_atom));
                }
            }
        }

        Attributes(array)
    }

    /// Returns the number of attributes.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Creates an iterator that yields `(QualName, &'a str)` tuples.
    pub fn iter(&self) -> AttributesIter<'_> {
        AttributesIter(self.0.iter())
    }
}

impl<'a> Iterator for AttributesIter<'a> {
    type Item = (QualName, &'a str);

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|(a, v)| (a.clone(), v.as_ref()))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use markup5ever::{expanded_name, local_name, namespace_url, ns};
    use std::ffi::CString;
    use std::ptr;

    #[test]
    fn empty_attributes() {
        let map = unsafe { Attributes::new_from_xml2_attributes(0, ptr::null()) };
        assert_eq!(map.len(), 0);
    }

    #[test]
    fn attributes_with_namespaces() {
        let attrs = [
            (
                CString::new("href").unwrap(),
                Some(CString::new("xlink").unwrap()),
                Some(CString::new("http://www.w3.org/1999/xlink").unwrap()),
                CString::new("1").unwrap(),
            ),
            (
                CString::new("ry").unwrap(),
                None,
                None,
                CString::new("2").unwrap(),
            ),
            (
                CString::new("d").unwrap(),
                None,
                None,
                CString::new("").unwrap(),
            ),
        ];

        let mut v: Vec<*const libc::c_char> = Vec::new();

        for (localname, prefix, uri, val) in &attrs {
            v.push(localname.as_ptr() as *const libc::c_char);
            v.push(
                prefix
                    .as_ref()
                    .map(|p: &CString| p.as_ptr())
                    .unwrap_or_else(|| ptr::null()) as *const libc::c_char,
            );
            v.push(
                uri.as_ref()
                    .map(|p: &CString| p.as_ptr())
                    .unwrap_or_else(|| ptr::null()) as *const libc::c_char,
            );

            let val_start = val.as_ptr() as *const libc::c_char;
            let val_end = unsafe { val_start.offset(val.as_bytes().len() as isize) };
            v.push(val_start); // value_start
            v.push(val_end); // value_end
        }

        let attrs = unsafe { Attributes::new_from_xml2_attributes(3, v.as_ptr()) };

        let mut had_href: bool = false;
        let mut had_ry: bool = false;
        let mut had_d: bool = false;

        for (a, v) in attrs.iter() {
            match a.expanded() {
                expanded_name!(xlink "href") => {
                    assert!(v == "1");
                    had_href = true;
                }

                expanded_name!("", "ry") => {
                    assert!(v == "2");
                    had_ry = true;
                }

                expanded_name!("", "d") => {
                    assert!(v == "");
                    had_d = true;
                }

                _ => unreachable!(),
            }
        }

        assert!(had_href);
        assert!(had_ry);
        assert!(had_d);
    }
}
<commit_msg>Remove obsolete note on the lifetime of Attributes<commit_after>//! Store XML element attributes and their values.

use std::slice;
use std::str;

use markup5ever::{namespace_url, LocalName, Namespace, Prefix, QualName};
use string_cache::DefaultAtom;

use crate::util::{opt_utf8_cstr, utf8_cstr};

/// Type used to store attribute values.
///
/// Attribute values are often repeated in an SVG file, so we intern them using the
/// string_cache crate.
pub type AttributeValue = DefaultAtom;

/// Iterable wrapper for libxml2's representation of attribute/value.
///
/// See the [`new_from_xml2_attributes`] function for information.
///
/// [`new_from_xml2_attributes`]: #method.new_from_xml2_attributes
#[derive(Clone)]
pub struct Attributes(Vec<(QualName, AttributeValue)>);

/// Iterator from `Attributes.iter`.
pub struct AttributesIter<'a>(slice::Iter<'a, (QualName, AttributeValue)>);

impl Attributes {
    /// Creates an iterable `Attributes` from the C array of borrowed C strings.
    ///
    /// With libxml2's SAX parser, the caller's startElementNsSAX2Func
    /// callback gets passed a `xmlChar **` for attributes, which
    /// comes in groups of (localname/prefix/URI/value_start/value_end).
    /// In those, localname/prefix/URI are NUL-terminated strings;
    /// value_start and value_end point to the start-inclusive and
    /// end-exclusive bytes in the attribute's value.
    ///
    /// # Safety
    ///
    /// This function is unsafe because the caller must guarantee the following:
    ///
    /// * `attrs` is a valid pointer, with (n_attributes * 5) elements.
    ///
    /// * All strings are valid UTF-8.
    pub unsafe fn new_from_xml2_attributes(
        n_attributes: usize,
        attrs: *const *const libc::c_char,
    ) -> Attributes {
        let mut array = Vec::new();

        if n_attributes > 0 && !attrs.is_null() {
            for attr in slice::from_raw_parts(attrs, n_attributes * 5).chunks_exact(5) {
                let localname = attr[0];
                let prefix = attr[1];
                let uri = attr[2];
                let value_start = attr[3];
                let value_end = attr[4];

                assert!(!localname.is_null());

                let localname = utf8_cstr(localname);

                let prefix = opt_utf8_cstr(prefix);
                let uri = opt_utf8_cstr(uri);
                let qual_name = QualName::new(
                    prefix.map(Prefix::from),
                    uri.map(Namespace::from)
                        .unwrap_or_else(|| namespace_url!("")),
                    LocalName::from(localname),
                );

                if !value_start.is_null() && !value_end.is_null() {
                    assert!(value_end >= value_start);

                    // FIXME: ptr::offset_from() is nightly-only.
                    // We'll do the computation of the length by hand.
                    let start = value_start as usize;
                    let end = value_end as usize;
                    let len = end - start;

                    let value_slice = slice::from_raw_parts(value_start as *const u8, len);
                    let value_str = str::from_utf8_unchecked(value_slice);
                    let value_atom = DefaultAtom::from(value_str);

                    array.push((qual_name, value_atom));
                }
            }
        }

        Attributes(array)
    }

    /// Returns the number of attributes.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Creates an iterator that yields `(QualName, &'a str)` tuples.
    pub fn iter(&self) -> AttributesIter<'_> {
        AttributesIter(self.0.iter())
    }
}

impl<'a> Iterator for AttributesIter<'a> {
    type Item = (QualName, &'a str);

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|(a, v)| (a.clone(), v.as_ref()))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use markup5ever::{expanded_name, local_name, namespace_url, ns};
    use std::ffi::CString;
    use std::ptr;

    #[test]
    fn empty_attributes() {
        let map = unsafe { Attributes::new_from_xml2_attributes(0, ptr::null()) };
        assert_eq!(map.len(), 0);
    }

    #[test]
    fn attributes_with_namespaces() {
        let attrs = [
            (
                CString::new("href").unwrap(),
                Some(CString::new("xlink").unwrap()),
                Some(CString::new("http://www.w3.org/1999/xlink").unwrap()),
                CString::new("1").unwrap(),
            ),
            (
                CString::new("ry").unwrap(),
                None,
                None,
                CString::new("2").unwrap(),
            ),
            (
                CString::new("d").unwrap(),
                None,
                None,
                CString::new("").unwrap(),
            ),
        ];

        let mut v: Vec<*const libc::c_char> = Vec::new();

        for (localname, prefix, uri, val) in &attrs {
            v.push(localname.as_ptr() as *const libc::c_char);
            v.push(
                prefix
                    .as_ref()
                    .map(|p: &CString| p.as_ptr())
                    .unwrap_or_else(|| ptr::null()) as *const libc::c_char,
            );
            v.push(
                uri.as_ref()
                    .map(|p: &CString| p.as_ptr())
                    .unwrap_or_else(|| ptr::null()) as *const libc::c_char,
            );

            let val_start = val.as_ptr() as *const libc::c_char;
            let val_end = unsafe { val_start.offset(val.as_bytes().len() as isize) };
            v.push(val_start); // value_start
            v.push(val_end); // value_end
        }

        let attrs = unsafe { Attributes::new_from_xml2_attributes(3, v.as_ptr()) };

        let mut had_href: bool = false;
        let mut had_ry: bool = false;
        let mut had_d: bool = false;

        for (a, v) in attrs.iter() {
            match a.expanded() {
                expanded_name!(xlink "href") => {
                    assert!(v == "1");
                    had_href = true;
                }

                expanded_name!("", "ry") => {
                    assert!(v == "2");
                    had_ry = true;
                }

                expanded_name!("", "d") => {
                    assert!(v == "");
                    had_d = true;
                }

                _ => unreachable!(),
            }
        }

        assert!(had_href);
        assert!(had_ry);
        assert!(had_d);
    }
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use crate::datatypes::ArrowPrimitiveType;

use super::{
    Array, ArrayRef, BinaryOffsetSizeTrait, BooleanArray, GenericBinaryArray,
    GenericListArray, GenericStringArray, OffsetSizeTrait, PrimitiveArray,
    StringOffsetSizeTrait,
};

/// an iterator that returns Some(T) or None, that can be used on any PrimitiveArray
// Note: This implementation is based on std's [Vec]s' [IntoIter].
#[derive(Debug)]
pub struct PrimitiveIter<'a, T: ArrowPrimitiveType> {
    array: &'a PrimitiveArray<T>,
    current: usize,
    current_end: usize,
}

impl<'a, T: ArrowPrimitiveType> PrimitiveIter<'a, T> {
    /// create a new iterator
    pub fn new(array: &'a PrimitiveArray<T>) -> Self {
        PrimitiveIter::<T> {
            array,
            current: 0,
            current_end: array.len(),
        }
    }
}

impl<'a, T: ArrowPrimitiveType> std::iter::Iterator for PrimitiveIter<'a, T> {
    type Item = Option<T::Native>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.current == self.current_end {
            None
        } else if self.array.is_null(self.current) {
            self.current += 1;
            Some(None)
        } else {
            let old = self.current;
            self.current += 1;
            Some(Some(self.array.value(old)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (
            self.array.len() - self.current,
            Some(self.array.len() - self.current),
        )
    }
}

impl<'a, T: ArrowPrimitiveType> std::iter::DoubleEndedIterator for PrimitiveIter<'a, T> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current_end == self.current {
            None
        } else {
            self.current_end -= 1;
            Some(if self.array.is_null(self.current_end) {
                None
            } else {
                Some(self.array.value(self.current_end))
            })
        }
    }
}

/// all arrays have known size.
impl<'a, T: ArrowPrimitiveType> std::iter::ExactSizeIterator for PrimitiveIter<'a, T> {}

/// an iterator that returns Some(bool) or None.
// Note: This implementation is based on std's [Vec]s' [IntoIter].
#[derive(Debug)]
pub struct BooleanIter<'a> {
    array: &'a BooleanArray,
    current: usize,
    current_end: usize,
}

impl<'a> BooleanIter<'a> {
    /// create a new iterator
    pub fn new(array: &'a BooleanArray) -> Self {
        BooleanIter {
            array,
            current: 0,
            current_end: array.len(),
        }
    }
}

impl<'a> std::iter::Iterator for BooleanIter<'a> {
    type Item = Option<bool>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current == self.current_end {
            None
        } else if self.array.is_null(self.current) {
            self.current += 1;
            Some(None)
        } else {
            let old = self.current;
            self.current += 1;
            Some(Some(self.array.value(old)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (
            self.array.len() - self.current,
            Some(self.array.len() - self.current),
        )
    }
}

impl<'a> std::iter::DoubleEndedIterator for BooleanIter<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current_end == self.current {
            None
        } else {
            self.current_end -= 1;
            Some(if self.array.is_null(self.current_end) {
                None
            } else {
                Some(self.array.value(self.current_end))
            })
        }
    }
}

/// all arrays have known size.
impl<'a> std::iter::ExactSizeIterator for BooleanIter<'a> {}

/// an iterator that returns `Some(&str)` or `None`, for string arrays
#[derive(Debug)]
pub struct GenericStringIter<'a, T>
where
    T: StringOffsetSizeTrait,
{
    array: &'a GenericStringArray<T>,
    i: usize,
    len: usize,
}

impl<'a, T: StringOffsetSizeTrait> GenericStringIter<'a, T> {
    /// create a new iterator
    pub fn new(array: &'a GenericStringArray<T>) -> Self {
        GenericStringIter::<T> {
            array,
            i: 0,
            len: array.len(),
        }
    }
}

impl<'a, T: StringOffsetSizeTrait> std::iter::Iterator for GenericStringIter<'a, T> {
    type Item = Option<&'a str>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        if i >= self.len {
            None
        } else if self.array.is_null(i) {
            self.i += 1;
            Some(None)
        } else {
            self.i += 1;
            Some(Some(self.array.value(i)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len - self.i, Some(self.len - self.i))
    }
}

/// all arrays have known size.
impl<'a, T: StringOffsetSizeTrait> std::iter::ExactSizeIterator
    for GenericStringIter<'a, T>
{
}

/// an iterator that returns `Some(&[u8])` or `None`, for binary arrays
#[derive(Debug)]
pub struct GenericBinaryIter<'a, T>
where
    T: BinaryOffsetSizeTrait,
{
    array: &'a GenericBinaryArray<T>,
    i: usize,
    len: usize,
}

impl<'a, T: BinaryOffsetSizeTrait> GenericBinaryIter<'a, T> {
    /// create a new iterator
    pub fn new(array: &'a GenericBinaryArray<T>) -> Self {
        GenericBinaryIter::<T> {
            array,
            i: 0,
            len: array.len(),
        }
    }
}

impl<'a, T: BinaryOffsetSizeTrait> std::iter::Iterator for GenericBinaryIter<'a, T> {
    type Item = Option<&'a [u8]>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        if i >= self.len {
            None
        } else if self.array.is_null(i) {
            self.i += 1;
            Some(None)
        } else {
            self.i += 1;
            Some(Some(self.array.value(i)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len - self.i, Some(self.len - self.i))
    }
}

#[derive(Debug)]
pub struct GenericListArrayIter<'a, S>
where
    S: OffsetSizeTrait,
{
    array: &'a GenericListArray<S>,
    i: usize,
    len: usize,
}

impl<'a, S: OffsetSizeTrait> GenericListArrayIter<'a, S> {
    pub fn new(array: &'a GenericListArray<S>) -> Self {
        GenericListArrayIter::<S> {
            array,
            i: 0,
            len: array.len(),
        }
    }
}

impl<'a, S: OffsetSizeTrait> std::iter::Iterator for GenericListArrayIter<'a, S> {
    type Item = Option<ArrayRef>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        if i >= self.len {
            None
        } else if self.array.is_null(i) {
            self.i += 1;
            Some(None)
        } else {
            self.i += 1;
            Some(Some(self.array.value(i)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len - self.i, Some(self.len - self.i))
    }
}

/// all arrays have known size.
impl<'a, T: BinaryOffsetSizeTrait> std::iter::ExactSizeIterator
    for GenericBinaryIter<'a, T>
{
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;

    use crate::array::{ArrayRef, BinaryArray, BooleanArray, Int32Array, StringArray};

    #[test]
    fn test_primitive_array_iter_round_trip() {
        let array = Int32Array::from(vec![Some(0), None, Some(2), None, Some(4)]);
        let array = Arc::new(array) as ArrayRef;

        let array = array.as_any().downcast_ref::<Int32Array>().unwrap();

        // to and from iter, with a +1
        let result: Int32Array = array.iter().map(|e| e.map(|e| e + 1)).collect();

        let expected = Int32Array::from(vec![Some(1), None, Some(3), None, Some(5)]);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_double_ended() {
        let array = Int32Array::from(vec![Some(0), None, Some(2), None, Some(4)]);
        let mut a = array.iter();
        assert_eq!(a.next(), Some(Some(0)));
        assert_eq!(a.next(), Some(None));
        assert_eq!(a.next_back(), Some(Some(4)));
        assert_eq!(a.next_back(), Some(None));
        assert_eq!(a.next_back(), Some(Some(2)));
        // the two sides have met: None is returned by both
        assert_eq!(a.next_back(), None);
        assert_eq!(a.next(), None);
    }

    #[test]
    fn test_string_array_iter_round_trip() {
        let array =
            StringArray::from(vec![Some("a"), None, Some("aaa"), None, Some("aaaaa")]);
        let array = Arc::new(array) as ArrayRef;

        let array = array.as_any().downcast_ref::<StringArray>().unwrap();

        // to and from iter, with a +1
        let result: StringArray = array
            .iter()
            .map(|e| {
                e.map(|e| {
                    let mut a = e.to_string();
                    a.push('b');
                    a
                })
            })
            .collect();

        let expected =
            StringArray::from(vec![Some("ab"), None, Some("aaab"), None, Some("aaaaab")]);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_binary_array_iter_round_trip() {
        let array = BinaryArray::from(vec![
            Some(b"a" as &[u8]),
            None,
            Some(b"aaa"),
            None,
            Some(b"aaaaa"),
        ]);

        // to and from iter
        let result: BinaryArray = array.iter().collect();

        assert_eq!(result, array);
    }

    #[test]
    fn test_boolean_array_iter_round_trip() {
        let array = BooleanArray::from(vec![Some(true), None, Some(false)]);

        // to and from iter
        let result: BooleanArray = array.iter().collect();

        assert_eq!(result, array);
    }
}
<commit_msg>ARROW-12337: [Rust] add DoubleEndedIterator and ExactSizeIterator traits<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use crate::datatypes::ArrowPrimitiveType;

use super::{
    Array, ArrayRef, BinaryOffsetSizeTrait, BooleanArray, GenericBinaryArray,
    GenericListArray, GenericStringArray, OffsetSizeTrait, PrimitiveArray,
    StringOffsetSizeTrait,
};

/// an iterator that returns Some(T) or None, that can be used on any PrimitiveArray
// Note: This implementation is based on std's [Vec]s' [IntoIter].
#[derive(Debug)]
pub struct PrimitiveIter<'a, T: ArrowPrimitiveType> {
    array: &'a PrimitiveArray<T>,
    current: usize,
    current_end: usize,
}

impl<'a, T: ArrowPrimitiveType> PrimitiveIter<'a, T> {
    /// create a new iterator
    pub fn new(array: &'a PrimitiveArray<T>) -> Self {
        PrimitiveIter::<T> {
            array,
            current: 0,
            current_end: array.len(),
        }
    }
}

impl<'a, T: ArrowPrimitiveType> std::iter::Iterator for PrimitiveIter<'a, T> {
    type Item = Option<T::Native>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.current == self.current_end {
            None
        } else if self.array.is_null(self.current) {
            self.current += 1;
            Some(None)
        } else {
            let old = self.current;
            self.current += 1;
            Some(Some(self.array.value(old)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (
            self.array.len() - self.current,
            Some(self.array.len() - self.current),
        )
    }
}

impl<'a, T: ArrowPrimitiveType> std::iter::DoubleEndedIterator for PrimitiveIter<'a, T> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current_end == self.current {
            None
        } else {
            self.current_end -= 1;
            Some(if self.array.is_null(self.current_end) {
                None
            } else {
                Some(self.array.value(self.current_end))
            })
        }
    }
}

/// all arrays have known size.
impl<'a, T: ArrowPrimitiveType> std::iter::ExactSizeIterator for PrimitiveIter<'a, T> {}

/// an iterator that returns Some(bool) or None.
// Note: This implementation is based on std's [Vec]s' [IntoIter].
#[derive(Debug)]
pub struct BooleanIter<'a> {
    array: &'a BooleanArray,
    current: usize,
    current_end: usize,
}

impl<'a> BooleanIter<'a> {
    /// create a new iterator
    pub fn new(array: &'a BooleanArray) -> Self {
        BooleanIter {
            array,
            current: 0,
            current_end: array.len(),
        }
    }
}

impl<'a> std::iter::Iterator for BooleanIter<'a> {
    type Item = Option<bool>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current == self.current_end {
            None
        } else if self.array.is_null(self.current) {
            self.current += 1;
            Some(None)
        } else {
            let old = self.current;
            self.current += 1;
            Some(Some(self.array.value(old)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (
            self.array.len() - self.current,
            Some(self.array.len() - self.current),
        )
    }
}

impl<'a> std::iter::DoubleEndedIterator for BooleanIter<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current_end == self.current {
            None
        } else {
            self.current_end -= 1;
            Some(if self.array.is_null(self.current_end) {
                None
            } else {
                Some(self.array.value(self.current_end))
            })
        }
    }
}

/// all arrays have known size.
impl<'a> std::iter::ExactSizeIterator for BooleanIter<'a> {}

/// an iterator that returns `Some(&str)` or `None`, for string arrays
#[derive(Debug)]
pub struct GenericStringIter<'a, T>
where
    T: StringOffsetSizeTrait,
{
    array: &'a GenericStringArray<T>,
    current: usize,
    current_end: usize,
}

impl<'a, T: StringOffsetSizeTrait> GenericStringIter<'a, T> {
    /// create a new iterator
    pub fn new(array: &'a GenericStringArray<T>) -> Self {
        GenericStringIter::<T> {
            array,
            current: 0,
            current_end: array.len(),
        }
    }
}

impl<'a, T: StringOffsetSizeTrait> std::iter::Iterator for GenericStringIter<'a, T> {
    type Item = Option<&'a str>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.current;
        if i >= self.current_end {
            None
        } else if self.array.is_null(i) {
            self.current += 1;
            Some(None)
        } else {
            self.current += 1;
            Some(Some(self.array.value(i)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (
            self.current_end - self.current,
            Some(self.current_end - self.current),
        )
    }
}

impl<'a, T: StringOffsetSizeTrait> std::iter::DoubleEndedIterator
    for GenericStringIter<'a, T>
{
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current_end == self.current {
            None
        } else {
            self.current_end -= 1;
            Some(if self.array.is_null(self.current_end) {
                None
            } else {
                Some(self.array.value(self.current_end))
            })
        }
    }
}

/// all arrays have known size.
impl<'a, T: StringOffsetSizeTrait> std::iter::ExactSizeIterator
    for GenericStringIter<'a, T>
{
}

/// an iterator that returns `Some(&[u8])` or `None`, for binary arrays
#[derive(Debug)]
pub struct GenericBinaryIter<'a, T>
where
    T: BinaryOffsetSizeTrait,
{
    array: &'a GenericBinaryArray<T>,
    current: usize,
    current_end: usize,
}

impl<'a, T: BinaryOffsetSizeTrait> GenericBinaryIter<'a, T> {
    /// create a new iterator
    pub fn new(array: &'a GenericBinaryArray<T>) -> Self {
        GenericBinaryIter::<T> {
            array,
            current: 0,
            current_end: array.len(),
        }
    }
}

impl<'a, T: BinaryOffsetSizeTrait> std::iter::Iterator for GenericBinaryIter<'a, T> {
    type Item = Option<&'a [u8]>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.current;
        if i >= self.current_end {
            None
        } else if self.array.is_null(i) {
            self.current += 1;
            Some(None)
        } else {
            self.current += 1;
            Some(Some(self.array.value(i)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (
            self.current_end - self.current,
            Some(self.current_end - self.current),
        )
    }
}

impl<'a, T: BinaryOffsetSizeTrait> std::iter::DoubleEndedIterator
    for GenericBinaryIter<'a, T>
{
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current_end == self.current {
            None
        } else {
            self.current_end -= 1;
            Some(if self.array.is_null(self.current_end) {
                None
            } else {
                Some(self.array.value(self.current_end))
            })
        }
    }
}

/// all arrays have known size.
impl<'a, T: BinaryOffsetSizeTrait> std::iter::ExactSizeIterator
    for GenericBinaryIter<'a, T>
{
}

#[derive(Debug)]
pub struct GenericListArrayIter<'a, S>
where
    S: OffsetSizeTrait,
{
    array: &'a GenericListArray<S>,
    current: usize,
    current_end: usize,
}

impl<'a, S: OffsetSizeTrait> GenericListArrayIter<'a, S> {
    pub fn new(array: &'a GenericListArray<S>) -> Self {
        GenericListArrayIter::<S> {
            array,
            current: 0,
            current_end: array.len(),
        }
    }
}

impl<'a, S: OffsetSizeTrait> std::iter::Iterator for GenericListArrayIter<'a, S> {
    type Item = Option<ArrayRef>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.current;
        if i >= self.current_end {
            None
        } else if self.array.is_null(i) {
            self.current += 1;
            Some(None)
        } else {
            self.current += 1;
            Some(Some(self.array.value(i)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (
            self.current_end - self.current,
            Some(self.current_end - self.current),
        )
    }
}

impl<'a, S: OffsetSizeTrait> std::iter::DoubleEndedIterator
    for GenericListArrayIter<'a, S>
{
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current_end == self.current {
            None
        } else {
            self.current_end -= 1;
            Some(if self.array.is_null(self.current_end) {
                None
            } else {
                Some(self.array.value(self.current_end))
            })
        }
    }
}

/// all arrays have known size.
impl<'a, S: OffsetSizeTrait> std::iter::ExactSizeIterator
    for GenericListArrayIter<'a, S>
{
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;

    use crate::array::{ArrayRef, BinaryArray, BooleanArray, Int32Array, StringArray};

    #[test]
    fn test_primitive_array_iter_round_trip() {
        let array = Int32Array::from(vec![Some(0), None, Some(2), None, Some(4)]);
        let array = Arc::new(array) as ArrayRef;

        let array = array.as_any().downcast_ref::<Int32Array>().unwrap();

        // to and from iter, with a +1
        let result: Int32Array = array.iter().map(|e| e.map(|e| e + 1)).collect();

        let expected = Int32Array::from(vec![Some(1), None, Some(3), None, Some(5)]);
        assert_eq!(result, expected);

        // check if DoubleEndedIterator is implemented
        let result: Int32Array = array.iter().rev().collect();
        let rev_array = Int32Array::from(vec![Some(4), None, Some(2), None, Some(0)]);
        assert_eq!(result, rev_array);
        // check if ExactSizeIterator is implemented
        let _ = array.iter().rposition(|opt_b| opt_b == Some(1));
    }

    #[test]
    fn test_double_ended() {
        let array = Int32Array::from(vec![Some(0), None, Some(2), None, Some(4)]);
        let mut a = array.iter();
        assert_eq!(a.next(), Some(Some(0)));
        assert_eq!(a.next(), Some(None));
        assert_eq!(a.next_back(), Some(Some(4)));
        assert_eq!(a.next_back(), Some(None));
        assert_eq!(a.next_back(), Some(Some(2)));
        // the two sides have met: None is returned by both
        assert_eq!(a.next_back(), None);
        assert_eq!(a.next(), None);
    }

    #[test]
    fn test_string_array_iter_round_trip() {
        let array =
            StringArray::from(vec![Some("a"), None, Some("aaa"), None, Some("aaaaa")]);
        let array = Arc::new(array) as ArrayRef;

        let array = array.as_any().downcast_ref::<StringArray>().unwrap();

        // to and from iter, with a +1
        let result: StringArray = array
            .iter()
            .map(|e| {
                e.map(|e| {
                    let mut a = e.to_string();
                    a.push('b');
                    a
                })
            })
            .collect();

        let expected =
            StringArray::from(vec![Some("ab"), None, Some("aaab"), None, Some("aaaaab")]);
        assert_eq!(result, expected);

        // check if DoubleEndedIterator is implemented
        let result: StringArray = array.iter().rev().collect();
        let rev_array =
            StringArray::from(vec![Some("aaaaa"), None, Some("aaa"), None, Some("a")]);
        assert_eq!(result, rev_array);
        // check if ExactSizeIterator is implemented
        let _ = array.iter().rposition(|opt_b| opt_b == Some("a"));
    }

    #[test]
    fn test_binary_array_iter_round_trip() {
        let array = BinaryArray::from(vec![
            Some(b"a" as &[u8]),
            None,
            Some(b"aaa"),
            None,
            Some(b"aaaaa"),
        ]);

        // to and from iter
        let result: BinaryArray = array.iter().collect();

        assert_eq!(result, array);

        // check if DoubleEndedIterator is implemented
        let result: BinaryArray = array.iter().rev().collect();
        let rev_array = BinaryArray::from(vec![
            Some(b"aaaaa" as &[u8]),
            None,
            Some(b"aaa"),
            None,
            Some(b"a"),
        ]);
        assert_eq!(result, rev_array);

        // check if ExactSizeIterator is implemented
        let _ = array.iter().rposition(|opt_b| opt_b == Some(&[9]));
    }

    #[test]
    fn test_boolean_array_iter_round_trip() {
        let array = BooleanArray::from(vec![Some(true), None, Some(false)]);

        // to and from iter
        let result: BooleanArray = array.iter().collect();

        assert_eq!(result, array);

        // check if DoubleEndedIterator is implemented
        let result: BooleanArray = array.iter().rev().collect();
        let rev_array = BooleanArray::from(vec![Some(false), None, Some(true)]);
        assert_eq!(result, rev_array);

        // check if ExactSizeIterator is implemented
        let _ = array.iter().rposition(|opt_b| opt_b == Some(true));
    }
}
<|endoftext|>