<commit_before>/// Custom event handlers
use crate::{Cmd, EditMode, InputMode, InputState, KeyEvent, Refresher, RepeatCount};

use radix_trie::TrieKey;
use serde::Serialize;
use smallvec::{smallvec, SmallVec};

/// Input event
#[derive(Debug, PartialEq, Eq, Hash, Serialize)]
pub enum Event {
    /// Wildcard.
    /// Useful if you want to filter out some keys.
    Any,
    /// Key sequence
    // TODO Validate 2 ?
    KeySeq(SmallVec<[KeyEvent; 2]>),
    /// TODO Mouse event
    Mouse(),
}

impl Event {
    /// See [`KeyEvent::normalize`]
    pub(crate) fn normalize(mut self) -> Self {
        if let Event::KeySeq(ref mut keys) = self {
            for key in keys.iter_mut() {
                *key = KeyEvent::normalize(*key);
            }
        }
        self
    }
}

impl From<KeyEvent> for Event {
    fn from(k: KeyEvent) -> Event {
        Event::KeySeq(smallvec![k])
    }
}

impl TrieKey for Event {
    fn encode_bytes(&self) -> Vec<u8> {
        bincode::serialize(self).unwrap()
    }
}

/// Event handler
pub enum EventHandler {
    /// unconditional command
    Simple(Cmd),
    /// handler behaviour depends on input state
    Conditional(Box<dyn ConditionalEventHandler>),
    /* invoke multiple actions
     * TODO Macro(), */
}

impl From<Cmd> for EventHandler {
    fn from(c: Cmd) -> EventHandler {
        EventHandler::Simple(c)
    }
}

/// Give access to user input.
pub struct EventContext<'r> {
    mode: EditMode,
    input_mode: InputMode,
    wrt: &'r dyn Refresher,
}

impl<'r> EventContext<'r> {
    pub(crate) fn new(is: &InputState, wrt: &'r dyn Refresher) -> Self {
        EventContext {
            mode: is.mode,
            input_mode: is.input_mode,
            wrt,
        }
    }

    /// emacs or vi mode
    pub fn mode(&self) -> EditMode {
        self.mode
    }

    /// vi input mode
    pub fn input_mode(&self) -> InputMode {
        self.input_mode
    }

    /// Returns `true` if there is a hint displayed.
    pub fn has_hint(&self) -> bool {
        self.wrt.has_hint()
    }

    /// currently edited line
    pub fn line(&self) -> &str {
        self.wrt.line()
    }

    /// Current cursor position (byte position)
    pub fn pos(&self) -> usize {
        self.wrt.pos()
    }
}

/// May behave differently depending on:
///  * edit mode (emacs vs vi)
///  * vi input mode (insert vs replace vs command modes)
///  * empty line
///  * cursor position
///  * repeat count
///  * original key pressed (when same command is bound to different key)
///  * hint
///  * ...
pub trait ConditionalEventHandler: Send + Sync {
    /// Takes the current input state and
    /// returns the command to be performed or `None` to perform the default
    /// one.
    fn handle(
        &self,
        evt: &Event,
        n: RepeatCount,
        positive: bool,
        ctx: &EventContext,
    ) -> Option<Cmd>;
}
<commit_msg>bincode is not compatible with subtrie<commit_after>/// Custom event handlers
use crate::{Cmd, EditMode, InputMode, InputState, KeyEvent, Refresher, RepeatCount};

use radix_trie::TrieKey;
use serde::Serialize;
use smallvec::{smallvec, SmallVec};

/// Input event
#[derive(Debug, PartialEq, Eq, Hash, Serialize)]
pub enum Event {
    /// Wildcard.
    /// Useful if you want to filter out some keys.
    Any,
    /// Key sequence
    // TODO Validate 2 ?
    KeySeq(SmallVec<[KeyEvent; 2]>),
    /// TODO Mouse event
    Mouse(),
}

impl Event {
    /// See [`KeyEvent::normalize`]
    pub(crate) fn normalize(mut self) -> Self {
        if let Event::KeySeq(ref mut keys) = self {
            for key in keys.iter_mut() {
                *key = KeyEvent::normalize(*key);
            }
        }
        self
    }
}

impl From<KeyEvent> for Event {
    fn from(k: KeyEvent) -> Event {
        Event::KeySeq(smallvec![k])
    }
}

impl TrieKey for Event {
    fn encode_bytes(&self) -> Vec<u8> {
        bincode::serialize(self).unwrap()
    }
}

/// Event handler
pub enum EventHandler {
    /// unconditional command
    Simple(Cmd),
    /// handler behaviour depends on input state
    Conditional(Box<dyn ConditionalEventHandler>),
    /* invoke multiple actions
     * TODO Macro(), */
}

impl From<Cmd> for EventHandler {
    fn from(c: Cmd) -> EventHandler {
        EventHandler::Simple(c)
    }
}

/// Give access to user input.
pub struct EventContext<'r> {
    mode: EditMode,
    input_mode: InputMode,
    wrt: &'r dyn Refresher,
}

impl<'r> EventContext<'r> {
    pub(crate) fn new(is: &InputState, wrt: &'r dyn Refresher) -> Self {
        EventContext {
            mode: is.mode,
            input_mode: is.input_mode,
            wrt,
        }
    }

    /// emacs or vi mode
    pub fn mode(&self) -> EditMode {
        self.mode
    }

    /// vi input mode
    pub fn input_mode(&self) -> InputMode {
        self.input_mode
    }

    /// Returns `true` if there is a hint displayed.
    pub fn has_hint(&self) -> bool {
        self.wrt.has_hint()
    }

    /// currently edited line
    pub fn line(&self) -> &str {
        self.wrt.line()
    }

    /// Current cursor position (byte position)
    pub fn pos(&self) -> usize {
        self.wrt.pos()
    }
}

/// May behave differently depending on:
///  * edit mode (emacs vs vi)
///  * vi input mode (insert vs replace vs command modes)
///  * empty line
///  * cursor position
///  * repeat count
///  * original key pressed (when same command is bound to different key)
///  * hint
///  * ...
pub trait ConditionalEventHandler: Send + Sync {
    /// Takes the current input state and
    /// returns the command to be performed or `None` to perform the default
    /// one.
    fn handle(
        &self,
        evt: &Event,
        n: RepeatCount,
        positive: bool,
        ctx: &EventContext,
    ) -> Option<Cmd>;
}

#[cfg(test)]
mod test {
    use crate::{KeyEvent, Cmd};
    use super::{Event, EventHandler};
    use radix_trie::Trie;
    use smallvec::smallvec;

    #[test]
    fn encode() {
        let mut trie = Trie::new();
        let evt = Event::KeySeq(smallvec![KeyEvent::ctrl('X'), KeyEvent::ctrl('E')]);
        trie.insert(evt, EventHandler::from(Cmd::Noop));
        let prefix = Event::from(KeyEvent::ctrl('X'));
        let subtrie = trie.subtrie(&prefix);
        assert!(subtrie.is_some())
    }
}<|endoftext|>


<commit_before>// Kevin Cantu
// replace djb with murmur

use std;
use vec2;

fn djb(&&ss: str) -> uint {
   // default str::hash
   // https://github.com/graydon/rust/blob/master/src/libcore/str.rs at ll. 43-50
   let uu: uint = 5381u;
   for cc: u8 in ss { uu *= 33u; uu += cc as uint; }
   ret uu;
}

// translate to hex
fn murmur_str(&&ss: str) -> str {
   let mm = murmur(ss);
   ret #fmt("%016X%016X", mm[0u], mm[1u]);
}

// murmur3 x64 128-bit
fn murmur(&&key_: str) -> [u64] {

   let key = str::bytes (key_);
   //std::io::println("key: "  + vec2::show(key,  {|b| #fmt("%02X", b as uint)}));

   // TODO: random seeds
   let seed = 0u64;
   let h1 = seed;
   let h2 = seed;

   let c1 = 0x_87c37b91114253d5_u64;
   let c2 = 0x_4cf5ad432745937f_u64;

   // rotation left
   fn rotl64 (x: u64, r: u64) -> u64 {
      ret (x << r) | (x >> (64u-r));
   }

   // conversion from 8 to 64 bits
   pure fn isEight (bytes: [u8]) -> bool {
      ret vec::len(bytes) == 8u;
   }

   fn convert_eight_u8_to_one_u64 (bb: [u8]) -> u64 {
      check isEight(bb);
      let bb_ = vec::reversed(bb);  // apparently rust doesn't have the same
                                    // endianness problem as C++ does
      ret vec::foldl(0u64, bb_, {|w, b| (w << 8u) + (b as u64)});
   }

   #[test]
   #[should_fail]
   fn test1_conversion_u8to64 () {
      let _XXXX = convert_u8to64 ([1u8,2u8]);
   }

   #[test]
   fn test2_conversion_u8to64 () {
      let aa = [255u8,0u8,8u8,0u8, 20u8,0u8,0u8,1u8];
      std::io::println(#fmt("converted: %016x", convert_eight_u8_to_one_u64 (aa)));
      let _test2 = convert_u8to64 (aa+aa);
   }

   fn convert_u8to64 (bb: [u8]) -> [u64] {
      fn lesser <copy TT> (aa: TT, bb: TT) -> TT {
         if aa < bb { aa } else { bb }
      }

      // split into vector^2
      fn splitEvery <copy TT> (nn: uint, xs: [TT]) -> [[TT]] {
         let ys: [[TT]] = [];

         vec::iteri (xs, {|ii, _x|
            let len = vec::len(xs);

            if ii % nn == 0u && ii < len {
               let y = vec::slice (xs, ii, lesser(nn+ii, len));
               vec::push (ys, y);
            }
         });

         ret ys;
      }

      let bbs = splitEvery(8u, bb);
      ret vec::map ( bbs, {|xs|
         convert_eight_u8_to_one_u64(xs)
      });
   }

   // fmix
   fn fmix (k_: u64) -> u64 {
      let kk = k_;

      kk ^= kk >> 33u;
      kk *= 0x_ff51afd7ed558ccd_u64;
      kk ^= kk >> 33u;
      kk *= 0x_c4ceb9fe1a85ec53_u64;
      kk ^= kk >> 33u;

      ret kk;
   }

   // split body data and tail
   let nbytes  = vec::len(key);
   let nblocks = nbytes / 16u;
   let (body_, tail) = vec2::splitAt (nblocks*16u, key);
   let body: [u64] = convert_u8to64 (body_);

   fn apply_constants (rot: u64,
                       kk: u64,
                       h: u64,
                       c: u64,
                       c_: u64) -> u64 {

      let k = kk;
      k *= c;
      k  = rotl64(k, rot);
      k *= c_;
      ret h ^ k;
   }

   // crunch body data
   fn do_body (blocks: [u64],
               nblocks: uint,
               h1_: u64,
               h2_: u64,
               c1: u64,
               c2: u64) -> (u64,u64) {
      let h1 = h1_;
      let h2 = h2_;

      let ii = 0u;
      assert nblocks % 2u == 0u;
      while (ii < nblocks) {

         let k1 = blocks[ii*2u + 0u];
         let k2 = blocks[ii*2u + 1u];

         h1 = apply_constants (31u64, k1, h1, c1, c2);

         h1 = rotl64(h1, 27u64);
         h1 += h2;
         h1 = h1*5u64 + 0x_52dce729_u64;

         h2 = apply_constants (33u64, k2, h2, c2, c1);

         h2 = rotl64(h2, 31u64);
         h2 += h1;
         h2 = h2*5u64 + 0x_38495ab5_u64;

         ii += 1u;
      }

      ret (h1, h2);
   }

   // tail
   fn do_tail (tail_: [u8], h1: u64, h2: u64, c1: u64, c2: u64) -> (u64,u64) {
      let tail = tail_;
      vec::grow(tail, 16u - vec::len(tail), 0u8);
      assert vec::len(tail) == 16u;
      //let jj = vec::reversed (tail);
      let jj = tail; // don't need to flip...
      let jj_ = convert_u8to64 (jj);
      assert vec::len(jj_) == 2u;
      let j1 = jj_[0u]; // reversing
      let j2 = jj_[1u]; // reversing

      let h2_ = apply_constants (33u64, j2, h2, c2, c1);
      let h1_ = apply_constants (31u64, j1, h1, c1, c2);
      ret (h1_,h2_);
   }

   // finalization
   fn finalize (h1_: u64, h2_: u64, len: uint) -> (u64,u64) {
      let h1 = h1_;
      let h2 = h2_;

      h1 ^= len as u64;
      h2 ^= len as u64;

      h1 += h2;
      h2 += h1;

      h1 = fmix(h1);
      h2 = fmix(h2);

      h1 += h2;
      h2 += h1;

      ret (h1, h2);
   }

   let (h1, h2) = do_body (body, nblocks, h1, h2, c1, c2);
   let (h1, h2) = do_tail (tail, h1, h2, c1, c2);
   let (h1, h2) = finalize (h1, h2, nbytes);

   ret [h1, h2];
}

<commit_msg>fixed <copy TT><commit_after>// Kevin Cantu
// replace djb with murmur

use std;
use vec2;

fn djb(&&ss: str) -> uint {
   // default str::hash
   // https://github.com/graydon/rust/blob/master/src/libcore/str.rs at ll. 43-50
   let uu: uint = 5381u;
   for cc: u8 in ss { uu *= 33u; uu += cc as uint; }
   ret uu;
}

// translate to hex
fn murmur_str(&&ss: str) -> str {
   let mm = murmur(ss);
   ret #fmt("%016X%016X", mm[0u], mm[1u]);
}

// murmur3 x64 128-bit
fn murmur(&&key_: str) -> [u64] {

   let key = str::bytes (key_);
   //std::io::println("key: "  + vec2::show(key,  {|b| #fmt("%02X", b as uint)}));

   // TODO: random seeds
   let seed = 0u64;
   let h1 = seed;
   let h2 = seed;

   let c1 = 0x_87c37b91114253d5_u64;
   let c2 = 0x_4cf5ad432745937f_u64;

   // rotation left
   fn rotl64 (x: u64, r: u64) -> u64 {
      ret (x << r) | (x >> (64u-r));
   }

   // conversion from 8 to 64 bits
   pure fn isEight (bytes: [u8]) -> bool {
      ret vec::len(bytes) == 8u;
   }

   fn convert_eight_u8_to_one_u64 (bb: [u8]) -> u64 {
      check isEight(bb);
      let bb_ = vec::reversed(bb);  // apparently rust doesn't have the same
                                    // endianness problem as C++ does
      ret vec::foldl(0u64, bb_, {|w, b| (w << 8u) + (b as u64)});
   }

   #[test]
   #[should_fail]
   fn test1_conversion_u8to64 () {
      let _XXXX = convert_u8to64 ([1u8,2u8]);
   }

   #[test]
   fn test2_conversion_u8to64 () {
      let aa = [255u8,0u8,8u8,0u8, 20u8,0u8,0u8,1u8];
      std::io::println(#fmt("converted: %016x", convert_eight_u8_to_one_u64 (aa)));
      let _test2 = convert_u8to64 (aa+aa);
   }

   fn convert_u8to64 (bb: [u8]) -> [u64] {
      fn lesser <TT: copy> (aa: TT, bb: TT) -> TT {
         if aa < bb { aa } else { bb }
      }

      // split into vector^2
      fn splitEvery <TT: copy> (nn: uint, xs: [TT]) -> [[TT]] {
         let ys: [[TT]] = [];

         vec::iteri (xs, {|ii, _x|
            let len = vec::len(xs);

            if ii % nn == 0u && ii < len {
               let y = vec::slice (xs, ii, lesser(nn+ii, len));
               vec::push (ys, y);
            }
         });

         ret ys;
      }

      let bbs = splitEvery(8u, bb);
      ret vec::map ( bbs, {|xs|
         convert_eight_u8_to_one_u64(xs)
      });
   }

   // fmix
   fn fmix (k_: u64) -> u64 {
      let kk = k_;

      kk ^= kk >> 33u;
      kk *= 0x_ff51afd7ed558ccd_u64;
      kk ^= kk >> 33u;
      kk *= 0x_c4ceb9fe1a85ec53_u64;
      kk ^= kk >> 33u;

      ret kk;
   }

   // split body data and tail
   let nbytes  = vec::len(key);
   let nblocks = nbytes / 16u;
   let (body_, tail) = vec2::splitAt (nblocks*16u, key);
   let body: [u64] = convert_u8to64 (body_);

   fn apply_constants (rot: u64,
                       kk: u64,
                       h: u64,
                       c: u64,
                       c_: u64) -> u64 {

      let k = kk;
      k *= c;
      k  = rotl64(k, rot);
      k *= c_;
      ret h ^ k;
   }

   // crunch body data
   fn do_body (blocks: [u64],
               nblocks: uint,
               h1_: u64,
               h2_: u64,
               c1: u64,
               c2: u64) -> (u64,u64) {
      let h1 = h1_;
      let h2 = h2_;

      let ii = 0u;
      assert nblocks % 2u == 0u;
      while (ii < nblocks) {

         let k1 = blocks[ii*2u + 0u];
         let k2 = blocks[ii*2u + 1u];

         h1 = apply_constants (31u64, k1, h1, c1, c2);

         h1 = rotl64(h1, 27u64);
         h1 += h2;
         h1 = h1*5u64 + 0x_52dce729_u64;

         h2 = apply_constants (33u64, k2, h2, c2, c1);

         h2 = rotl64(h2, 31u64);
         h2 += h1;
         h2 = h2*5u64 + 0x_38495ab5_u64;

         ii += 1u;
      }

      ret (h1, h2);
   }

   // tail
   fn do_tail (tail_: [u8], h1: u64, h2: u64, c1: u64, c2: u64) -> (u64,u64) {
      let tail = tail_;
      vec::grow(tail, 16u - vec::len(tail), 0u8);
      assert vec::len(tail) == 16u;
      //let jj = vec::reversed (tail);
      let jj = tail; // don't need to flip...
      let jj_ = convert_u8to64 (jj);
      assert vec::len(jj_) == 2u;
      let j1 = jj_[0u]; // reversing
      let j2 = jj_[1u]; // reversing

      let h2_ = apply_constants (33u64, j2, h2, c2, c1);
      let h1_ = apply_constants (31u64, j1, h1, c1, c2);
      ret (h1_,h2_);
   }

   // finalization
   fn finalize (h1_: u64, h2_: u64, len: uint) -> (u64,u64) {
      let h1 = h1_;
      let h2 = h2_;

      h1 ^= len as u64;
      h2 ^= len as u64;

      h1 += h2;
      h2 += h1;

      h1 = fmix(h1);
      h2 = fmix(h2);

      h1 += h2;
      h2 += h1;

      ret (h1, h2);
   }

   let (h1, h2) = do_body (body, nblocks, h1, h2, c1, c2);
   let (h1, h2) = do_tail (tail, h1, h2, c1, c2);
   let (h1, h2) = finalize (h1, h2, nbytes);

   ret [h1, h2];
}

<|endoftext|>


<commit_before><commit_msg>Implement more From conversions for VirtualAddress (but remove From<u64>)<commit_after><|endoftext|>


<commit_before>use rand;
use rand::distributions::{IndependentSample, Range};

use std::{cmp, thread, time};
use std::fmt::Debug;

#[derive(Debug, PartialEq, Eq)]
pub enum RetryAction {
    OKAY,
    WAIT
}

pub trait RetryPolicy: Debug + PartialEq + Eq {
    fn max_tries(&self) -> usize;
    fn current_tries(&self) -> usize;

    fn fail(&mut self);
    fn succeed(&mut self);

    fn can_try(&self) -> Option<RetryAction> {
        if self.current_tries() >= self.max_tries() {
            None
        } else {
            Some(RetryAction::OKAY)
        }
    }

    fn is_down(&self) -> bool;
}

#[derive(Debug, PartialEq, Eq)]
pub enum RetryPolicyWrapper {
    ExponentialBackoff(ExponentialBackoffPolicy)
}

#[derive(Debug, PartialEq, Eq)]
pub struct ExponentialBackoffPolicy {
    max_tries: usize,
    current_tries: usize,
    last_try: time::Instant,
    wait: time::Duration
}

impl ExponentialBackoffPolicy {
    pub fn new(max_tries: usize) -> Self {
        ExponentialBackoffPolicy {
            max_tries,
            current_tries: 0,
            last_try: time::Instant::now(),
            wait: time::Duration::default()
        }
    }
}

impl RetryPolicy for ExponentialBackoffPolicy {
    fn max_tries(&self) -> usize {
        self.max_tries
    }

    fn current_tries(&self) -> usize {
        self.current_tries
    }

    fn fail(&mut self) {
        if self.last_try.elapsed().lt(&self.wait) {
          //we're already in back off
          return;
        }

        let max_secs = cmp::max(1, 1u64.wrapping_shl(self.current_tries as u32));
        let wait = if max_secs == 1 {
            1
        } else {
            let mut rng = rand::thread_rng();
            let range = Range::new(1, max_secs);
            range.ind_sample(&mut rng)
        };

        self.wait = time::Duration::from_secs(wait);
        self.last_try = time::Instant::now();
        self.current_tries += 1;
    }

    fn succeed(&mut self) {
        self.wait = time::Duration::default();
        self.last_try = time::Instant::now();
        self.current_tries = 0;
    }

    fn can_try(&self) -> Option<RetryAction> {
        if self.current_tries() >= self.max_tries() {
            return None;
        }

        let action = if self.last_try.elapsed().gt(&self.wait) {
            RetryAction::OKAY
        } else {
            RetryAction::WAIT
        };

        Some(action)
    }

    fn is_down(&self) -> bool {
      self.current_tries() >= self.max_tries()
    }
}

impl Into<RetryPolicyWrapper> for ExponentialBackoffPolicy {
    fn into(self) -> RetryPolicyWrapper {
        RetryPolicyWrapper::ExponentialBackoff(self)
    }
}

impl RetryPolicy for RetryPolicyWrapper {
    fn max_tries(&self) -> usize {
        match *self {
            RetryPolicyWrapper::ExponentialBackoff(ref policy) => policy
        }.max_tries()
    }

    fn current_tries(&self) -> usize {
        match *self {
            RetryPolicyWrapper::ExponentialBackoff(ref policy) => policy
        }.current_tries()
    }

    fn fail(&mut self) {
        match *self {
            RetryPolicyWrapper::ExponentialBackoff(ref mut policy) => policy
        }.fail()
    }

    fn succeed(&mut self) {
        match *self {
            RetryPolicyWrapper::ExponentialBackoff(ref mut policy) => policy
        }.succeed()
    }

    fn can_try(&self) -> Option<RetryAction> {
        match *self {
            RetryPolicyWrapper::ExponentialBackoff(ref policy) => policy
        }.can_try()
    }

    fn is_down(&self) -> bool {
        match *self {
            RetryPolicyWrapper::ExponentialBackoff(ref policy) => policy
        }.is_down()
    }
}

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

    use super::{RetryAction, RetryPolicy, ExponentialBackoffPolicy};

    const MAX_FAILS: usize = 10;

    #[test]
    fn no_fail() {
        let policy = ExponentialBackoffPolicy::new(MAX_FAILS);
        let can_try = policy.can_try();

        assert_eq!(Some(RetryAction::OKAY), can_try)
    }

    #[test]
    fn single_fail() {
        let mut policy = ExponentialBackoffPolicy::new(MAX_FAILS);
        policy.fail();
        let can_try = policy.can_try();

        // The wait will be >= 1s, so we'll be WAIT by the time we do the assert
        assert_eq!(Some(RetryAction::WAIT), can_try)
    }

    #[test]
    fn max_fails() {
        let mut policy = ExponentialBackoffPolicy::new(MAX_FAILS);

        for _ in 0..MAX_FAILS {
            policy.fail();
        }

        let can_try = policy.can_try();

        assert_eq!(None, can_try)
    }

    #[test]
    fn recover_from_fail() {
        let mut policy = ExponentialBackoffPolicy::new(MAX_FAILS);

        // Stop just before total failure
        for _ in 0..(MAX_FAILS - 1) {
            policy.fail();
        }

        policy.succeed();
        policy.fail();
        policy.fail();
        policy.fail();

        let can_try = policy.can_try();

        assert_eq!(Some(RetryAction::WAIT), can_try)
    }
}
<commit_msg>fix retry policy test<commit_after>use rand;
use rand::distributions::{IndependentSample, Range};

use std::{cmp, thread, time};
use std::fmt::Debug;

#[derive(Debug, PartialEq, Eq)]
pub enum RetryAction {
    OKAY,
    WAIT
}

pub trait RetryPolicy: Debug + PartialEq + Eq {
    fn max_tries(&self) -> usize;
    fn current_tries(&self) -> usize;

    fn fail(&mut self);
    fn succeed(&mut self);

    fn can_try(&self) -> Option<RetryAction> {
        if self.current_tries() >= self.max_tries() {
            None
        } else {
            Some(RetryAction::OKAY)
        }
    }

    fn is_down(&self) -> bool;
}

#[derive(Debug, PartialEq, Eq)]
pub enum RetryPolicyWrapper {
    ExponentialBackoff(ExponentialBackoffPolicy)
}

#[derive(Debug, PartialEq, Eq)]
pub struct ExponentialBackoffPolicy {
    max_tries: usize,
    current_tries: usize,
    last_try: time::Instant,
    wait: time::Duration
}

impl ExponentialBackoffPolicy {
    pub fn new(max_tries: usize) -> Self {
        ExponentialBackoffPolicy {
            max_tries,
            current_tries: 0,
            last_try: time::Instant::now(),
            wait: time::Duration::default()
        }
    }
}

impl RetryPolicy for ExponentialBackoffPolicy {
    fn max_tries(&self) -> usize {
        self.max_tries
    }

    fn current_tries(&self) -> usize {
        self.current_tries
    }

    fn fail(&mut self) {
        if self.last_try.elapsed().lt(&self.wait) {
          //we're already in back off
          return;
        }

        let max_secs = cmp::max(1, 1u64.wrapping_shl(self.current_tries as u32));
        let wait = if max_secs == 1 {
            1
        } else {
            let mut rng = rand::thread_rng();
            let range = Range::new(1, max_secs);
            range.ind_sample(&mut rng)
        };

        self.wait = time::Duration::from_secs(wait);
        self.last_try = time::Instant::now();
        self.current_tries += 1;
    }

    fn succeed(&mut self) {
        self.wait = time::Duration::default();
        self.last_try = time::Instant::now();
        self.current_tries = 0;
    }

    fn can_try(&self) -> Option<RetryAction> {
        if self.current_tries() >= self.max_tries() {
            return None;
        }

        let action = if self.last_try.elapsed().gt(&self.wait) {
            RetryAction::OKAY
        } else {
            RetryAction::WAIT
        };

        Some(action)
    }

    fn is_down(&self) -> bool {
      self.current_tries() >= self.max_tries()
    }
}

impl Into<RetryPolicyWrapper> for ExponentialBackoffPolicy {
    fn into(self) -> RetryPolicyWrapper {
        RetryPolicyWrapper::ExponentialBackoff(self)
    }
}

impl RetryPolicy for RetryPolicyWrapper {
    fn max_tries(&self) -> usize {
        match *self {
            RetryPolicyWrapper::ExponentialBackoff(ref policy) => policy
        }.max_tries()
    }

    fn current_tries(&self) -> usize {
        match *self {
            RetryPolicyWrapper::ExponentialBackoff(ref policy) => policy
        }.current_tries()
    }

    fn fail(&mut self) {
        match *self {
            RetryPolicyWrapper::ExponentialBackoff(ref mut policy) => policy
        }.fail()
    }

    fn succeed(&mut self) {
        match *self {
            RetryPolicyWrapper::ExponentialBackoff(ref mut policy) => policy
        }.succeed()
    }

    fn can_try(&self) -> Option<RetryAction> {
        match *self {
            RetryPolicyWrapper::ExponentialBackoff(ref policy) => policy
        }.can_try()
    }

    fn is_down(&self) -> bool {
        match *self {
            RetryPolicyWrapper::ExponentialBackoff(ref policy) => policy
        }.is_down()
    }
}

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

    use super::{RetryAction, RetryPolicy, ExponentialBackoffPolicy};

    const MAX_FAILS: usize = 10;

    #[test]
    fn no_fail() {
        let policy = ExponentialBackoffPolicy::new(MAX_FAILS);
        let can_try = policy.can_try();

        assert_eq!(Some(RetryAction::OKAY), can_try)
    }

    #[test]
    fn single_fail() {
        let mut policy = ExponentialBackoffPolicy::new(MAX_FAILS);
        policy.fail();
        let can_try = policy.can_try();

        // The wait will be >= 1s, so we'll be WAIT by the time we do the assert
        assert_eq!(Some(RetryAction::WAIT), can_try)
    }

    #[test]
    fn max_fails() {
        let mut policy = ExponentialBackoffPolicy::new(MAX_FAILS);

        for _ in 0..MAX_FAILS {
            policy.fail();
        }

        let can_try = policy.can_try();

        assert_eq!(Some(RetryAction::WAIT), can_try)
    }

    #[test]
    fn recover_from_fail() {
        let mut policy = ExponentialBackoffPolicy::new(MAX_FAILS);

        // Stop just before total failure
        for _ in 0..(MAX_FAILS - 1) {
            policy.fail();
        }

        policy.succeed();
        policy.fail();
        policy.fail();
        policy.fail();

        let can_try = policy.can_try();

        assert_eq!(Some(RetryAction::WAIT), can_try)
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::io::{BufRead, Read};
use std::str::FromStr;
use std::fmt;

use gc::Gc;
use interner::{Interner, InternedStr};

use self::Token::*;

#[derive(PartialEq, Copy, Clone, Debug)]
pub enum Token {
    TInteger(i64),
    TFloat(f64),
    TString(InternedStr),
    TChar(char),
    TTrue,
    TFalse,
    TIf,
    TElse,
    TWhile,
    TFor,
    TMatch,
    TData,
    TTrait,
    TImpl,
    TVariable(InternedStr),
    TConstructor(InternedStr),
    TOpenBrace,
    TCloseBrace,
    TOpenParen,
    TCloseParen,
    TOpenBracket,
    TCloseBracket,
    TOperator(InternedStr),
    TSemicolon,
    TDot,
    TComma,
    TColon,
    TLet,
    TAssign,
    TRArrow,
    TMatchArrow,
    TLambda,
    TEOF,
    TError(&'static str)
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Location {
    pub column : i32,
    pub row : i32,
    pub absolute : i32
}

impl Location {
    pub fn eof() -> Location {
        Location { column: -1, row: -1, absolute: -1 }
    }
}

impl fmt::Display for Location {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Line {}, Row {}", self.row, self.column)
    }
}

///Returns whether the character is a haskell operator
fn is_operator(first_char : char) -> bool {
    match first_char {
        '+' | '-' | '*' | '/' | '.' | '$' |
        ':' | '=' | '<' | '>' | '|' | '&' | '!' => true,
        _ => false
    }
}

pub struct Lexer<'a, 'b> {
    input: ::std::io::Chars<&'b mut (BufRead + 'b)>,
    buffer: String,
    peek_c: Option<char>,
    location: Location,
    tokens: VecDeque<Token>,
    offset: usize,
    interner: &'a mut Interner,
    gc: &'a mut Gc
}

impl <'a, 'b> Lexer<'a, 'b> {

    pub fn new(interner: &'a mut Interner, gc: &'a mut Gc, s: &'b mut BufRead) -> Lexer<'a, 'b> {
        let mut chars = s.chars();
        Lexer {
            peek_c: chars.next().and_then(|result| result.ok()),
            input: chars,
            buffer: String::new(),
            location: Location { row: 1, column: 1, absolute: 0 },
            tokens: VecDeque::with_capacity(20),
            offset: 0,
            interner: interner,
            gc: gc
        }
    }

    pub fn location(&self) -> Location {
        self.location
    }

    pub fn peek(&mut self) -> &Token {
        if self.offset != 0 && self.tokens.len() != 0 {
            &self.tokens[self.tokens.len() - self.offset]
        }
        else {
            self.next();
            self.backtrack();
            &self.tokens[self.tokens.len() - 1]
        }
    }

    ///Returns the next token in the lexer
    pub fn next(&mut self) -> &Token {
        if self.offset > 0 {
            self.offset -= 1;
        }
        else {
            let t = self.next_token();
            self.tokens.push_back(t);
            self.reset_str();
            debug!("Token {:?}", self.current());
        }
        self.current()
    }

    ///Returns a reference to the current token
    pub fn current(&self) -> &Token {
        &self.tokens[self.tokens.len() - self.offset - 1]
    }

    ///Moves the lexer back one token
    ///TODO check for overflow in the buffer
    pub fn backtrack(&mut self) {
        self.offset += 1;
    }

    ///Peeks at the next character in the input
    fn peek_char(&mut self) -> Option<char> {
        self.peek_c
    }

    fn reset_str(&mut self) {
        self.buffer.clear();
    }

    ///Reads a character from the input and increments the current position
    fn read_char(&mut self) -> Option<char> {
        let result = self.peek_c;
        match self.peek_c {
            Some(c) => {
                self.buffer.push(c);
                self.peek_c = self.input.next().and_then(|result| result.ok());
                self.location.absolute += 1;
                self.location.column += 1;
                if c == '\n' || c == '\r' {
                    self.location.column = 0;
                    self.location.row += 1;
                    //If this is a \n\r line ending skip the next char without increasing the location
                    if c == '\r' && self.peek_c == Some('\n') {
                        self.peek_c = self.input.next().and_then(|result| result.ok());
                    }
                }
            }
            None => ()
        }
        result
    }
    fn current_str(&self) -> &str {
        self.buffer.as_slice()
    }

    pub fn intern(&mut self, s: &str) -> InternedStr {
        self.interner.intern(self.gc, s)
    }
    fn intern_current(&mut self) -> InternedStr {
        self.interner.intern(self.gc, self.buffer.as_slice())
    }

    ///Scans digits into a string
    fn scan_digits(&mut self) {
        loop {
            match self.peek_char() {
                Some(x) => {
                    if !x.is_digit(10) {
                        break;
                    }
                    self.read_char();
                }
                None => break
            }
        }
    }
    ///Scans a number, float or integer and returns the appropriate token
    fn scan_number(&mut self) -> Token {
        self.scan_digits();
        let mut is_float = false;
        match self.peek_char() {
            Some('.') => {
                self.read_char();
                is_float = true;
                self.scan_digits();
            }
            _ => ()
        }
        if is_float {
            TFloat(FromStr::from_str(self.current_str()).unwrap())
        }
        else {
            TInteger(FromStr::from_str(self.current_str()).unwrap())
        }
    }

    ///Scans an identifier or a keyword
    fn scan_identifier(&mut self) -> Token {
        loop {
            match self.peek_char() {
                Some(ch) => {
                    if !ch.is_alphanumeric() && ch != '_' {
                        break;
                    }
                    self.read_char();
                }
                None => break
            }
        }
        match self.current_str() {
            "if" => TIf,
            "else" => TElse,
            "while" => TWhile,
            "for" => TFor,
            "match" => TMatch,
            "trait" => TTrait,
            "impl" => TImpl,
            "data" => TData,
            "let" => TLet,
            "true" => TTrue,
            "false" => TFalse,
            _ => {
                let s = self.intern_current();
                if s.char_at(0).is_uppercase() {
                    TConstructor(s)
                }
                else {
                    TVariable(s)
                }
            }
        }
    }

    ///Scans the character stream for the next token
    ///Return EOF token if the token stream has ehas ended
    fn next_token(&mut self) -> Token {
        let mut c = ' ';
        //Skip all whitespace before the token
        while c.is_whitespace() {
            self.reset_str();
            match self.read_char() {
                Some(x) => {
                    c = x;
                }
                None => { return TEOF }
            }
        }

        //Decide how to tokenize depending on what the first char is
        //ie if its an operator then more operators will follow
        if is_operator(c) {
            loop {
                match self.peek_char() {
                    Some(ch) => {
                        if !is_operator(ch) {
                            break;
                        }
                        self.read_char();
                    }
                    None => { break; }
                }
            }
            return match self.current_str() {
                "=" => TAssign,
                ":" => TColon,
                "->" => TRArrow,
                "." => TDot,
                "=>" => TMatchArrow,
                _ => TOperator(self.intern_current())
            }
        }
        else if c.is_digit(10) {
            return self.scan_number();
        }
        else if c.is_alphabetic() || c == '_' {
            return self.scan_identifier();
        }
        else if c == '"' {
            loop {
                match self.read_char() {
                    Some('"') => {
                        //Drop the '"' at the start and end
                        let contents = &self.buffer[1..self.buffer.len() - 1];
                        let s = self.interner.intern(self.gc, contents);
                        return TString(s)
                    }
                    Some(_) => (),
                    None => return TError("Unexpected EOF when lexing string literal")
                }
            }
        }
        else if c == '\'' {
            match self.read_char() {
                Some(x) => {
                    return if self.read_char() == Some('\'') {
                        TChar(x)
                    }
                    else {
                        TError("Attempted to lex a character literal with multiple character")
                    }
                }
                None => return TError("Unexpected EOF when lexing char literal")
            }
        }
        else {
            match c {
                ';' => TSemicolon,
                '(' => TOpenParen,
                ')' => TCloseParen,
                '[' => TOpenBracket,
                ']' => TCloseBracket,
                '{' => TOpenBrace,
                '}' => TCloseBrace,
                ',' => TComma,
                '\\' => TLambda,
                _   => TEOF
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use lexer;
    use lexer::Token::*;
    use gc::Gc;
    use interner::Interner;
    use std::io::BufReader;

    #[test]
    fn lex() {
        let mut buffer = BufReader::new("main : () -> Int; main = { 1 + 2 }".as_bytes());
        let mut gc = Gc::new();
        let mut interner = Interner::new();
        let mut lexer = lexer::Lexer::new(&mut interner, &mut gc, &mut buffer);
        let plus = lexer.intern("+");
        let main = lexer.intern("main");
        let i = lexer.intern("Int");
        assert_eq!(lexer.next(), &TVariable(main));
        assert_eq!(lexer.next(), &TColon);
        assert_eq!(lexer.next(), &TOpenParen);
        assert_eq!(lexer.next(), &TCloseParen);
        assert_eq!(lexer.next(), &TRArrow);
        assert_eq!(lexer.next(), &TConstructor(i));
        assert_eq!(lexer.next(), &TSemicolon);
        assert_eq!(lexer.next(), &TVariable(main));
        assert_eq!(lexer.next(), &TAssign);
        assert_eq!(lexer.next(), &TOpenBrace);
        assert_eq!(lexer.next(), &TInteger(1));
        assert_eq!(lexer.next(), &TOperator(plus));
        assert_eq!(lexer.next(), &TInteger(2));
        assert_eq!(lexer.next(), &TCloseBrace);
    }
}
<commit_msg>Cleared up the lexer a bit and fixed a TODO<commit_after>use std::collections::VecDeque;
use std::io::{BufRead, Read};
use std::str::FromStr;
use std::fmt;

use gc::Gc;
use interner::{Interner, InternedStr};

use self::Token::*;

#[derive(PartialEq, Copy, Clone, Debug)]
pub enum Token {
    TInteger(i64),
    TFloat(f64),
    TString(InternedStr),
    TChar(char),
    TTrue,
    TFalse,
    TIf,
    TElse,
    TWhile,
    TFor,
    TMatch,
    TData,
    TTrait,
    TImpl,
    TVariable(InternedStr),
    TConstructor(InternedStr),
    TOpenBrace,
    TCloseBrace,
    TOpenParen,
    TCloseParen,
    TOpenBracket,
    TCloseBracket,
    TOperator(InternedStr),
    TSemicolon,
    TDot,
    TComma,
    TColon,
    TLet,
    TAssign,
    TRArrow,
    TMatchArrow,
    TLambda,
    TEOF,
    TError(&'static str)
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Location {
    pub column : i32,
    pub row : i32,
    pub absolute : i32
}

impl Location {
    pub fn eof() -> Location {
        Location { column: -1, row: -1, absolute: -1 }
    }
}

impl fmt::Display for Location {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Line {}, Row {}", self.row, self.column)
    }
}

///Returns whether the character is a haskell operator
fn is_operator(first_char : char) -> bool {
    match first_char {
        '+' | '-' | '*' | '/' | '.' | '$' |
        ':' | '=' | '<' | '>' | '|' | '&' | '!' => true,
        _ => false
    }
}

pub struct Lexer<'a, 'b> {
    input: ::std::io::Chars<&'b mut (BufRead + 'b)>,
    buffer: String,
    peek_c: Option<char>,
    location: Location,
    tokens: VecDeque<Token>,
    offset: usize,
    interner: &'a mut Interner,
    gc: &'a mut Gc
}

impl <'a, 'b> Lexer<'a, 'b> {

    pub fn new(interner: &'a mut Interner, gc: &'a mut Gc, s: &'b mut BufRead) -> Lexer<'a, 'b> {
        let mut chars = s.chars();
        Lexer {
            peek_c: chars.next().and_then(|result| result.ok()),
            input: chars,
            buffer: String::new(),
            location: Location { row: 1, column: 1, absolute: 0 },
            tokens: VecDeque::with_capacity(20),
            offset: 0,
            interner: interner,
            gc: gc
        }
    }

    pub fn location(&self) -> Location {
        self.location
    }

    pub fn peek(&mut self) -> &Token {
        if self.offset != 0 && self.tokens.len() != 0 {
            &self.tokens[self.tokens.len() - self.offset]
        }
        else {
            self.next();
            self.backtrack();
            &self.tokens[self.tokens.len() - 1]
        }
    }

    ///Returns the next token in the lexer
    pub fn next(&mut self) -> &Token {
        if self.offset > 0 {
            self.offset -= 1;
        }
        else {
            let t = self.next_token();
            self.tokens.push_back(t);
            self.reset_str();
            debug!("Token {:?}", self.current());
        }
        self.current()
    }

    ///Returns a reference to the current token
    pub fn current(&self) -> &Token {
        &self.tokens[self.tokens.len() - self.offset - 1]
    }

    ///Moves the lexer back one token
    pub fn backtrack(&mut self) {
        self.offset += 1;
        if self.offset > self.tokens.len() {
            panic!("ICE:{} Backtracked outside the token buffer", self.location());
        }
    }

    ///Peeks at the next character in the input
    fn peek_char(&mut self) -> Option<char> {
        self.peek_c
    }

    fn reset_str(&mut self) {
        self.buffer.clear();
    }

    ///Reads a character from the input and increments the current position
    fn read_char(&mut self) -> Option<char> {
        let result = self.peek_c;
        match self.peek_c {
            Some(c) => {
                self.buffer.push(c);
                self.peek_c = self.input.next().and_then(|result| result.ok());
                self.location.absolute += 1;
                self.location.column += 1;
                if c == '\n' || c == '\r' {
                    self.location.column = 0;
                    self.location.row += 1;
                    //If this is a \n\r line ending skip the next char without increasing the location
                    if c == '\r' && self.peek_c == Some('\n') {
                        self.peek_c = self.input.next().and_then(|result| result.ok());
                    }
                }
            }
            None => ()
        }
        result
    }
    fn current_str(&self) -> &str {
        self.buffer.as_slice()
    }

    pub fn intern(&mut self, s: &str) -> InternedStr {
        self.interner.intern(self.gc, s)
    }
    fn intern_current(&mut self) -> InternedStr {
        self.interner.intern(self.gc, self.buffer.as_slice())
    }

    ///Scans digits into a string
    fn scan_digits(&mut self) {
        loop {
            match self.peek_char() {
                Some(x) if x.is_digit(10) =>  {
                    self.read_char();
                }
                _ => break
            }
        }
    }
    ///Scans a number, float or integer and returns the appropriate token
    fn scan_number(&mut self) -> Token {
        self.scan_digits();
        let mut is_float = false;
        if self.peek_char() == Some('.') {
            self.read_char();
            is_float = true;
            self.scan_digits();
        }
        if is_float {
            TFloat(FromStr::from_str(self.current_str()).unwrap())
        }
        else {
            TInteger(FromStr::from_str(self.current_str()).unwrap())
        }
    }

    ///Scans an identifier or a keyword
    fn scan_identifier(&mut self) -> Token {
        loop {
            match self.peek_char() {
                Some(ch) if ch.is_alphanumeric() || ch == '_' => {
                    self.read_char();
                }
                _ => break
            }
        }
        match self.current_str() {
            "if" => TIf,
            "else" => TElse,
            "while" => TWhile,
            "for" => TFor,
            "match" => TMatch,
            "trait" => TTrait,
            "impl" => TImpl,
            "data" => TData,
            "let" => TLet,
            "true" => TTrue,
            "false" => TFalse,
            _ => {
                let s = self.intern_current();
                if s.char_at(0).is_uppercase() {
                    TConstructor(s)
                }
                else {
                    TVariable(s)
                }
            }
        }
    }

    ///Scans the character stream for the next token
    ///Return EOF token if the token stream has ehas ended
    fn next_token(&mut self) -> Token {
        let mut c = ' ';
        //Skip all whitespace before the token
        while c.is_whitespace() {
            self.reset_str();
            match self.read_char() {
                Some(x) => {
                    c = x;
                }
                None => { return TEOF }
            }
        }

        //Decide how to tokenize depending on what the first char is
        //ie if its an operator then more operators will follow
        if is_operator(c) {
            loop {
                match self.peek_char() {
                    Some(ch) if is_operator(ch) => {
                        self.read_char();
                    }
                    _ => break
                }
            }
            return match self.current_str() {
                "=" => TAssign,
                ":" => TColon,
                "->" => TRArrow,
                "." => TDot,
                "=>" => TMatchArrow,
                _ => TOperator(self.intern_current())
            }
        }
        else if c.is_digit(10) {
            return self.scan_number();
        }
        else if c.is_alphabetic() || c == '_' {
            return self.scan_identifier();
        }
        else if c == '"' {
            loop {
                match self.read_char() {
                    Some('"') => {
                        //Drop the '"' at the start and end
                        let contents = &self.buffer[1..self.buffer.len() - 1];
                        let s = self.interner.intern(self.gc, contents);
                        return TString(s)
                    }
                    Some(_) => (),
                    None => return TError("Unexpected EOF when lexing string literal")
                }
            }
        }
        else if c == '\'' {
            match self.read_char() {
                Some(x) => {
                    return if self.read_char() == Some('\'') {
                        TChar(x)
                    }
                    else {
                        TError("Attempted to lex a character literal with multiple characters")
                    }
                }
                None => return TError("Unexpected EOF when lexing char literal")
            }
        }
        else {
            match c {
                ';' => TSemicolon,
                '(' => TOpenParen,
                ')' => TCloseParen,
                '[' => TOpenBracket,
                ']' => TCloseBracket,
                '{' => TOpenBrace,
                '}' => TCloseBrace,
                ',' => TComma,
                '\\' => TLambda,
                _   => TEOF
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use lexer;
    use lexer::Token::*;
    use gc::Gc;
    use interner::Interner;
    use std::io::BufReader;

    #[test]
    fn lex() {
        let mut buffer = BufReader::new("main : () -> Int; main = { 1 + 2 }".as_bytes());
        let mut gc = Gc::new();
        let mut interner = Interner::new();
        let mut lexer = lexer::Lexer::new(&mut interner, &mut gc, &mut buffer);
        let plus = lexer.intern("+");
        let main = lexer.intern("main");
        let i = lexer.intern("Int");
        assert_eq!(lexer.next(), &TVariable(main));
        assert_eq!(lexer.next(), &TColon);
        assert_eq!(lexer.next(), &TOpenParen);
        assert_eq!(lexer.next(), &TCloseParen);
        assert_eq!(lexer.next(), &TRArrow);
        assert_eq!(lexer.next(), &TConstructor(i));
        assert_eq!(lexer.next(), &TSemicolon);
        assert_eq!(lexer.next(), &TVariable(main));
        assert_eq!(lexer.next(), &TAssign);
        assert_eq!(lexer.next(), &TOpenBrace);
        assert_eq!(lexer.next(), &TInteger(1));
        assert_eq!(lexer.next(), &TOperator(plus));
        assert_eq!(lexer.next(), &TInteger(2));
        assert_eq!(lexer.next(), &TCloseBrace);
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Bytes;

#[derive(Debug)]
pub enum Mnemonic {
    Add, Call, Cls, Drw,
    Jp, Ld, Or, Ret,
    Rnd, Se, Shl, Shr,
    Sknp, Skp, Sne, Sub,
    Subn, Sys, Xor,
}

#[derive(Debug)]
pub enum Register {
    V0, V1, V2, V3,
    V4, V5, V6, V7,
    V8, V9, Va, Vb,
    Vc, Vd, Ve, Vf,
    Sp, Pc, I, St, Dt, IVal,
}

#[derive(Debug)]
pub enum Token {
    Opcode(Mnemonic),
    Reg(Register),
    ImmConst(u16),
}

pub struct Stream {
    input: Bytes<File>,
    line: u32,
}

impl Stream {
    pub fn new(input: Bytes<File>) -> Stream {
        Stream {
            input: input,
            line: 1,
        }
    }

    pub fn next_token(&mut self) -> Option<Token> {
        let mut buffer: Vec<u8> = vec![];

        loop {
            let bs = self.input.next().map_or(None, |bm| match bm {
                Ok(b) => Some(b),
                _ => None
            });

            match bs {
                Some(b) => {
                    if Stream::is_separator(b) {
                        if (b as char) == '\n' {
                            self.line += 1;
                        }
                        if buffer.len() > 0 {
                            return Stream::create_token(buffer);
                        }
                    } else {
                        buffer.push(b);
                    }
                },
                None => {
                    return Stream::create_token(buffer);
                }
            }
        }
    }

    pub fn line(&self) -> u32 {
        self.line
    }

    fn create_token(input: Vec<u8>) -> Option<Token> {
        let token_str: String = String::from_utf8(input).unwrap_or_else(|err| {
            println!("Error: {:?}", err);
            "".to_owned()
        }).to_lowercase();

        let (numeric, radix) = Stream::is_numeric(&token_str);
        if numeric {
            return match radix {
                // base 10
                0 => Some(Token::ImmConst(token_str.parse::<u16>().unwrap())),
                // base 16
                1 => Some(Token::ImmConst(u16::from_str_radix(&token_str[2..], 16).unwrap())),
                _ => None,
            }

        }

        if Stream::is_register(&token_str) {
            return match token_str.as_str() {
                "v0"   => Some(Token::Reg(Register::V0)),
                "v1"   => Some(Token::Reg(Register::V1)),
                "v2"   => Some(Token::Reg(Register::V2)),
                "v3"   => Some(Token::Reg(Register::V3)),
                "v4"   => Some(Token::Reg(Register::V4)),
                "v5"   => Some(Token::Reg(Register::V5)),
                "v6"   => Some(Token::Reg(Register::V6)),
                "v7"   => Some(Token::Reg(Register::V7)),
                "v8"   => Some(Token::Reg(Register::V8)),
                "v9"   => Some(Token::Reg(Register::V9)),
                "va"   => Some(Token::Reg(Register::Va)),
                "vb"   => Some(Token::Reg(Register::Vb)),
                "vc"   => Some(Token::Reg(Register::Vc)),
                "vd"   => Some(Token::Reg(Register::Vd)),
                "ve"   => Some(Token::Reg(Register::Ve)),
                "vf"   => Some(Token::Reg(Register::Vf)),
                "sp"   => Some(Token::Reg(Register::Sp)),
                "st"   => Some(Token::Reg(Register::St)),
                "dt"   => Some(Token::Reg(Register::Dt)),
                "pc"   => Some(Token::Reg(Register::Pc)),
                "i"    => Some(Token::Reg(Register::I)),
                "[i]"  => Some(Token::Reg(Register::IVal)),
                _      => None
            }
        }

        match token_str.as_str() {
            "add"   => Some(Token::Opcode(Mnemonic::Add)),
            "call"  => Some(Token::Opcode(Mnemonic::Call)),
            "cls"   => Some(Token::Opcode(Mnemonic::Cls)),
            "drw"   => Some(Token::Opcode(Mnemonic::Drw)),
            "jp"    => Some(Token::Opcode(Mnemonic::Jp)),
            "ld"    => Some(Token::Opcode(Mnemonic::Ld)),
            "or"    => Some(Token::Opcode(Mnemonic::Or)),
            "ret"   => Some(Token::Opcode(Mnemonic::Ret)),
            "rnd"   => Some(Token::Opcode(Mnemonic::Rnd)),
            "se"    => Some(Token::Opcode(Mnemonic::Se)),
            "shl"   => Some(Token::Opcode(Mnemonic::Shl)),
            "shr"   => Some(Token::Opcode(Mnemonic::Shr)),
            "sknp"  => Some(Token::Opcode(Mnemonic::Sknp)),
            "skp"   => Some(Token::Opcode(Mnemonic::Skp)),
            "sne"   => Some(Token::Opcode(Mnemonic::Sne)),
            "sub"   => Some(Token::Opcode(Mnemonic::Sub)),
            "subn"  => Some(Token::Opcode(Mnemonic::Subn)),
            "sys"   => Some(Token::Opcode(Mnemonic::Sys)),
            "xor"   => Some(Token::Opcode(Mnemonic::Xor)),
            _       => None
        }
    }

    fn is_separator(b: u8) -> bool {
        match b as char {
            ','|' '|'\n' | '\t' => { true }
            _ => { false }
        }
    }

    fn is_register(input: &str) -> bool {
        input == "v0" || input == "v1" || input == "v2" ||
        input == "v3" || input == "v4" || input == "v5" ||
        input == "v6" || input == "v7" || input == "v8" ||
        input == "v9" || input == "va" || input == "vb" ||
        input == "vc" || input == "vd" || input == "ve" ||
        input == "vf" || input == "sp" || input == "st" ||
        input == "dt" || input == "pc" || input == "i" ||
        input == "[i]"
    }

    // Returns a tuple of boolean and integer
    // The input is numeric if the boolean component of the result is true
    // Integer component of result:
    //   0 => base 10
    //   1 => base 16
    fn is_numeric(input: &str) -> (bool, u8) {
        if input.len() < 1 {
            return (false, ::std::u8::MAX);
        }

        let in_bytes = input.as_bytes();
        if !Stream::is_ascii_numeric(in_bytes[0]) {
            return (false, ::std::u8::MAX);
        }

        // hex
        if input.starts_with("0x") {
            for i in 2..(in_bytes.len()) {
                if !Stream::is_ascii_hex(in_bytes[i]) {
                    return (false, ::std::u8::MAX);
                }
                return (true, 1);
            }
        } else {
            for b in in_bytes {
                if !Stream::is_ascii_numeric(*b) {
                    return (false, ::std::u8::MAX);
                }
                return (true, 0);
            }
        }
        return (false, ::std::u8::MAX);
    }

    fn is_ascii_numeric(input: u8) -> bool {
        input >= 48 && input <= 57
    }

    fn is_ascii_hex(input: u8) -> bool {
        (input >= 48 && input <= 57) || ((input >= 97 && input <= 102) || (input >= 65 && input <= 70))
    }
}
<commit_msg>Add a second data field for a line number to all variants of Token<commit_after>use std::fs::File;
use std::io::Bytes;

#[derive(Debug)]
pub enum Mnemonic {
    Add, Call, Cls, Drw,
    Jp, Ld, Or, Ret,
    Rnd, Se, Shl, Shr,
    Sknp, Skp, Sne, Sub,
    Subn, Sys, Xor,
}

#[derive(Debug)]
pub enum Register {
    V0, V1, V2, V3,
    V4, V5, V6, V7,
    V8, V9, Va, Vb,
    Vc, Vd, Ve, Vf,
    Sp, Pc, I, St, Dt, IVal,
}

#[derive(Debug)]
pub enum Token {
    Opcode(Mnemonic, u32),
    Reg(Register, u32),
    ImmConst(u16, u32),
}

pub struct Stream {
    input: Bytes<File>,
    line: u32,
}

impl Stream {
    pub fn new(input: Bytes<File>) -> Stream {
        Stream {
            input: input,
            line: 1,
        }
    }

    pub fn next_token(&mut self) -> Option<Token> {
        let mut buffer: Vec<u8> = vec![];

        loop {
            let bs = self.input.next().map_or(None, |bm| match bm {
                Ok(b) => Some(b),
                _ => None
            });

            match bs {
                Some(b) => {
                    if Stream::is_separator(b) {
                        if buffer.len() > 0 {
                            return Stream::create_token(buffer, self.line);
                        }
                        if (b as char) == '\n' {
                            self.line += 1;
                        }
                    } else {
                        buffer.push(b);
                    }
                },
                None => {
                    return Stream::create_token(buffer, self.line);
                }
            }
        }
    }

    pub fn line(&self) -> u32 {
        self.line
    }

    fn create_token(input: Vec<u8>, line: u32) -> Option<Token> {
        let token_str: String = String::from_utf8(input).unwrap_or_else(|err| {
            println!("Error: {:?}", err);
            "".to_owned()
        }).to_lowercase();

        let (numeric, radix) = Stream::is_numeric(&token_str);
        if numeric {
            return match radix {
                // base 10
                0 => Some(Token::ImmConst(token_str.parse::<u16>().unwrap(), line)),
                // base 16
                1 => Some(Token::ImmConst(u16::from_str_radix(&token_str[2..], 16).unwrap(), line)),
                _ => None,
            }

        }

        if Stream::is_register(&token_str) {
            return match token_str.as_str() {
                "v0"   => Some(Token::Reg(Register::V0, line)),
                "v1"   => Some(Token::Reg(Register::V1, line)),
                "v2"   => Some(Token::Reg(Register::V2, line)),
                "v3"   => Some(Token::Reg(Register::V3, line)),
                "v4"   => Some(Token::Reg(Register::V4, line)),
                "v5"   => Some(Token::Reg(Register::V5, line)),
                "v6"   => Some(Token::Reg(Register::V6, line)),
                "v7"   => Some(Token::Reg(Register::V7, line)),
                "v8"   => Some(Token::Reg(Register::V8, line)),
                "v9"   => Some(Token::Reg(Register::V9, line)),
                "va"   => Some(Token::Reg(Register::Va, line)),
                "vb"   => Some(Token::Reg(Register::Vb, line)),
                "vc"   => Some(Token::Reg(Register::Vc, line)),
                "vd"   => Some(Token::Reg(Register::Vd, line)),
                "ve"   => Some(Token::Reg(Register::Ve, line)),
                "vf"   => Some(Token::Reg(Register::Vf, line)),
                "sp"   => Some(Token::Reg(Register::Sp, line)),
                "st"   => Some(Token::Reg(Register::St, line)),
                "dt"   => Some(Token::Reg(Register::Dt, line)),
                "pc"   => Some(Token::Reg(Register::Pc, line)),
                "i"    => Some(Token::Reg(Register::I, line)),
                "[i]"  => Some(Token::Reg(Register::IVal, line)),
                _      => None
            }
        }

        match token_str.as_str() {
            "add"   => Some(Token::Opcode(Mnemonic::Add, line)),
            "call"  => Some(Token::Opcode(Mnemonic::Call, line)),
            "cls"   => Some(Token::Opcode(Mnemonic::Cls, line)),
            "drw"   => Some(Token::Opcode(Mnemonic::Drw, line)),
            "jp"    => Some(Token::Opcode(Mnemonic::Jp, line)),
            "ld"    => Some(Token::Opcode(Mnemonic::Ld, line)),
            "or"    => Some(Token::Opcode(Mnemonic::Or, line)),
            "ret"   => Some(Token::Opcode(Mnemonic::Ret, line)),
            "rnd"   => Some(Token::Opcode(Mnemonic::Rnd, line)),
            "se"    => Some(Token::Opcode(Mnemonic::Se, line)),
            "shl"   => Some(Token::Opcode(Mnemonic::Shl, line)),
            "shr"   => Some(Token::Opcode(Mnemonic::Shr, line)),
            "sknp"  => Some(Token::Opcode(Mnemonic::Sknp, line)),
            "skp"   => Some(Token::Opcode(Mnemonic::Skp, line)),
            "sne"   => Some(Token::Opcode(Mnemonic::Sne, line)),
            "sub"   => Some(Token::Opcode(Mnemonic::Sub, line)),
            "subn"  => Some(Token::Opcode(Mnemonic::Subn, line)),
            "sys"   => Some(Token::Opcode(Mnemonic::Sys, line)),
            "xor"   => Some(Token::Opcode(Mnemonic::Xor, line)),
            _       => None
        }
    }

    fn is_separator(b: u8) -> bool {
        match b as char {
            ','|' '|'\n' | '\t' => { true }
            _ => { false }
        }
    }

    fn is_register(input: &str) -> bool {
        input == "v0" || input == "v1" || input == "v2" ||
        input == "v3" || input == "v4" || input == "v5" ||
        input == "v6" || input == "v7" || input == "v8" ||
        input == "v9" || input == "va" || input == "vb" ||
        input == "vc" || input == "vd" || input == "ve" ||
        input == "vf" || input == "sp" || input == "st" ||
        input == "dt" || input == "pc" || input == "i" ||
        input == "[i]"
    }

    // Returns a tuple of boolean and integer
    // The input is numeric if the boolean component of the result is true
    // Integer component of result:
    //   0 => base 10
    //   1 => base 16
    fn is_numeric(input: &str) -> (bool, u8) {
        if input.len() < 1 {
            return (false, ::std::u8::MAX);
        }

        let in_bytes = input.as_bytes();
        if !Stream::is_ascii_numeric(in_bytes[0]) {
            return (false, ::std::u8::MAX);
        }

        // hex
        if input.starts_with("0x") {
            for i in 2..(in_bytes.len()) {
                if !Stream::is_ascii_hex(in_bytes[i]) {
                    return (false, ::std::u8::MAX);
                }
                return (true, 1);
            }
        } else {
            for b in in_bytes {
                if !Stream::is_ascii_numeric(*b) {
                    return (false, ::std::u8::MAX);
                }
                return (true, 0);
            }
        }
        return (false, ::std::u8::MAX);
    }

    fn is_ascii_numeric(input: u8) -> bool {
        input >= 48 && input <= 57
    }

    fn is_ascii_hex(input: u8) -> bool {
        (input >= 48 && input <= 57) || ((input >= 97 && input <= 102) || (input >= 65 && input <= 70))
    }
}
<|endoftext|>


<commit_before><commit_msg>pb-rs: Allow hexadecimal tag numbers<commit_after><|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::Error as FmtError;
use std::clone::Clone;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LinkErrorKind {
    EntryHeaderReadError,
    EntryHeaderWriteError,
    ExistingLinkTypeWrong,
    LinkTargetDoesNotExist,
    InternalConversionError,
    InvalidUri,
    StoreReadError,
}

fn link_error_type_as_str(e: &LinkErrorKind) -> &'static str {
    match e {
        &LinkErrorKind::EntryHeaderReadError
            => "Error while reading an entry header",

        &LinkErrorKind::EntryHeaderWriteError
            => "Error while writing an entry header",

        &LinkErrorKind::ExistingLinkTypeWrong
            => "Existing link entry has wrong type",

        &LinkErrorKind::LinkTargetDoesNotExist
            => "Link target does not exist in the store",

        &LinkErrorKind::InternalConversionError
            => "Error while converting values internally",

        &LinkErrorKind::InvalidUri
            => "URI is not valid",

        &LinkErrorKind::StoreReadError
            => "Store read error",
    }
}

impl Display for LinkErrorKind {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "{}", link_error_type_as_str(self)));
        Ok(())
    }

}

#[derive(Debug)]
pub struct LinkError {
    kind: LinkErrorKind,
    cause: Option<Box<Error>>,
}

impl LinkError {

    pub fn new(errtype: LinkErrorKind, cause: Option<Box<Error>>) -> LinkError {
        LinkError {
            kind: errtype,
            cause: cause,
        }
    }

}

impl Display for LinkError {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "[{}]", link_error_type_as_str(&self.kind)));
        Ok(())
    }

}

impl Error for LinkError {

    fn description(&self) -> &str {
        link_error_type_as_str(&self.kind)
    }

    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e)
    }

}
<commit_msg>Add StoreWriteError error type<commit_after>use std::error::Error;
use std::fmt::Error as FmtError;
use std::clone::Clone;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LinkErrorKind {
    EntryHeaderReadError,
    EntryHeaderWriteError,
    ExistingLinkTypeWrong,
    LinkTargetDoesNotExist,
    InternalConversionError,
    InvalidUri,
    StoreReadError,
    StoreWriteError,
}

fn link_error_type_as_str(e: &LinkErrorKind) -> &'static str {
    match e {
        &LinkErrorKind::EntryHeaderReadError
            => "Error while reading an entry header",

        &LinkErrorKind::EntryHeaderWriteError
            => "Error while writing an entry header",

        &LinkErrorKind::ExistingLinkTypeWrong
            => "Existing link entry has wrong type",

        &LinkErrorKind::LinkTargetDoesNotExist
            => "Link target does not exist in the store",

        &LinkErrorKind::InternalConversionError
            => "Error while converting values internally",

        &LinkErrorKind::InvalidUri
            => "URI is not valid",

        &LinkErrorKind::StoreReadError
            => "Store read error",

        &LinkErrorKind::StoreWriteError
            => "Store write error",
    }
}

impl Display for LinkErrorKind {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "{}", link_error_type_as_str(self)));
        Ok(())
    }

}

#[derive(Debug)]
pub struct LinkError {
    kind: LinkErrorKind,
    cause: Option<Box<Error>>,
}

impl LinkError {

    pub fn new(errtype: LinkErrorKind, cause: Option<Box<Error>>) -> LinkError {
        LinkError {
            kind: errtype,
            cause: cause,
        }
    }

}

impl Display for LinkError {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "[{}]", link_error_type_as_str(&self.kind)));
        Ok(())
    }

}

impl Error for LinkError {

    fn description(&self) -> &str {
        link_error_type_as_str(&self.kind)
    }

    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e)
    }

}
<|endoftext|>


<commit_before>/*
  This Source Code Form is subject to the terms of the Mozilla Public
  License, v. 2.0. If a copy of the MPL was not distributed with this
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

use rusqlite::Connection;

#[derive(Debug, Default)]
/// Represent the content view. Applies to `Collection` and `Folder`
pub struct Content {
    /// Filter
    pub filter: Option<String>,
    /// What to sort on
    pub sort_type: Option<String>,
    /// Which direction to sort
    pub sort_direction: Option<String>,
    /// Define the smart collection (if any)
    pub smart_collection: Option<String>,
}

impl Content {
    pub fn from_db(
        conn: &Connection,
        table: &str,
        container_col: &str,
        container_id: i64,
    ) -> Content {
        let mut content = Content::default();

        let query = format!(
            "SELECT content,owningModule from {} where {}=?1",
            table, container_col
        );
        if let Ok(mut stmt) = conn.prepare(&query) {
            let mut rows = stmt.query(&[&container_id]).unwrap();
            while let Some(Ok(row)) = rows.next() {
                let value = row.get_checked(0);
                let owning_module: String = row.get(1);
                match owning_module.as_str() {
                    "com.adobe.ag.library.filter" => content.filter = value.ok(),
                    "com.adobe.ag.library.sortType" => content.sort_type = value.ok(),
                    "com.adobe.ag.library.sortDirection" => content.sort_direction = value.ok(),
                    "ag.library.smart_collection" => content.smart_collection = value.ok(),
                    _ => (),
                };
            }
        }
        content
    }
}
<commit_msg>Content has custom Debug. SortDirection enum.<commit_after>/*
  This Source Code Form is subject to the terms of the Mozilla Public
  License, v. 2.0. If a copy of the MPL was not distributed with this
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

use std::fmt;

use rusqlite::Connection;

#[derive(Debug)]
pub enum SortDirection {
    Ascending,
    Descending,
    Unknown,
}

#[derive(Default)]
/// Represent the content view. Applies to `Collection` and `Folder`
pub struct Content {
    /// Filter
    pub filter: Option<String>,
    /// What to sort on
    pub sort_type: Option<String>,
    /// Which direction to sort
    pub sort_direction: Option<SortDirection>,
    /// Define the smart collection (if any)
    pub smart_collection: Option<String>,
}

impl fmt::Debug for Content {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut empty: bool = true;
        if let Some(ref filter) = self.filter {
            try!(write!(f, "filter: {:?}", filter));
            empty = false;
        }
        if let Some(ref sort_type) = self.sort_type {
            if !empty {
                try!(write!(f, ", "));
            }
            try!(write!(f, "sort: {:?}", sort_type));
            empty = false;
        }
        if let Some(ref direction) = self.sort_direction {
            if !empty {
                try!(write!(f, ", "));
            }
            try!(write!(f, "direction: {:?}", direction));
            empty = false;
        }
        if let Some(ref smart_coll) = self.smart_collection {
            if !empty {
                try!(write!(f, ", "));
            }
            try!(write!(f, "smart_collection: {:?}", smart_coll));
        }
        Ok(())
    }
}

impl Content {
    pub fn from_db(
        conn: &Connection,
        table: &str,
        container_col: &str,
        container_id: i64,
    ) -> Content {
        let mut content = Content::default();

        let query = format!(
            "SELECT content,owningModule from {} where {}=?1",
            table, container_col
        );
        if let Ok(mut stmt) = conn.prepare(&query) {
            let mut rows = stmt.query(&[&container_id]).unwrap();
            while let Some(Ok(row)) = rows.next() {
                let value = row.get_checked(0);
                let owning_module: String = row.get(1);
                match owning_module.as_str() {
                    "com.adobe.ag.library.filter" => content.filter = value.ok(),
                    "com.adobe.ag.library.sortType" => content.sort_type = value.ok(),
                    "com.adobe.ag.library.sortDirection" => {
                        content.sort_direction = if let Some(sd) = value.ok() {
                            match sd.as_str() {
                                "ascending" => Some(SortDirection::Ascending),
                                "descending" => Some(SortDirection::Descending),
                                _ => Some(SortDirection::Unknown),
                            }
                        } else {
                            None
                        }
                    }
                    "ag.library.smart_collection" => content.smart_collection = value.ok(),
                    _ => (),
                };
            }
        }
        content
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, VecDeque};

use pest::Parser;
use serde::Serialize;
use serde_json::value::{to_value, Map, Value as Json};

use crate::error::RenderError;
use crate::grammar::{HandlebarsParser, Rule};
use crate::json::path::*;
use crate::value::ScopedJson;

pub type Object = HashMap<String, Json>;

#[derive(Clone, Debug)]
pub enum BlockParamHolder {
    // a reference to certain context value
    Path(Vec<String>),
    // an actual value holder
    Value(Json),
}

impl BlockParamHolder {
    pub fn value(v: Json) -> BlockParamHolder {
        BlockParamHolder::Value(v)
    }

    pub fn path(r: Vec<String>) -> BlockParamHolder {
        BlockParamHolder::Path(r)
    }
}

#[derive(Clone, Debug, Default)]
pub struct BlockParams {
    data: HashMap<String, BlockParamHolder>,
}

impl BlockParams {
    pub fn new() -> BlockParams {
        BlockParams::default()
    }

    pub fn add_path(&mut self, k: &str, v: Vec<String>) -> Result<(), RenderError> {
        self.data.insert(k.to_owned(), BlockParamHolder::path(v));
        Ok(())
    }

    pub fn add_value(&mut self, k: &str, v: Json) -> Result<(), RenderError> {
        self.data.insert(k.to_owned(), BlockParamHolder::value(v));
        Ok(())
    }

    pub fn get(&self, k: &str) -> Option<&BlockParamHolder> {
        self.data.get(k)
    }
}

/// The context wrap data you render on your templates.
///
#[derive(Debug, Clone)]
pub struct Context {
    data: Json,
}

#[derive(Default)]
pub struct ResolvedPath<'b>(Vec<String>, Option<&'b BlockParamHolder>);

// from json path to a deque of
pub fn parse_json_path<'a>(path: &'a str) -> Result<Vec<PathSeg<'a>>, RenderError> {
    let mut path_stack = Vec::new();
    let parsed_path = HandlebarsParser::parse(Rule::path, path)
        .map(|p| p.flatten())
        .map_err(|_| RenderError::new("Invalid JSON path"))?;

    for seg in parsed_path {
        match seg.as_rule() {
            Rule::path_root => {
                path_stack.push(PathSeg::Ruled(Rule::path_root));
            }
            Rule::path_up => {
                path_stack.push(PathSeg::Ruled(Rule::path_up));
            }
            Rule::path_id | Rule::path_raw_id => {
                path_stack.push(PathSeg::Named(seg.as_str()));
            }
            _ => {
                continue;
            }
        }
    }

    Ok(path_stack)
}

fn parse_json_visitor<'a, 'b: 'a>(
    base_path: &[String],
    path_context: &VecDeque<Vec<String>>,
    relative_path: &[PathSeg<'a>],
    block_params: &'b VecDeque<BlockParams>,
) -> Result<ResolvedPath<'b>, RenderError> {
    let mut path_stack = Vec::new();

    let mut path_context_depth: i64 = -1;
    let mut used_block_param = None;
    let mut from_root = false;

    // peek relative_path for block param, @root and  "../../"
    for path_seg in relative_path {
        match path_seg {
            PathSeg::Named(the_path) => {
                if let Some(holder) = get_in_block_params(&block_params, the_path) {
                    used_block_param = Some(holder);
                }
                break;
            }
            PathSeg::Ruled(the_rule) => match the_rule {
                Rule::path_root => {
                    from_root = true;
                    break;
                }
                Rule::path_up => path_context_depth += 1,
                _ => break,
            },
        }
    }

    match used_block_param {
        Some(BlockParamHolder::Value(_)) => Ok(ResolvedPath(path_stack, used_block_param)),
        Some(BlockParamHolder::Path(ref paths)) => {
            path_stack.extend_from_slice(paths);
            merge_json_path(&mut path_stack, &relative_path[1..]);

            Ok(ResolvedPath(path_stack, used_block_param))
        }
        None => {
            if path_context_depth >= 0 {
                if let Some(context_base_path) = path_context.get(path_context_depth as usize) {
                    path_stack.extend_from_slice(context_base_path);
                } else {
                    // TODO: is this correct behaviour?
                    path_stack.extend_from_slice(base_path);
                }
            } else if !from_root {
                path_stack.extend_from_slice(base_path);
            }

            merge_json_path(&mut path_stack, relative_path);
            Ok(ResolvedPath(path_stack, None))
        }
    }
}

fn get_data<'a>(d: Option<&'a Json>, p: &str) -> Result<Option<&'a Json>, RenderError> {
    if p == "this" {
        return Ok(d);
    }

    let result = match d {
        Some(&Json::Array(ref l)) => p
            .parse::<usize>()
            .map_err(RenderError::with)
            .map(|idx_u| l.get(idx_u))?,
        Some(&Json::Object(ref m)) => m.get(p),
        Some(_) => None,
        None => None,
    };
    Ok(result)
}

pub(crate) fn get_in_block_params<'a>(
    block_contexts: &'a VecDeque<BlockParams>,
    p: &str,
) -> Option<&'a BlockParamHolder> {
    for bc in block_contexts {
        let v = bc.get(p);
        if v.is_some() {
            return v;
        }
    }

    None
}

pub fn merge_json(base: &Json, addition: &Object) -> Json {
    let mut base_map = match base {
        Json::Object(ref m) => m.clone(),
        _ => Map::new(),
    };

    for (k, v) in addition.iter() {
        base_map.insert(k.clone(), v.clone());
    }

    Json::Object(base_map)
}

impl Context {
    /// Create a context with null data
    pub fn null() -> Context {
        Context { data: Json::Null }
    }

    /// Create a context with given data
    pub fn wraps<T: Serialize>(e: T) -> Result<Context, RenderError> {
        to_value(e)
            .map_err(RenderError::from)
            .map(|d| Context { data: d })
    }

    /// Navigate the context with base path and relative path
    /// Typically you will set base path to `RenderContext.get_path()`
    /// and set relative path to helper argument or so.
    ///
    /// If you want to navigate from top level, set the base path to `"."`
    pub fn navigate<'reg, 'rc>(
        &'rc self,
        base_path: &[String],
        path_context: &VecDeque<Vec<String>>,
        relative_path: &str,
        block_params: &VecDeque<BlockParams>,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        let parsed_relative_path = parse_json_path(relative_path)?;
        let ResolvedPath(paths, block_param_holder) =
            parse_json_visitor(base_path, path_context, &parsed_relative_path, block_params)?;

        if let Some(BlockParamHolder::Value(ref block_param_value)) = block_param_holder {
            let mut data = Some(block_param_value);
            for p in paths.iter() {
                data = get_data(data, p)?;
            }
            Ok(data
                .map(|v| ScopedJson::Derived(v.clone()))
                .unwrap_or_else(|| ScopedJson::Missing))
        } else {
            let mut data = Some(self.data());
            for p in paths.iter() {
                data = get_data(data, p)?;
            }

            if let Some(BlockParamHolder::Path(_)) = block_param_holder {
                Ok(data
                    .map(|v| ScopedJson::BlockContext(v, paths))
                    .unwrap_or_else(|| ScopedJson::Missing))
            } else {
                let ResolvedPath(path_root, _) = parse_json_visitor(
                    base_path,
                    path_context,
                    &parsed_relative_path[..1],
                    block_params,
                )?;
                Ok(data
                    .map(|v| ScopedJson::Context(v, paths, path_root))
                    .unwrap_or_else(|| ScopedJson::Missing))
            }
        }
    }

    pub fn data(&self) -> &Json {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut Json {
        &mut self.data
    }
}

fn join(segs: &VecDeque<&str>, sep: &str) -> String {
    let mut out = String::new();
    let mut iter = segs.iter();
    if let Some(fst) = iter.next() {
        out.push_str(fst);
        for elt in iter {
            out.push_str(sep);
            out.push_str(elt);
        }
    }
    out
}

#[cfg(test)]
mod test {
    use crate::context::{self, BlockParams, Context};
    use crate::error::RenderError;
    use crate::value::{self, ScopedJson};
    use serde_json::value::Map;
    use std::collections::{HashMap, VecDeque};

    fn navigate_from_root<'reg, 'rc>(
        ctx: &'rc Context,
        path: &str,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        ctx.navigate(&Vec::new(), &VecDeque::new(), path, &VecDeque::new())
    }

    #[derive(Serialize)]
    struct Address {
        city: String,
        country: String,
    }

    #[derive(Serialize)]
    struct Person {
        name: String,
        age: i16,
        addr: Address,
        titles: Vec<String>,
    }

    #[test]
    fn test_render() {
        let v = "hello";
        let ctx = Context::wraps(&v.to_string()).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "this").unwrap().render(),
            v.to_string()
        );
    }

    #[test]
    fn test_navigation() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr,
            titles: vec!["programmer".to_string(), "cartographer".to_string()],
        };

        let ctx = Context::wraps(&person).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "./addr/country").unwrap().render(),
            "China".to_string()
        );
        assert_eq!(
            navigate_from_root(&ctx, "addr.[country]").unwrap().render(),
            "China".to_string()
        );

        let v = true;
        let ctx2 = Context::wraps(&v).unwrap();
        assert_eq!(
            navigate_from_root(&ctx2, "this").unwrap().render(),
            "true".to_string()
        );

        assert_eq!(
            navigate_from_root(&ctx, "titles.[0]").unwrap().render(),
            "programmer".to_string()
        );

        assert_eq!(
            navigate_from_root(&ctx, "age").unwrap().render(),
            "27".to_string()
        );
    }

    #[test]
    fn test_this() {
        let mut map_with_this = Map::new();
        map_with_this.insert("this".to_string(), value::to_json("hello"));
        map_with_this.insert("age".to_string(), value::to_json(5usize));
        let ctx1 = Context::wraps(&map_with_this).unwrap();

        let mut map_without_this = Map::new();
        map_without_this.insert("age".to_string(), value::to_json(4usize));
        let ctx2 = Context::wraps(&map_without_this).unwrap();

        assert_eq!(
            navigate_from_root(&ctx1, "this").unwrap().render(),
            "[object]".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx2, "age").unwrap().render(),
            "4".to_owned()
        );
    }

    #[test]
    fn test_merge_json() {
        let map = json!({ "age": 4 });
        let s = "hello".to_owned();
        let mut hash = HashMap::new();
        hash.insert("tag".to_owned(), value::to_json("h1"));

        let ctx_a1 = Context::wraps(&context::merge_json(&map, &hash)).unwrap();
        assert_eq!(
            navigate_from_root(&ctx_a1, "age").unwrap().render(),
            "4".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx_a1, "tag").unwrap().render(),
            "h1".to_owned()
        );

        let ctx_a2 = Context::wraps(&context::merge_json(&value::to_json(s), &hash)).unwrap();
        assert_eq!(
            navigate_from_root(&ctx_a2, "this").unwrap().render(),
            "[object]".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx_a2, "tag").unwrap().render(),
            "h1".to_owned()
        );
    }

    #[test]
    fn test_key_name_with_this() {
        let m = btreemap! {
            "this_name".to_string() => "the_value".to_string()
        };
        let ctx = Context::wraps(&m).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "this_name").unwrap().render(),
            "the_value".to_string()
        );
    }

    use serde::ser::Error as SerdeError;
    use serde::{Serialize, Serializer};

    struct UnserializableType {}

    impl Serialize for UnserializableType {
        fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            Err(SerdeError::custom("test"))
        }
    }

    #[test]
    fn test_serialize_error() {
        let d = UnserializableType {};
        assert!(Context::wraps(&d).is_err());
    }

    #[test]
    fn test_root() {
        let m = json!({
            "a" : {
                "b" : {
                    "c" : {
                        "d" : 1
                    }
                }
            },
            "b": 2
        });
        let ctx = Context::wraps(&m).unwrap();
        assert_eq!(
            ctx.navigate(
                &["a".to_owned(), "b".to_owned()],
                &VecDeque::new(),
                "@root/b",
                &VecDeque::new()
            )
            .unwrap()
            .render(),
            "2".to_string()
        );
    }

    #[test]
    fn test_block_params() {
        let m = json!([{
            "a": [1, 2]
        }, {
            "b": [2, 3]
        }]);

        let ctx = Context::wraps(&m).unwrap();
        let mut block_param = BlockParams::new();
        block_param
            .add_path("z", ["0".to_owned(), "a".to_owned()].to_vec())
            .unwrap();

        let mut block_params = VecDeque::new();
        block_params.push_front(block_param);

        assert_eq!(
            ctx.navigate(&Vec::new(), &VecDeque::new(), "z.[1]", &block_params)
                .unwrap()
                .render(),
            "2".to_string()
        );
    }
}
<commit_msg>(test) add case for accessing block param value<commit_after>use std::collections::{HashMap, VecDeque};

use pest::Parser;
use serde::Serialize;
use serde_json::value::{to_value, Map, Value as Json};

use crate::error::RenderError;
use crate::grammar::{HandlebarsParser, Rule};
use crate::json::path::*;
use crate::value::ScopedJson;

pub type Object = HashMap<String, Json>;

#[derive(Clone, Debug)]
pub enum BlockParamHolder {
    // a reference to certain context value
    Path(Vec<String>),
    // an actual value holder
    Value(Json),
}

impl BlockParamHolder {
    pub fn value(v: Json) -> BlockParamHolder {
        BlockParamHolder::Value(v)
    }

    pub fn path(r: Vec<String>) -> BlockParamHolder {
        BlockParamHolder::Path(r)
    }
}

#[derive(Clone, Debug, Default)]
pub struct BlockParams {
    data: HashMap<String, BlockParamHolder>,
}

impl BlockParams {
    pub fn new() -> BlockParams {
        BlockParams::default()
    }

    pub fn add_path(&mut self, k: &str, v: Vec<String>) -> Result<(), RenderError> {
        self.data.insert(k.to_owned(), BlockParamHolder::path(v));
        Ok(())
    }

    pub fn add_value(&mut self, k: &str, v: Json) -> Result<(), RenderError> {
        self.data.insert(k.to_owned(), BlockParamHolder::value(v));
        Ok(())
    }

    pub fn get(&self, k: &str) -> Option<&BlockParamHolder> {
        self.data.get(k)
    }
}

/// The context wrap data you render on your templates.
///
#[derive(Debug, Clone)]
pub struct Context {
    data: Json,
}

#[derive(Default)]
pub struct ResolvedPath<'b>(Vec<String>, Option<&'b BlockParamHolder>);

// from json path to a deque of
pub fn parse_json_path<'a>(path: &'a str) -> Result<Vec<PathSeg<'a>>, RenderError> {
    let mut path_stack = Vec::new();
    let parsed_path = HandlebarsParser::parse(Rule::path, path)
        .map(|p| p.flatten())
        .map_err(|_| RenderError::new("Invalid JSON path"))?;

    for seg in parsed_path {
        match seg.as_rule() {
            Rule::path_root => {
                path_stack.push(PathSeg::Ruled(Rule::path_root));
            }
            Rule::path_up => {
                path_stack.push(PathSeg::Ruled(Rule::path_up));
            }
            Rule::path_id | Rule::path_raw_id => {
                path_stack.push(PathSeg::Named(seg.as_str()));
            }
            _ => {
                continue;
            }
        }
    }

    Ok(path_stack)
}

fn parse_json_visitor<'a, 'b: 'a>(
    base_path: &[String],
    path_context: &VecDeque<Vec<String>>,
    relative_path: &[PathSeg<'a>],
    block_params: &'b VecDeque<BlockParams>,
) -> Result<ResolvedPath<'b>, RenderError> {
    let mut path_stack = Vec::new();

    let mut path_context_depth: i64 = -1;
    let mut used_block_param = None;
    let mut from_root = false;

    // peek relative_path for block param, @root and  "../../"
    for path_seg in relative_path {
        match path_seg {
            PathSeg::Named(the_path) => {
                if let Some(holder) = get_in_block_params(&block_params, the_path) {
                    used_block_param = Some(holder);
                }
                break;
            }
            PathSeg::Ruled(the_rule) => match the_rule {
                Rule::path_root => {
                    from_root = true;
                    break;
                }
                Rule::path_up => path_context_depth += 1,
                _ => break,
            },
        }
    }

    match used_block_param {
        Some(BlockParamHolder::Value(_)) => Ok(ResolvedPath(path_stack, used_block_param)),
        Some(BlockParamHolder::Path(ref paths)) => {
            path_stack.extend_from_slice(paths);
            merge_json_path(&mut path_stack, &relative_path[1..]);

            Ok(ResolvedPath(path_stack, used_block_param))
        }
        None => {
            if path_context_depth >= 0 {
                if let Some(context_base_path) = path_context.get(path_context_depth as usize) {
                    path_stack.extend_from_slice(context_base_path);
                } else {
                    // TODO: is this correct behaviour?
                    path_stack.extend_from_slice(base_path);
                }
            } else if !from_root {
                path_stack.extend_from_slice(base_path);
            }

            merge_json_path(&mut path_stack, relative_path);
            Ok(ResolvedPath(path_stack, None))
        }
    }
}

fn get_data<'a>(d: Option<&'a Json>, p: &str) -> Result<Option<&'a Json>, RenderError> {
    if p == "this" {
        return Ok(d);
    }

    let result = match d {
        Some(&Json::Array(ref l)) => p
            .parse::<usize>()
            .map_err(RenderError::with)
            .map(|idx_u| l.get(idx_u))?,
        Some(&Json::Object(ref m)) => m.get(p),
        Some(_) => None,
        None => None,
    };
    Ok(result)
}

pub(crate) fn get_in_block_params<'a>(
    block_contexts: &'a VecDeque<BlockParams>,
    p: &str,
) -> Option<&'a BlockParamHolder> {
    for bc in block_contexts {
        let v = bc.get(p);
        if v.is_some() {
            return v;
        }
    }

    None
}

pub fn merge_json(base: &Json, addition: &Object) -> Json {
    let mut base_map = match base {
        Json::Object(ref m) => m.clone(),
        _ => Map::new(),
    };

    for (k, v) in addition.iter() {
        base_map.insert(k.clone(), v.clone());
    }

    Json::Object(base_map)
}

impl Context {
    /// Create a context with null data
    pub fn null() -> Context {
        Context { data: Json::Null }
    }

    /// Create a context with given data
    pub fn wraps<T: Serialize>(e: T) -> Result<Context, RenderError> {
        to_value(e)
            .map_err(RenderError::from)
            .map(|d| Context { data: d })
    }

    /// Navigate the context with base path and relative path
    /// Typically you will set base path to `RenderContext.get_path()`
    /// and set relative path to helper argument or so.
    ///
    /// If you want to navigate from top level, set the base path to `"."`
    pub fn navigate<'reg, 'rc>(
        &'rc self,
        base_path: &[String],
        path_context: &VecDeque<Vec<String>>,
        relative_path: &str,
        block_params: &VecDeque<BlockParams>,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        let parsed_relative_path = parse_json_path(relative_path)?;
        let ResolvedPath(paths, block_param_holder) =
            parse_json_visitor(base_path, path_context, &parsed_relative_path, block_params)?;

        if let Some(BlockParamHolder::Value(ref block_param_value)) = block_param_holder {
            let mut data = Some(block_param_value);
            for p in paths.iter() {
                data = get_data(data, p)?;
            }
            Ok(data
                .map(|v| ScopedJson::Derived(v.clone()))
                .unwrap_or_else(|| ScopedJson::Missing))
        } else {
            let mut data = Some(self.data());
            for p in paths.iter() {
                data = get_data(data, p)?;
            }

            if let Some(BlockParamHolder::Path(_)) = block_param_holder {
                Ok(data
                    .map(|v| ScopedJson::BlockContext(v, paths))
                    .unwrap_or_else(|| ScopedJson::Missing))
            } else {
                let ResolvedPath(path_root, _) = parse_json_visitor(
                    base_path,
                    path_context,
                    &parsed_relative_path[..1],
                    block_params,
                )?;
                Ok(data
                    .map(|v| ScopedJson::Context(v, paths, path_root))
                    .unwrap_or_else(|| ScopedJson::Missing))
            }
        }
    }

    pub fn data(&self) -> &Json {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut Json {
        &mut self.data
    }
}

fn join(segs: &VecDeque<&str>, sep: &str) -> String {
    let mut out = String::new();
    let mut iter = segs.iter();
    if let Some(fst) = iter.next() {
        out.push_str(fst);
        for elt in iter {
            out.push_str(sep);
            out.push_str(elt);
        }
    }
    out
}

#[cfg(test)]
mod test {
    use crate::context::{self, BlockParams, Context};
    use crate::error::RenderError;
    use crate::value::{self, ScopedJson};
    use serde_json::value::Map;
    use std::collections::{HashMap, VecDeque};

    fn navigate_from_root<'reg, 'rc>(
        ctx: &'rc Context,
        path: &str,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        ctx.navigate(&Vec::new(), &VecDeque::new(), path, &VecDeque::new())
    }

    #[derive(Serialize)]
    struct Address {
        city: String,
        country: String,
    }

    #[derive(Serialize)]
    struct Person {
        name: String,
        age: i16,
        addr: Address,
        titles: Vec<String>,
    }

    #[test]
    fn test_render() {
        let v = "hello";
        let ctx = Context::wraps(&v.to_string()).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "this").unwrap().render(),
            v.to_string()
        );
    }

    #[test]
    fn test_navigation() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr,
            titles: vec!["programmer".to_string(), "cartographer".to_string()],
        };

        let ctx = Context::wraps(&person).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "./addr/country").unwrap().render(),
            "China".to_string()
        );
        assert_eq!(
            navigate_from_root(&ctx, "addr.[country]").unwrap().render(),
            "China".to_string()
        );

        let v = true;
        let ctx2 = Context::wraps(&v).unwrap();
        assert_eq!(
            navigate_from_root(&ctx2, "this").unwrap().render(),
            "true".to_string()
        );

        assert_eq!(
            navigate_from_root(&ctx, "titles.[0]").unwrap().render(),
            "programmer".to_string()
        );

        assert_eq!(
            navigate_from_root(&ctx, "age").unwrap().render(),
            "27".to_string()
        );
    }

    #[test]
    fn test_this() {
        let mut map_with_this = Map::new();
        map_with_this.insert("this".to_string(), value::to_json("hello"));
        map_with_this.insert("age".to_string(), value::to_json(5usize));
        let ctx1 = Context::wraps(&map_with_this).unwrap();

        let mut map_without_this = Map::new();
        map_without_this.insert("age".to_string(), value::to_json(4usize));
        let ctx2 = Context::wraps(&map_without_this).unwrap();

        assert_eq!(
            navigate_from_root(&ctx1, "this").unwrap().render(),
            "[object]".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx2, "age").unwrap().render(),
            "4".to_owned()
        );
    }

    #[test]
    fn test_merge_json() {
        let map = json!({ "age": 4 });
        let s = "hello".to_owned();
        let mut hash = HashMap::new();
        hash.insert("tag".to_owned(), value::to_json("h1"));

        let ctx_a1 = Context::wraps(&context::merge_json(&map, &hash)).unwrap();
        assert_eq!(
            navigate_from_root(&ctx_a1, "age").unwrap().render(),
            "4".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx_a1, "tag").unwrap().render(),
            "h1".to_owned()
        );

        let ctx_a2 = Context::wraps(&context::merge_json(&value::to_json(s), &hash)).unwrap();
        assert_eq!(
            navigate_from_root(&ctx_a2, "this").unwrap().render(),
            "[object]".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx_a2, "tag").unwrap().render(),
            "h1".to_owned()
        );
    }

    #[test]
    fn test_key_name_with_this() {
        let m = btreemap! {
            "this_name".to_string() => "the_value".to_string()
        };
        let ctx = Context::wraps(&m).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "this_name").unwrap().render(),
            "the_value".to_string()
        );
    }

    use serde::ser::Error as SerdeError;
    use serde::{Serialize, Serializer};

    struct UnserializableType {}

    impl Serialize for UnserializableType {
        fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            Err(SerdeError::custom("test"))
        }
    }

    #[test]
    fn test_serialize_error() {
        let d = UnserializableType {};
        assert!(Context::wraps(&d).is_err());
    }

    #[test]
    fn test_root() {
        let m = json!({
            "a" : {
                "b" : {
                    "c" : {
                        "d" : 1
                    }
                }
            },
            "b": 2
        });
        let ctx = Context::wraps(&m).unwrap();
        assert_eq!(
            ctx.navigate(
                &["a".to_owned(), "b".to_owned()],
                &VecDeque::new(),
                "@root/b",
                &VecDeque::new()
            )
            .unwrap()
            .render(),
            "2".to_string()
        );
    }

    #[test]
    fn test_block_params() {
        let m = json!([{
            "a": [1, 2]
        }, {
            "b": [2, 3]
        }]);

        let ctx = Context::wraps(&m).unwrap();
        let mut block_param = BlockParams::new();
        block_param
            .add_path("z", ["0".to_owned(), "a".to_owned()].to_vec())
            .unwrap();
        block_param.add_value("t", json!("good")).unwrap();

        let mut block_params = VecDeque::new();
        block_params.push_front(block_param);

        assert_eq!(
            ctx.navigate(&Vec::new(), &VecDeque::new(), "z.[1]", &block_params)
                .unwrap()
                .render(),
            "2".to_string()
        );
        assert_eq!(
            ctx.navigate(&Vec::new(), &VecDeque::new(), "t", &block_params)
                .unwrap()
                .render(),
            "good".to_string()
        );
    }
}
<|endoftext|>