<commit_before>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::str::FromStr;
use std::io::prelude::*;
use std::path::Path;

use clap::ArgMatches;
use hcore::package::{PackageArchive, PackageIdent};
use common::ui::UI;
use rand;
use rand::Rng;

use export_docker::Result;

use habitat_sup::manager::service::Topology;
use manifestjson::ManifestJson;
use bind;

#[derive(Debug, Clone)]
pub struct Manifest {
    pub metadata_name: String,
    pub habitat_name: String,
    pub image: String,
    pub count: u64,
    pub service_topology: Topology,
    pub service_group: Option<String>,
    pub config_secret_name: Option<String>,
    pub ring_secret_name: Option<String>,
    pub binds: Vec<bind::Bind>,
}

impl Manifest {
    pub fn new_from_cli_matches(_ui: &mut UI, matches: &ArgMatches) -> Result<Self> {
        let count = matches.value_of("COUNT").unwrap_or("1").parse()?;
        let topology: Topology = FromStr::from_str(
            matches.value_of("TOPOLOGY").unwrap_or("standalone"),
        ).unwrap_or(Topology::Standalone);
        let group = matches.value_of("GROUP").map(|s| s.to_string());
        let config_secret_name = matches.value_of("CONFIG_SECRET_NAME").map(
            |s| s.to_string(),
        );
        let ring_secret_name = matches.value_of("RING_SECRET_NAME").map(|s| s.to_string());
        // clap ensures that we do have the mandatory args so unwrap() is fine here
        let pkg_ident_str = matches.value_of("PKG_IDENT_OR_ARTIFACT").expect(
            "No package specified",
        );
        let pkg_ident = if Path::new(pkg_ident_str).is_file() {
            // We're going to use the `$pkg_origin/$pkg_name`, fuzzy form of a package
            // identifier to ensure that update strategies will work if desired
            PackageArchive::new(pkg_ident_str).ident()?
        } else {
            PackageIdent::from_str(pkg_ident_str)?
        };

        // To allow multiple instances of Habitat application in Kubernetes,
        // random suffix in metadata_name is needed.
        let metadata_name =
            format!(
            "{}-{}",
            pkg_ident.name,
            rand::thread_rng()
                .gen_ascii_chars()
                .filter(|c| c.is_lowercase() || c.is_numeric())
                .take(5)
                .collect::<String>(),
        );

        let image = match matches.value_of("IMAGE_NAME") {
            Some(i) => i.to_string(),
            None => pkg_ident.origin + "/" + &pkg_ident.name + ":latest",
        };

        let binds = bind::parse_bind_args(&matches)?;

        Ok(Manifest {
            metadata_name: metadata_name,
            habitat_name: pkg_ident.name,
            image: image,
            count: count,
            service_topology: topology,
            service_group: group,
            config_secret_name: config_secret_name,
            ring_secret_name: ring_secret_name,
            binds: binds,
        })
    }

    pub fn generate(&mut self, write: &mut Write) -> Result<()> {
        let out = ManifestJson::new(&self).into_string()?;

        write.write(out.as_bytes())?;

        Ok(())
    }
}
<commit_msg>pkg-export-k8s: Use str::parse()<commit_after>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::str::FromStr;
use std::io::prelude::*;
use std::path::Path;

use clap::ArgMatches;
use hcore::package::{PackageArchive, PackageIdent};
use common::ui::UI;
use rand;
use rand::Rng;

use export_docker::Result;

use habitat_sup::manager::service::Topology;
use manifestjson::ManifestJson;
use bind;

#[derive(Debug, Clone)]
pub struct Manifest {
    pub metadata_name: String,
    pub habitat_name: String,
    pub image: String,
    pub count: u64,
    pub service_topology: Topology,
    pub service_group: Option<String>,
    pub config_secret_name: Option<String>,
    pub ring_secret_name: Option<String>,
    pub binds: Vec<bind::Bind>,
}

impl Manifest {
    pub fn new_from_cli_matches(_ui: &mut UI, matches: &ArgMatches) -> Result<Self> {
        let count = matches.value_of("COUNT").unwrap_or("1").parse()?;
        let topology: Topology = matches
            .value_of("TOPOLOGY")
            .unwrap_or("standalone")
            .parse()
            .unwrap_or(Default::default());
        let group = matches.value_of("GROUP").map(|s| s.to_string());
        let config_secret_name = matches.value_of("CONFIG_SECRET_NAME").map(
            |s| s.to_string(),
        );
        let ring_secret_name = matches.value_of("RING_SECRET_NAME").map(|s| s.to_string());
        // clap ensures that we do have the mandatory args so unwrap() is fine here
        let pkg_ident_str = matches.value_of("PKG_IDENT_OR_ARTIFACT").expect(
            "No package specified",
        );
        let pkg_ident = if Path::new(pkg_ident_str).is_file() {
            // We're going to use the `$pkg_origin/$pkg_name`, fuzzy form of a package
            // identifier to ensure that update strategies will work if desired
            PackageArchive::new(pkg_ident_str).ident()?
        } else {
            PackageIdent::from_str(pkg_ident_str)?
        };

        // To allow multiple instances of Habitat application in Kubernetes,
        // random suffix in metadata_name is needed.
        let metadata_name =
            format!(
            "{}-{}",
            pkg_ident.name,
            rand::thread_rng()
                .gen_ascii_chars()
                .filter(|c| c.is_lowercase() || c.is_numeric())
                .take(5)
                .collect::<String>(),
        );

        let image = match matches.value_of("IMAGE_NAME") {
            Some(i) => i.to_string(),
            None => pkg_ident.origin + "/" + &pkg_ident.name + ":latest",
        };

        let binds = bind::parse_bind_args(&matches)?;

        Ok(Manifest {
            metadata_name: metadata_name,
            habitat_name: pkg_ident.name,
            image: image,
            count: count,
            service_topology: topology,
            service_group: group,
            config_secret_name: config_secret_name,
            ring_secret_name: ring_secret_name,
            binds: binds,
        })
    }

    pub fn generate(&mut self, write: &mut Write) -> Result<()> {
        let out = ManifestJson::new(&self).into_string()?;

        write.write(out.as_bytes())?;

        Ok(())
    }
}
<|endoftext|>


<commit_before>mod thread_guard;

use std::fmt;
use std::io;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use std::thread;
use std::time::{Duration, Instant};
use std::ops::Deref;

use serial::prelude::*;
use serial;
use self::thread_guard::*;
use super::Packet;

pub enum ConnectionEvent {
    Packet(Packet),
    InvalidPacket(Packet),
    ReadError(io::Error),
    WriteError(io::Error),
    Heartbeat
}

impl fmt::Display for ConnectionEvent {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ConnectionEvent::Packet(ref p) => write!(f, "{}", p),
            &ConnectionEvent::InvalidPacket(ref p) => write!(f, "Invalid! {}", p),
            &ConnectionEvent::ReadError(ref err) => write!(f, "READ ERROR! [{:?}]", err),
            &ConnectionEvent::WriteError(ref err) => write!(f, "WRITE ERROR! [{:?}]", err),
            &ConnectionEvent::Heartbeat => write!(f, "Tick Tock")
        }
    }
}

pub struct Connection {
    pub tty_path: String,
    event_receiver: Receiver<ConnectionEvent>,
    packet_sender: Sender<Packet>,
    kill_thread_signal: Arc<Mutex<bool>>,
    reader_thread_handle: Option<ThreadHandle<()>>,
}

impl Connection {
    pub fn new(tty_path: &str, heartbeat_milliseconds: Option<u64>) -> io::Result<Connection> {
        let (event_sender, event_receiver) = channel::<ConnectionEvent>();
        let (packet_sender, packet_receiver) = channel::<Packet>();

        let kill_signal = Arc::new(Mutex::new(false));

        let reader_thread = build_connection_read_thread(tty_path.to_string(), event_sender, packet_receiver, heartbeat_milliseconds, kill_signal.clone());

        Ok(Connection {
            tty_path: tty_path.to_string(),
            event_receiver: event_receiver,
            packet_sender: packet_sender,
            kill_thread_signal: kill_signal,
            reader_thread_handle: Some(reader_thread)
        })
    }

    pub fn send(&mut self, p: Packet) -> io::Result<()> {
        match self.is_ok() {
            true => {
                self.packet_sender.send(p).unwrap();
                Ok(())
            },
            false => Err(io::Error::new(io::ErrorKind::ConnectionAborted, "worker threads have stopped"))
        }
    }

    pub fn wait(&self) -> io::Result<ConnectionEvent> {
        match self.is_ok() {
            false => Err(io::Error::new(io::ErrorKind::ConnectionAborted, "worker threads have stopped")),
            true => {
                Ok(self.event_receiver.recv().unwrap())
            }
        }
    }

    pub fn get_events(&self) -> io::Result<Vec<ConnectionEvent>> {
        match self.is_ok() {
            false => Err(io::Error::new(io::ErrorKind::ConnectionAborted, "worker threads have stopped")),
            true => {
                let mut data: Vec<ConnectionEvent> = vec!();

                loop {
                    match self.event_receiver.try_recv() {
                        Ok(evt) => { data.push(evt) },
                        Err(TryRecvError::Empty) => { break; },
                        Err(TryRecvError::Disconnected) => { panic!("channels should not disconnect") }
                    }
                }

                Ok(data)
            }
        }
    }

    pub fn is_ok(&self) -> bool {
        let mut ret = true;

        match &self.reader_thread_handle {
            &Some(ref h) => {
                ret = ret && match h.status.lock().unwrap().deref() {
                    &ThreadStatus::Ok => true,
                    _ => false
                }
            },
            _ => {}
        }
        ret
    }
}

impl Drop for Connection {
    fn drop(&mut self) {

        {
            *self.kill_thread_signal.lock().unwrap() = true;
        }

        match self.reader_thread_handle.take() {
            Some(th) => {
                th.handle.join().unwrap();
            },
            None => {}
        }
    }
}

fn build_connection_read_thread(tty_path: String, event_sender: Sender<ConnectionEvent>, packet_receiver: Receiver<Packet>, heartbeat: Option<u64>, kill_signal: Arc<Mutex<bool>>) -> ThreadHandle<()> {
    guard_thread("reader_thread", move || {
        let mut serial = match serial::open(&tty_path) {
            Err(e) => {panic!(format!("Unable to create serial port: {}", e)) },
            Ok(s) => s
        };

        match serial.set_timeout(Duration::from_millis(500)) {
            Err(e) => { panic!(format!("Unable to set serial timeout: {}", e)) },
            Ok(_) => {}
        };

        let mut packet_buffer: Vec<u8> = Vec::new();
        let mut read_buffer: Vec<u8> = Vec::new();
        let mut last_read = Instant::now();
        let mut last_heartbeat = Instant::now();

        while !*kill_signal.lock().unwrap() {

            if packet_buffer.len() > 0 && last_read.elapsed().as_secs() > 2 {
                let evt = ConnectionEvent::ReadError(io::Error::new(io::ErrorKind::InvalidData, format!("Invalid packet data: {:?}", packet_buffer.clone())));
                event_sender.send(evt).unwrap();
                packet_buffer.clear();
            };

            match packet_receiver.try_recv() {
                Ok(p) => {
                    println!("going to write...");
                    match serial.write_all(&p.data) {
                        Ok(_) => {},
                        Err(e) => {
                            let evt = ConnectionEvent::WriteError(e);
                            event_sender.send(evt).unwrap();
                        }
                    }
                },
                Err(TryRecvError::Empty) => {  },
                Err(TryRecvError::Disconnected) => { panic!("channels should not disconnect") }
            }

            match serial.read(&mut read_buffer) {
                Err(e) if e.kind() == io::ErrorKind::TimedOut => {},
                Err(e) => {
                    let evt = ConnectionEvent::ReadError(e);
                    event_sender.send(evt).unwrap();
                },
                Ok(bytes) if bytes > 0 => {
                    last_read = Instant::now();
                    for x in 0 .. bytes {
                        packet_buffer.push(read_buffer[x]);
                    }
                },
                Ok(_) => {} // do nothing for 0 bytes read
            };

            while packet_buffer.len() >= 128 {
                let data: Vec<u8> = packet_buffer.drain(0..128).collect();
                let p = Packet::from_bytes(&data);

                if p.is_checksum_valid() {
                    let evt = ConnectionEvent::Packet(p);
                    event_sender.send(evt).unwrap();
                } else {
                    let evt = ConnectionEvent::InvalidPacket(p);
                    event_sender.send(evt).unwrap();
                }
            }

            match heartbeat {
                Some(ms) => {
                    if last_heartbeat.elapsed() >= Duration::from_millis(ms) {
                        let evt = ConnectionEvent::Heartbeat;
                        event_sender.send(evt).unwrap();
                        last_heartbeat = Instant::now();
                    }
                },
                None => {}
            }

            thread::sleep(Duration::from_millis(250));
        }
        ()
    })
}
<commit_msg>debug<commit_after>mod thread_guard;

use std::fmt;
use std::io;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use std::thread;
use std::time::{Duration, Instant};
use std::ops::Deref;

use serial::prelude::*;
use serial;
use self::thread_guard::*;
use super::Packet;

pub enum ConnectionEvent {
    Packet(Packet),
    InvalidPacket(Packet),
    ReadError(io::Error),
    WriteError(io::Error),
    Heartbeat
}

impl fmt::Display for ConnectionEvent {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ConnectionEvent::Packet(ref p) => write!(f, "{}", p),
            &ConnectionEvent::InvalidPacket(ref p) => write!(f, "Invalid! {}", p),
            &ConnectionEvent::ReadError(ref err) => write!(f, "READ ERROR! [{:?}]", err),
            &ConnectionEvent::WriteError(ref err) => write!(f, "WRITE ERROR! [{:?}]", err),
            &ConnectionEvent::Heartbeat => write!(f, "Tick Tock")
        }
    }
}

pub struct Connection {
    pub tty_path: String,
    event_receiver: Receiver<ConnectionEvent>,
    packet_sender: Sender<Packet>,
    kill_thread_signal: Arc<Mutex<bool>>,
    reader_thread_handle: Option<ThreadHandle<()>>,
}

impl Connection {
    pub fn new(tty_path: &str, heartbeat_milliseconds: Option<u64>) -> io::Result<Connection> {
        let (event_sender, event_receiver) = channel::<ConnectionEvent>();
        let (packet_sender, packet_receiver) = channel::<Packet>();

        let kill_signal = Arc::new(Mutex::new(false));

        let reader_thread = build_connection_read_thread(tty_path.to_string(), event_sender, packet_receiver, heartbeat_milliseconds, kill_signal.clone());

        Ok(Connection {
            tty_path: tty_path.to_string(),
            event_receiver: event_receiver,
            packet_sender: packet_sender,
            kill_thread_signal: kill_signal,
            reader_thread_handle: Some(reader_thread)
        })
    }

    pub fn send(&mut self, p: Packet) -> io::Result<()> {
        match self.is_ok() {
            true => {
                self.packet_sender.send(p).unwrap();
                Ok(())
            },
            false => Err(io::Error::new(io::ErrorKind::ConnectionAborted, "worker threads have stopped"))
        }
    }

    pub fn wait(&self) -> io::Result<ConnectionEvent> {
        match self.is_ok() {
            false => Err(io::Error::new(io::ErrorKind::ConnectionAborted, "worker threads have stopped")),
            true => {
                Ok(self.event_receiver.recv().unwrap())
            }
        }
    }

    pub fn get_events(&self) -> io::Result<Vec<ConnectionEvent>> {
        match self.is_ok() {
            false => Err(io::Error::new(io::ErrorKind::ConnectionAborted, "worker threads have stopped")),
            true => {
                let mut data: Vec<ConnectionEvent> = vec!();

                loop {
                    match self.event_receiver.try_recv() {
                        Ok(evt) => { data.push(evt) },
                        Err(TryRecvError::Empty) => { break; },
                        Err(TryRecvError::Disconnected) => { panic!("channels should not disconnect") }
                    }
                }

                Ok(data)
            }
        }
    }

    pub fn is_ok(&self) -> bool {
        let mut ret = true;

        match &self.reader_thread_handle {
            &Some(ref h) => {
                ret = ret && match h.status.lock().unwrap().deref() {
                    &ThreadStatus::Ok => true,
                    _ => false
                }
            },
            _ => {}
        }
        ret
    }
}

impl Drop for Connection {
    fn drop(&mut self) {

        {
            *self.kill_thread_signal.lock().unwrap() = true;
        }

        match self.reader_thread_handle.take() {
            Some(th) => {
                th.handle.join().unwrap();
            },
            None => {}
        }
    }
}

fn build_connection_read_thread(tty_path: String, event_sender: Sender<ConnectionEvent>, packet_receiver: Receiver<Packet>, heartbeat: Option<u64>, kill_signal: Arc<Mutex<bool>>) -> ThreadHandle<()> {
    guard_thread("reader_thread", move || {
        let mut serial = match serial::open(&tty_path) {
            Err(e) => {panic!(format!("Unable to create serial port: {}", e)) },
            Ok(s) => s
        };

        match serial.set_timeout(Duration::from_millis(500)) {
            Err(e) => { panic!(format!("Unable to set serial timeout: {}", e)) },
            Ok(_) => {}
        };

        let mut packet_buffer: Vec<u8> = Vec::new();
        let mut read_buffer: Vec<u8> = Vec::new();
        let mut last_read = Instant::now();
        let mut last_heartbeat = Instant::now();

        while !*kill_signal.lock().unwrap() {

            if packet_buffer.len() > 0 && last_read.elapsed().as_secs() > 2 {
                let evt = ConnectionEvent::ReadError(io::Error::new(io::ErrorKind::InvalidData, format!("Invalid packet data: {:?}", packet_buffer.clone())));
                event_sender.send(evt).unwrap();
                packet_buffer.clear();
            };

            match packet_receiver.try_recv() {
                Ok(p) => {
                    println!("going to write...");
                    match serial.write_all(&p.data) {
                        Ok(_) => {},
                        Err(e) => {
                            let evt = ConnectionEvent::WriteError(e);
                            event_sender.send(evt).unwrap();
                        }
                    }
                },
                Err(TryRecvError::Empty) => {  },
                Err(TryRecvError::Disconnected) => { panic!("channels should not disconnect") }
            }

            match serial.read(&mut read_buffer) {
                Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {},
                Err(e) => {
                    let evt = ConnectionEvent::ReadError(e);
                    event_sender.send(evt).unwrap();
                },
                Ok(bytes) if bytes > 0 => {
                    last_read = Instant::now();
                    for x in 0 .. bytes {
                        packet_buffer.push(read_buffer[x]);
                    }
                },
                Ok(_) => {} // do nothing for 0 bytes read
            };

            while packet_buffer.len() >= 128 {
                let data: Vec<u8> = packet_buffer.drain(0..128).collect();
                let p = Packet::from_bytes(&data);

                if p.is_checksum_valid() {
                    let evt = ConnectionEvent::Packet(p);
                    event_sender.send(evt).unwrap();
                } else {
                    let evt = ConnectionEvent::InvalidPacket(p);
                    event_sender.send(evt).unwrap();
                }
            }

            match heartbeat {
                Some(ms) => {
                    if last_heartbeat.elapsed() >= Duration::from_millis(ms) {
                        let evt = ConnectionEvent::Heartbeat;
                        event_sender.send(evt).unwrap();
                        last_heartbeat = Instant::now();
                    }
                },
                None => {}
            }

            thread::sleep(Duration::from_millis(250));
        }
        ()
    })
}
<|endoftext|>


<commit_before>
use wtools::vector;

//

#[test]
fn append_vectors_once_trivial()
{
  println!( "empty vector::" );
  let mut dst: Vec<u8> = vec![];
  let src: Vec<Vec<u8>> = vec![];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  let exp: Vec<u8> = vec![];
  assert_eq!( *got, exp );

  println!( "dst - filled, src - empty" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );

  println!( "dst - filled, src - filled, all is unical elements" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 3, 4 ], vec![ 5, 6 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2, 3, 4, 5, 6 ] );

  println!( "dst - filled, src - filled, some is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 3 ], vec![ 4, 2 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2, 3, 4 ] );

  println!( "dst - filled, src - filled, all is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 1 ], vec![ 2, 2 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );

  println!( "dst - filled, src - filled, all is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 2 ], vec![ 2, 1 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );
}

/*
  append_vectors_once_trivial
*/
<commit_msg>Write test routine `left_index_trivial`<commit_after>
use wtools::vector;

//

#[test]
fn append_vectors_once_trivial()
{
  println!( "empty vector" );
  let mut dst: Vec<u8> = vec![];
  let src: Vec<Vec<u8>> = vec![];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  let exp: Vec<u8> = vec![];
  assert_eq!( *got, exp );

  println!( "dst - filled, src - empty" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );

  println!( "dst - filled, src - filled, all is unical elements" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 3, 4 ], vec![ 5, 6 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2, 3, 4, 5, 6 ] );

  println!( "dst - filled, src - filled, some is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 3 ], vec![ 4, 2 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2, 3, 4 ] );

  println!( "dst - filled, src - filled, all is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 1 ], vec![ 2, 2 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );

  println!( "dst - filled, src - filled, all is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 2 ], vec![ 2, 1 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );
}

//

#[test]
fn left_index_trivial()
{
  println!( "empty vector" );
  let src: Vec<u8> = vec![];
  let got = vector::left_index( &src, 1, None::<fn(_)> );
  assert_eq!( got, None );

  println!( "filled vector, not matches" );
  let src: Vec<u8> = vec![ 1, 2, 3 ];
  let got = vector::left_index( &src, 4, None::<fn(_)> );
  assert_eq!( got, None );

  println!( "filled vector, matches one" );
  let src: Vec<u8> = vec![ 1, 2, 3 ];
  let got = vector::left_index( &src, 2, None::<fn(_)> );
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches several" );
  let src: Vec<u8> = vec![ 1, 2, 2 ];
  let got = vector::left_index( &src, 2, None::<fn(_)> );
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches all" );
  let src: Vec<u8> = vec![ 2, 2, 2 ];
  let got = vector::left_index( &src, 2, None::<fn(_)> );
  assert_eq!( got, Some( 0 ) );
}

/*
  append_vectors_once_trivial
  left_index_trivial
*/
<|endoftext|>


<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

#[macro_use]
extern crate lazy_static;
extern crate serde_json;

extern crate micro_http;

pub mod data_store;

use serde_json::{Map, Value};
use std::sync::{Arc, Mutex};

use data_store::{Error as MmdsError, Mmds, OutputFormat};
use micro_http::{Body, MediaType, Method, Request, RequestError, Response, StatusCode, Version};

lazy_static! {
    // A static reference to a global Mmds instance. We currently use this for ease of access during
    // prototyping. We'll consider something like passing Arc<Mutex<Mmds>> references to the
    // appropriate threads in the future.
    pub static ref MMDS: Arc<Mutex<Mmds>> = Arc::new(Mutex::new(Mmds::default()));
}

impl Into<OutputFormat> for MediaType {
    fn into(self) -> OutputFormat {
        match self {
            MediaType::ApplicationJson => OutputFormat::Json,
            MediaType::PlainText => OutputFormat::Imds,
        }
    }
}

/// Patch provided JSON document (given as `serde_json::Value`) in-place with JSON Merge Patch
/// [RFC 7396](https://tools.ietf.org/html/rfc7396).
pub fn json_patch(target: &mut Value, patch: &Value) {
    if patch.is_object() {
        if !target.is_object() {
            // Replace target with a serde_json object so we can recursively copy patch values.
            *target = Value::Object(Map::new());
        }

        // This is safe since we make sure patch and target are objects beforehand.
        let doc = target.as_object_mut().unwrap();
        for (key, value) in patch.as_object().unwrap() {
            if value.is_null() {
                // If the value in the patch is null we remove the entry.
                doc.remove(key.as_str());
            } else {
                // Recursive call to update target document.
                // If `key` is not in the target document (it's a new field defined in `patch`)
                // insert a null placeholder and pass it as the new target
                // so we can insert new values recursively.
                json_patch(doc.entry(key.as_str()).or_insert(Value::Null), value);
            }
        }
    } else {
        *target = patch.clone();
    }
}

fn build_response(http_version: Version, status_code: StatusCode, body: Body) -> Response {
    let mut response = Response::new(http_version, status_code);
    response.set_body(body);
    response
}

pub fn parse_request(request_bytes: &[u8]) -> Response {
    let request = Request::try_from(request_bytes);
    match request {
        Ok(request) => {
            let uri = request.uri().get_abs_path();
            if uri.is_empty() {
                return build_response(
                    request.http_version(),
                    StatusCode::BadRequest,
                    Body::new("Invalid URI.".to_string()),
                );
            }

            if request.method() != Method::Get {
                let mut response = build_response(
                    request.http_version(),
                    StatusCode::MethodNotAllowed,
                    Body::new("Not allowed HTTP method."),
                );
                response.allow_method(Method::Get);
                return response;
            }

            // The lock can be held by one thread only, so it is safe to unwrap.
            // If another thread poisoned the lock, we abort the execution.
            let response = MMDS
                .lock()
                .expect("Poisoned lock")
                .get_value(uri.to_string(), request.headers.accept().into());

            match response {
                Ok(response_body) => build_response(
                    request.http_version(),
                    StatusCode::OK,
                    Body::new(response_body),
                ),
                Err(e) => match e {
                    MmdsError::NotFound => {
                        let error_msg = format!("Resource not found: {}.", uri);
                        build_response(
                            request.http_version(),
                            StatusCode::NotFound,
                            Body::new(error_msg),
                        )
                    }
                    MmdsError::UnsupportedValueType => build_response(
                        request.http_version(),
                        StatusCode::NotImplemented,
                        Body::new(e.to_string()),
                    ),
                    MmdsError::NotInitialized => unreachable!(),
                },
            }
        }
        Err(e) => match e {
            RequestError::InvalidHttpVersion(err_msg) => build_response(
                Version::default(),
                StatusCode::NotImplemented,
                Body::new(err_msg.to_string()),
            ),
            RequestError::InvalidUri(err_msg) => build_response(
                Version::default(),
                StatusCode::BadRequest,
                Body::new(err_msg.to_string()),
            ),
            RequestError::InvalidHttpMethod(err_msg) => build_response(
                Version::default(),
                StatusCode::NotImplemented,
                Body::new(err_msg.to_string()),
            ),
            RequestError::InvalidRequest => build_response(
                Version::default(),
                StatusCode::BadRequest,
                Body::new("Invalid request.".to_string()),
            ),
            RequestError::InvalidHeader => build_response(
                Version::default(),
                StatusCode::BadRequest,
                Body::new("Invalid headers.".to_string()),
            ),
            // `micro-http` supports a predefined list of HTTP headers.
            // It shouldn't reach this point, because it ignores the
            // HTTP unsupported headers.
            RequestError::UnsupportedHeader => unreachable!(),
        },
    }
}

#[cfg(test)]
mod tests {
    extern crate serde_json;
    use super::*;

    fn check_http_method_failure(method: String, status: StatusCode, err_msg: String) {
        let request = format!("{} http://169.254.169.254/ HTTP/1.1\r\n\r\n", method);
        let mut expected_response = Response::new(Version::Http11, status);
        expected_response.set_body(Body::new(err_msg));
        let actual_response = parse_request(request.as_bytes());
        assert!(expected_response.status() == actual_response.status());
        assert!(expected_response.body().unwrap() == actual_response.body().unwrap());
    }

    #[test]
    fn test_parse_request() {
        let data = r#"{
            "name": {
                "first": "John",
                "second": "Doe"
            },
            "age": 43,
            "phones": {
                "home": {
                    "RO": "+401234567",
                    "UK": "+441234567"
                },
                "mobile": "+442345678"
            }
        }"#;
        MMDS.lock()
            .unwrap()
            .put_data(serde_json::from_str(data).unwrap())
            .unwrap();

        // Test invalid request.
        let request = b"HTTP/1.1";
        let dummy_response = Response::new(Version::Http11, StatusCode::BadRequest);
        assert!(parse_request(request).status() == dummy_response.status());

        // Test unsupported HTTP version.
        let request = b"GET http://169.254.169.255/ HTTP/2.0\r\n\r\n";
        let mut expected_response = Response::new(Version::Http11, StatusCode::NotImplemented);
        expected_response.set_body(Body::new("Unsupported HTTP version.".to_string()));
        let actual_response = parse_request(request);

        assert!(expected_response.status() == actual_response.status());
        assert!(expected_response.body().unwrap() == actual_response.body().unwrap());
        assert!(expected_response.http_version() == actual_response.http_version());

        // Test invalid (empty absolute path) URI.
        let request = b"GET http:// HTTP/1.0\r\n\r\n";
        let mut expected_response = Response::new(Version::Http10, StatusCode::BadRequest);
        expected_response.set_body(Body::new("Invalid URI.".to_string()));
        let actual_response = parse_request(request);

        assert!(expected_response.status() == actual_response.status());
        assert!(expected_response.body().unwrap() == actual_response.body().unwrap());
        assert!(expected_response.http_version() == actual_response.http_version());

        // Test invalid HTTP format.
        let request = b"GET / HTTP/1.1\r\n";
        let mut expected_response = Response::new(Version::Http11, StatusCode::BadRequest);
        expected_response.set_body(Body::new("Invalid request.".to_string()));
        let actual_response = parse_request(request);

        assert!(expected_response.status() == actual_response.status());
        assert!(expected_response.body().unwrap() == actual_response.body().unwrap());
        assert!(expected_response.http_version() == actual_response.http_version());

        // Test resource not found.
        let request = b"GET http://169.254.169.254/invalid HTTP/1.0\r\n\r\n";
        let mut expected_response = Response::new(Version::Http10, StatusCode::NotFound);
        expected_response.set_body(Body::new("Resource not found: /invalid.".to_string()));
        let actual_response = parse_request(request);

        assert!(expected_response.status() == actual_response.status());
        assert!(expected_response.body().unwrap() == actual_response.body().unwrap());
        assert!(expected_response.http_version() == actual_response.http_version());

        // Test Ok path.
        let request = b"GET http://169.254.169.254/ HTTP/1.0\r\n\
                                    Accept: application/json\r\n\r\n";
        let mut expected_response = Response::new(Version::Http10, StatusCode::OK);
        let mut body = r#"{
                "age": 43,
                "name": {
                    "first": "John",
                    "second": "Doe"
                },
                "phones": {
                    "home": {
                        "RO": "+401234567",
                        "UK": "+441234567"
                    },
                    "mobile": "+442345678"
                }
        }"#
        .to_string();
        body.retain(|c| !c.is_whitespace());
        expected_response.set_body(Body::new(body));
        let actual_response = parse_request(request);

        assert!(expected_response.status() == actual_response.status());
        assert!(expected_response.body().unwrap() == actual_response.body().unwrap());
        assert!(expected_response.http_version() == actual_response.http_version());

        let request = b"GET /age HTTP/1.1\r\n\r\n";
        let mut expected_response = Response::new(Version::Http11, StatusCode::NotImplemented);
        let body = "Cannot retrieve value. The value has an unsupported type.".to_string();
        expected_response.set_body(Body::new(body));
        let actual_response = parse_request(request);

        assert!(expected_response.status() == actual_response.status());
        assert!(expected_response.body().unwrap() == actual_response.body().unwrap());
        assert!(expected_response.http_version() == actual_response.http_version());
    }

    #[test]
    fn test_unsupported_http_method() {
        check_http_method_failure(
            "PUT".to_string(),
            StatusCode::MethodNotAllowed,
            "Not allowed HTTP method.".to_string(),
        );
        check_http_method_failure(
            "PATCH".to_string(),
            StatusCode::MethodNotAllowed,
            "Not allowed HTTP method.".to_string(),
        );
        check_http_method_failure(
            "POST".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
        check_http_method_failure(
            "DELETE".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
        check_http_method_failure(
            "POST".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
        check_http_method_failure(
            "HEAD".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
        check_http_method_failure(
            "CONNECT".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
        check_http_method_failure(
            "OPTIONS".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
        check_http_method_failure(
            "TRACE".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
        check_http_method_failure(
            "NOMETHOD".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
    }

    #[test]
    fn test_json_patch() {
        let mut data = serde_json::json!({
            "name": {
                "first": "John",
                "second": "Doe"
            },
            "age": "43",
            "phones": {
                "home": {
                    "RO": "+40 1234567",
                    "UK": "+44 1234567"
                },
                "mobile": "+44 2345678"
            }
        });

        let patch = serde_json::json!({
            "name": {
                "second": null,
                "last": "Kennedy"
            },
            "age": "44",
            "phones": {
                "home": "+44 1234567",
                "mobile": {
                    "RO": "+40 2345678",
                    "UK": "+44 2345678"
                }
            }
        });
        json_patch(&mut data, &patch);

        // Test value replacement in target document.
        assert_eq!(data["age"], patch["age"]);

        // Test null value removal from target document.
        assert_eq!(data["name"]["second"], Value::Null);

        // Test add value to target document.
        assert_eq!(data["name"]["last"], patch["name"]["last"]);
        assert!(!data["phones"]["home"].is_object());
        assert_eq!(data["phones"]["home"], patch["phones"]["home"]);
        assert!(data["phones"]["mobile"].is_object());
        assert_eq!(
            data["phones"]["mobile"]["RO"],
            patch["phones"]["mobile"]["RO"]
        );
        assert_eq!(
            data["phones"]["mobile"]["UK"],
            patch["phones"]["mobile"]["UK"]
        );
    }
}
<commit_msg>Sanitize the MMDS request URI.<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

#[macro_use]
extern crate lazy_static;
extern crate serde_json;

extern crate micro_http;

pub mod data_store;

use serde_json::{Map, Value};
use std::sync::{Arc, Mutex};

use data_store::{Error as MmdsError, Mmds, OutputFormat};
use micro_http::{Body, MediaType, Method, Request, RequestError, Response, StatusCode, Version};

lazy_static! {
    // A static reference to a global Mmds instance. We currently use this for ease of access during
    // prototyping. We'll consider something like passing Arc<Mutex<Mmds>> references to the
    // appropriate threads in the future.
    pub static ref MMDS: Arc<Mutex<Mmds>> = Arc::new(Mutex::new(Mmds::default()));
}

impl Into<OutputFormat> for MediaType {
    fn into(self) -> OutputFormat {
        match self {
            MediaType::ApplicationJson => OutputFormat::Json,
            MediaType::PlainText => OutputFormat::Imds,
        }
    }
}

/// Patch provided JSON document (given as `serde_json::Value`) in-place with JSON Merge Patch
/// [RFC 7396](https://tools.ietf.org/html/rfc7396).
pub fn json_patch(target: &mut Value, patch: &Value) {
    if patch.is_object() {
        if !target.is_object() {
            // Replace target with a serde_json object so we can recursively copy patch values.
            *target = Value::Object(Map::new());
        }

        // This is safe since we make sure patch and target are objects beforehand.
        let doc = target.as_object_mut().unwrap();
        for (key, value) in patch.as_object().unwrap() {
            if value.is_null() {
                // If the value in the patch is null we remove the entry.
                doc.remove(key.as_str());
            } else {
                // Recursive call to update target document.
                // If `key` is not in the target document (it's a new field defined in `patch`)
                // insert a null placeholder and pass it as the new target
                // so we can insert new values recursively.
                json_patch(doc.entry(key.as_str()).or_insert(Value::Null), value);
            }
        }
    } else {
        *target = patch.clone();
    }
}

fn build_response(http_version: Version, status_code: StatusCode, body: Body) -> Response {
    let mut response = Response::new(http_version, status_code);
    response.set_body(body);
    response
}

// Make the URI a correct JSON pointer value.
fn sanitize_uri(mut uri: String) -> String {
    let mut len = u32::MAX as usize;
    // Loop while the deduping decreases the sanitized len.
    // Each iteration will attempt to dedup "//".
    while uri.len() < len {
        len = uri.len();
        uri = uri.replace("//", "/");
    }

    uri
}

pub fn parse_request(request_bytes: &[u8]) -> Response {
    let request = Request::try_from(request_bytes);
    match request {
        Ok(request) => {
            let uri = request.uri().get_abs_path();
            if uri.is_empty() {
                return build_response(
                    request.http_version(),
                    StatusCode::BadRequest,
                    Body::new("Invalid URI.".to_string()),
                );
            }

            if request.method() != Method::Get {
                let mut response = build_response(
                    request.http_version(),
                    StatusCode::MethodNotAllowed,
                    Body::new("Not allowed HTTP method."),
                );
                response.allow_method(Method::Get);
                return response;
            }

            // The data store expects a strict json path, so we need to
            // sanitize the URI.
            let json_pointer = sanitize_uri(uri.to_string());

            // The lock can be held by one thread only, so it is safe to unwrap.
            // If another thread poisoned the lock, we abort the execution.
            let response = MMDS
                .lock()
                .expect("Poisoned lock")
                .get_value(json_pointer, request.headers.accept().into());

            match response {
                Ok(response_body) => build_response(
                    request.http_version(),
                    StatusCode::OK,
                    Body::new(response_body),
                ),
                Err(e) => match e {
                    MmdsError::NotFound => {
                        let error_msg = format!("Resource not found: {}.", uri);
                        build_response(
                            request.http_version(),
                            StatusCode::NotFound,
                            Body::new(error_msg),
                        )
                    }
                    MmdsError::UnsupportedValueType => build_response(
                        request.http_version(),
                        StatusCode::NotImplemented,
                        Body::new(e.to_string()),
                    ),
                    MmdsError::NotInitialized => unreachable!(),
                },
            }
        }
        Err(e) => match e {
            RequestError::InvalidHttpVersion(err_msg) => build_response(
                Version::default(),
                StatusCode::NotImplemented,
                Body::new(err_msg.to_string()),
            ),
            RequestError::InvalidUri(err_msg) => build_response(
                Version::default(),
                StatusCode::BadRequest,
                Body::new(err_msg.to_string()),
            ),
            RequestError::InvalidHttpMethod(err_msg) => build_response(
                Version::default(),
                StatusCode::NotImplemented,
                Body::new(err_msg.to_string()),
            ),
            RequestError::InvalidRequest => build_response(
                Version::default(),
                StatusCode::BadRequest,
                Body::new("Invalid request.".to_string()),
            ),
            RequestError::InvalidHeader => build_response(
                Version::default(),
                StatusCode::BadRequest,
                Body::new("Invalid headers.".to_string()),
            ),
            // `micro-http` supports a predefined list of HTTP headers.
            // It shouldn't reach this point, because it ignores the
            // HTTP unsupported headers.
            RequestError::UnsupportedHeader => unreachable!(),
        },
    }
}

#[cfg(test)]
mod tests {
    extern crate serde_json;
    use super::*;

    fn check_http_method_failure(method: String, status: StatusCode, err_msg: String) {
        let request = format!("{} http://169.254.169.254/ HTTP/1.1\r\n\r\n", method);
        let mut expected_response = Response::new(Version::Http11, status);
        expected_response.set_body(Body::new(err_msg));
        let actual_response = parse_request(request.as_bytes());
        assert!(expected_response.status() == actual_response.status());
        assert!(expected_response.body().unwrap() == actual_response.body().unwrap());
    }

    #[test]
    fn test_parse_request() {
        let data = r#"{
            "name": {
                "first": "John",
                "second": "Doe"
            },
            "age": 43,
            "phones": {
                "home": {
                    "RO": "+401234567",
                    "UK": "+441234567"
                },
                "mobile": "+442345678"
            }
        }"#;
        MMDS.lock()
            .unwrap()
            .put_data(serde_json::from_str(data).unwrap())
            .unwrap();

        // Test invalid request.
        let request = b"HTTP/1.1";
        let dummy_response = Response::new(Version::Http11, StatusCode::BadRequest);
        assert!(parse_request(request).status() == dummy_response.status());

        // Test unsupported HTTP version.
        let request = b"GET http://169.254.169.255/ HTTP/2.0\r\n\r\n";
        let mut expected_response = Response::new(Version::Http11, StatusCode::NotImplemented);
        expected_response.set_body(Body::new("Unsupported HTTP version.".to_string()));
        let actual_response = parse_request(request);

        assert!(expected_response.status() == actual_response.status());
        assert!(expected_response.body().unwrap() == actual_response.body().unwrap());
        assert!(expected_response.http_version() == actual_response.http_version());

        // Test invalid (empty absolute path) URI.
        let request = b"GET http:// HTTP/1.0\r\n\r\n";
        let mut expected_response = Response::new(Version::Http10, StatusCode::BadRequest);
        expected_response.set_body(Body::new("Invalid URI.".to_string()));
        let actual_response = parse_request(request);

        assert!(expected_response.status() == actual_response.status());
        assert!(expected_response.body().unwrap() == actual_response.body().unwrap());
        assert!(expected_response.http_version() == actual_response.http_version());

        // Test invalid HTTP format.
        let request = b"GET / HTTP/1.1\r\n";
        let mut expected_response = Response::new(Version::Http11, StatusCode::BadRequest);
        expected_response.set_body(Body::new("Invalid request.".to_string()));
        let actual_response = parse_request(request);

        assert!(expected_response.status() == actual_response.status());
        assert!(expected_response.body().unwrap() == actual_response.body().unwrap());
        assert!(expected_response.http_version() == actual_response.http_version());

        // Test resource not found.
        let request = b"GET http://169.254.169.254/invalid HTTP/1.0\r\n\r\n";
        let mut expected_response = Response::new(Version::Http10, StatusCode::NotFound);
        expected_response.set_body(Body::new("Resource not found: /invalid.".to_string()));
        let actual_response = parse_request(request);

        assert!(expected_response.status() == actual_response.status());
        assert!(expected_response.body().unwrap() == actual_response.body().unwrap());
        assert!(expected_response.http_version() == actual_response.http_version());

        // Test Ok path.
        let request = b"GET http://169.254.169.254/ HTTP/1.0\r\n\
                                    Accept: application/json\r\n\r\n";
        let mut expected_response = Response::new(Version::Http10, StatusCode::OK);
        let mut body = r#"{
                "age": 43,
                "name": {
                    "first": "John",
                    "second": "Doe"
                },
                "phones": {
                    "home": {
                        "RO": "+401234567",
                        "UK": "+441234567"
                    },
                    "mobile": "+442345678"
                }
        }"#
        .to_string();
        body.retain(|c| !c.is_whitespace());
        expected_response.set_body(Body::new(body));
        let actual_response = parse_request(request);

        assert!(expected_response.status() == actual_response.status());
        assert!(expected_response.body().unwrap() == actual_response.body().unwrap());
        assert!(expected_response.http_version() == actual_response.http_version());

        let request = b"GET /age HTTP/1.1\r\n\r\n";
        let mut expected_response = Response::new(Version::Http11, StatusCode::NotImplemented);
        let body = "Cannot retrieve value. The value has an unsupported type.".to_string();
        expected_response.set_body(Body::new(body));
        let actual_response = parse_request(request);

        assert!(expected_response.status() == actual_response.status());
        assert!(expected_response.body().unwrap() == actual_response.body().unwrap());
        assert!(expected_response.http_version() == actual_response.http_version());
    }

    #[test]
    fn test_unsupported_http_method() {
        check_http_method_failure(
            "PUT".to_string(),
            StatusCode::MethodNotAllowed,
            "Not allowed HTTP method.".to_string(),
        );
        check_http_method_failure(
            "PATCH".to_string(),
            StatusCode::MethodNotAllowed,
            "Not allowed HTTP method.".to_string(),
        );
        check_http_method_failure(
            "POST".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
        check_http_method_failure(
            "DELETE".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
        check_http_method_failure(
            "POST".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
        check_http_method_failure(
            "HEAD".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
        check_http_method_failure(
            "CONNECT".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
        check_http_method_failure(
            "OPTIONS".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
        check_http_method_failure(
            "TRACE".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
        check_http_method_failure(
            "NOMETHOD".to_string(),
            StatusCode::NotImplemented,
            "Unsupported HTTP method.".to_string(),
        );
    }

    #[test]
    fn test_json_patch() {
        let mut data = serde_json::json!({
            "name": {
                "first": "John",
                "second": "Doe"
            },
            "age": "43",
            "phones": {
                "home": {
                    "RO": "+40 1234567",
                    "UK": "+44 1234567"
                },
                "mobile": "+44 2345678"
            }
        });

        let patch = serde_json::json!({
            "name": {
                "second": null,
                "last": "Kennedy"
            },
            "age": "44",
            "phones": {
                "home": "+44 1234567",
                "mobile": {
                    "RO": "+40 2345678",
                    "UK": "+44 2345678"
                }
            }
        });
        json_patch(&mut data, &patch);

        // Test value replacement in target document.
        assert_eq!(data["age"], patch["age"]);

        // Test null value removal from target document.
        assert_eq!(data["name"]["second"], Value::Null);

        // Test add value to target document.
        assert_eq!(data["name"]["last"], patch["name"]["last"]);
        assert!(!data["phones"]["home"].is_object());
        assert_eq!(data["phones"]["home"], patch["phones"]["home"]);
        assert!(data["phones"]["mobile"].is_object());
        assert_eq!(
            data["phones"]["mobile"]["RO"],
            patch["phones"]["mobile"]["RO"]
        );
        assert_eq!(
            data["phones"]["mobile"]["UK"],
            patch["phones"]["mobile"]["UK"]
        );
    }
}
<|endoftext|>


<commit_before>//! Parallel testing.
//!
//! mcuboot simulator is strictly single threaded, as there is a lock around running the C startup
//! code, because it contains numerous global variables.
//!
//! To help speed up testing, the Travis configuration defines all of the configurations that can
//! be run in parallel.  Fortunately, cargo works well this way, and these can be run by simply
//! using subprocess for each particular thread.

use chrono::Local;
use failure::format_err;
use log::{debug, error, warn};
use regex::Regex;
use std::{
    collections::HashSet,
    fs::{self, OpenOptions},
    io::{ErrorKind, stdout, Write},
    process::{Command, Output},
    result,
    sync::{
        Arc,
        Mutex,
    },
    thread,
    time::Duration,
};
use std_semaphore::Semaphore;
use yaml_rust::{
    Yaml,
    YamlLoader,
};

type Result<T> = result::Result<T, failure::Error>;

fn main() -> Result<()> {
    env_logger::init();

    let travis_text = fs::read_to_string("../.travis.yml")?;
    let travis = YamlLoader::load_from_str(&travis_text)?;

    let ncpus = num_cpus::get();
    let limiter = Arc::new(Semaphore::new(ncpus as isize));

    let matrix = Matrix::from_yaml(&travis)?;

    let mut children = vec![];
    let state = State::new(matrix.envs.len());
    let st2 = state.clone();
    let _status = thread::spawn(move || {
        loop {
            thread::sleep(Duration::new(15, 0));
            st2.lock().unwrap().status();
        }
    });
    for env in matrix.envs {
        let state = state.clone();
        let limiter = limiter.clone();

        let child = thread::spawn(move || {
            let _run = limiter.access();
            state.lock().unwrap().start(&env);
            let out = env.run();
            state.lock().unwrap().done(&env, out);
        });
        children.push(child);
    }

    for child in children {
        child.join().unwrap();
    }

    println!("");

    Ok(())
}

/// State, for printing status.
struct State {
    running: HashSet<String>,
    done: HashSet<String>,
    total: usize,
}

impl State {
    fn new(total: usize) -> Arc<Mutex<State>> {
        Arc::new(Mutex::new(State {
            running: HashSet::new(),
            done: HashSet::new(),
            total: total,
        }))
    }

    fn start(&mut self, fs: &FeatureSet) {
        let key = fs.textual();
        if self.running.contains(&key) || self.done.contains(&key) {
            warn!("Duplicate: {:?}", key);
        }
        debug!("Starting: {} ({} running)", key, self.running.len() + 1);
        self.running.insert(key);
        self.status();
    }

    fn done(&mut self, fs: &FeatureSet, output: Result<Option<Output>>) {
        let key = fs.textual();
        self.running.remove(&key);
        self.done.insert(key.clone());
        match output {
            Ok(None) => {
                // println!("Success {} ({} running)", key, self.running.len());
            }
            Ok(Some(output)) => {
                // Write the output into a file.
                let mut count = 1;
                let (mut fd, logname) = loop {
                    let name = format!("./failure-{:04}.log", count);
                    count += 1;
                    match OpenOptions::new()
                        .create_new(true)
                        .write(true)
                        .open(&name)
                    {
                        Ok(file) => break (file, name),
                        Err(ref err) if err.kind() == ErrorKind::AlreadyExists => continue,
                        Err(err) => {
                            error!("Unable to write log file to current directory: {:?}", err);
                            return;
                        }
                    }
                };
                writeln!(&mut fd, "Test failure {}", key).unwrap();
                writeln!(&mut fd, "time: {}", Local::now().to_rfc3339()).unwrap();
                writeln!(&mut fd, "----------------------------------------").unwrap();
                writeln!(&mut fd, "stdout:").unwrap();
                fd.write_all(&output.stdout).unwrap();
                writeln!(&mut fd, "----------------------------------------").unwrap();
                writeln!(&mut fd, "\nstderr:").unwrap();
                fd.write_all(&output.stderr).unwrap();
                error!("Failure {} log:{:?} ({} running)", key, logname,
                    self.running.len());
            }
            Err(err) => {
                error!("Unable to run test {:?} ({:?})", key, err);
            }
        }
        self.status();
    }

    fn status(&self) {
        let running = self.running.len();
        let done = self.done.len();
        print!(" {} running ({}/{}/{} done)\r", running, done, running + done, self.total);
        stdout().flush().unwrap();
    }
}

/// The extracted configurations from the travis config
#[derive(Debug)]
struct Matrix {
    envs: Vec<FeatureSet>,
}

#[derive(Debug, Eq, Hash, PartialEq)]
struct FeatureSet {
    // The environment variable to set.
    env: String,
    // The successive values to set it to.
    values: Vec<String>,
}

impl Matrix {
    fn from_yaml(yaml: &[Yaml]) -> Result<Matrix> {
        let mut envs = vec![];

        let mut all_tests = HashSet::new();

        for y in yaml {
            let m = match lookup_matrix(y) {
                Some (m) => m,
                None => continue,
            };
            for elt in m {
                if lookup_os(elt) == Some("linux") {
                    debug!("yaml: {:?}", lookup_env(elt));
                    let env = match lookup_env(elt) {
                        Some (env) => env,
                        None => continue,
                    };

                    let fset = FeatureSet::decode(env)?;
                    debug!("fset: {:?}", fset);

                    if false {
                        // Respect the groupings in the `.travis.yml` file.
                        envs.push(fset);
                    } else {
                        // Break each test up so we can run more in
                        // parallel.
                        let env = fset.env.clone();
                        for val in fset.values {
                            if !all_tests.contains(&val) {
                                all_tests.insert(val.clone());
                                envs.push(FeatureSet {
                                    env: env.clone(),
                                    values: vec![val],
                                });
                            } else {
                                warn!("Duplicate: {:?}: {:?}", env, val);
                            }
                        }
                    }
                }
            }
        }

        Ok(Matrix {
            envs: envs,
        })
    }
}

impl FeatureSet {
    fn decode(text: &str) -> Result<FeatureSet> {
        let re = Regex::new(r#"^([A-Z_]+)="(.*)"$"#)?;

        match re.captures(text) {
            None => Err(format_err!("Invalid line: {:?}", text)),
            Some(cap) => {
                let ename = &cap[1];
                let sep = if ename == "SINGLE_FEATURES" { ' ' } else { ',' };
                let values: Vec<_> = cap[2]
                    .split(sep)
                    .map(|s| s.to_string())
                    .collect();
                debug!("name={:?} values={:?}", ename, values);
                Ok(FeatureSet {
                    env: ename.to_string(),
                    values: values,
                })
            }
        }
    }

    /// Run a test for this given feature set.  Output is captured and will be returned if there is
    /// an error.  Each will be run successively, and the first failure will be returned.
    /// Otherwise, it returns None, which means everything worked.
    fn run(&self) -> Result<Option<Output>> {
        for v in &self.values {
            let output = Command::new("bash")
               .arg("./scripts/run_tests.sh")
               .current_dir("..")
               .env(&self.env, v)
               .output()?;
            if !output.status.success() {
                return Ok(Some(output));
            }
        }
        return Ok(None);
    }

    /// Convert this feature set into a textual representation
    fn textual(&self) -> String {
        use std::fmt::Write;

        let mut buf = String::new();

        write!(&mut buf, "{}:", self.env).unwrap();
        for v in &self.values {
            write!(&mut buf, " {}", v).unwrap();
        }

        buf
    }
}

fn lookup_matrix(y: &Yaml) -> Option<&Vec<Yaml>> {
    let matrix = Yaml::String("matrix".to_string());
    let include = Yaml::String("include".to_string());
    y.as_hash()?.get(&matrix)?.as_hash()?.get(&include)?.as_vec()
}

fn lookup_os(y: &Yaml) -> Option<&str> {
    let os = Yaml::String("os".to_string());

    y.as_hash()?.get(&os)?.as_str()
}

fn lookup_env(y: &Yaml) -> Option<&str> {
    let env = Yaml::String("env".to_string());

    y.as_hash()?.get(&env)?.as_str()
}
<commit_msg>ptest: Support new format of .travis.yml<commit_after>//! Parallel testing.
//!
//! mcuboot simulator is strictly single threaded, as there is a lock around running the C startup
//! code, because it contains numerous global variables.
//!
//! To help speed up testing, the Travis configuration defines all of the configurations that can
//! be run in parallel.  Fortunately, cargo works well this way, and these can be run by simply
//! using subprocess for each particular thread.

use chrono::Local;
use failure::format_err;
use log::{debug, error, warn};
use regex::Regex;
use std::{
    collections::HashSet,
    fs::{self, OpenOptions},
    io::{ErrorKind, stdout, Write},
    process::{Command, Output},
    result,
    sync::{
        Arc,
        Mutex,
    },
    thread,
    time::Duration,
};
use std_semaphore::Semaphore;
use yaml_rust::{
    Yaml,
    YamlLoader,
};

type Result<T> = result::Result<T, failure::Error>;

fn main() -> Result<()> {
    env_logger::init();

    let travis_text = fs::read_to_string("../.travis.yml")?;
    let travis = YamlLoader::load_from_str(&travis_text)?;

    let ncpus = num_cpus::get();
    let limiter = Arc::new(Semaphore::new(ncpus as isize));

    let matrix = Matrix::from_yaml(&travis)?;

    let mut children = vec![];
    let state = State::new(matrix.envs.len());
    let st2 = state.clone();
    let _status = thread::spawn(move || {
        loop {
            thread::sleep(Duration::new(15, 0));
            st2.lock().unwrap().status();
        }
    });
    for env in matrix.envs {
        let state = state.clone();
        let limiter = limiter.clone();

        let child = thread::spawn(move || {
            let _run = limiter.access();
            state.lock().unwrap().start(&env);
            let out = env.run();
            state.lock().unwrap().done(&env, out);
        });
        children.push(child);
    }

    for child in children {
        child.join().unwrap();
    }

    println!("");

    Ok(())
}

/// State, for printing status.
struct State {
    running: HashSet<String>,
    done: HashSet<String>,
    total: usize,
}

impl State {
    fn new(total: usize) -> Arc<Mutex<State>> {
        Arc::new(Mutex::new(State {
            running: HashSet::new(),
            done: HashSet::new(),
            total: total,
        }))
    }

    fn start(&mut self, fs: &FeatureSet) {
        let key = fs.textual();
        if self.running.contains(&key) || self.done.contains(&key) {
            warn!("Duplicate: {:?}", key);
        }
        debug!("Starting: {} ({} running)", key, self.running.len() + 1);
        self.running.insert(key);
        self.status();
    }

    fn done(&mut self, fs: &FeatureSet, output: Result<Option<Output>>) {
        let key = fs.textual();
        self.running.remove(&key);
        self.done.insert(key.clone());
        match output {
            Ok(None) => {
                // println!("Success {} ({} running)", key, self.running.len());
            }
            Ok(Some(output)) => {
                // Write the output into a file.
                let mut count = 1;
                let (mut fd, logname) = loop {
                    let name = format!("./failure-{:04}.log", count);
                    count += 1;
                    match OpenOptions::new()
                        .create_new(true)
                        .write(true)
                        .open(&name)
                    {
                        Ok(file) => break (file, name),
                        Err(ref err) if err.kind() == ErrorKind::AlreadyExists => continue,
                        Err(err) => {
                            error!("Unable to write log file to current directory: {:?}", err);
                            return;
                        }
                    }
                };
                writeln!(&mut fd, "Test failure {}", key).unwrap();
                writeln!(&mut fd, "time: {}", Local::now().to_rfc3339()).unwrap();
                writeln!(&mut fd, "----------------------------------------").unwrap();
                writeln!(&mut fd, "stdout:").unwrap();
                fd.write_all(&output.stdout).unwrap();
                writeln!(&mut fd, "----------------------------------------").unwrap();
                writeln!(&mut fd, "\nstderr:").unwrap();
                fd.write_all(&output.stderr).unwrap();
                error!("Failure {} log:{:?} ({} running)", key, logname,
                    self.running.len());
            }
            Err(err) => {
                error!("Unable to run test {:?} ({:?})", key, err);
            }
        }
        self.status();
    }

    fn status(&self) {
        let running = self.running.len();
        let done = self.done.len();
        print!(" {} running ({}/{}/{} done)\r", running, done, running + done, self.total);
        stdout().flush().unwrap();
    }
}

/// The extracted configurations from the travis config
#[derive(Debug)]
struct Matrix {
    envs: Vec<FeatureSet>,
}

#[derive(Debug, Eq, Hash, PartialEq)]
struct FeatureSet {
    // The environment variable to set.
    env: String,
    // The successive values to set it to.
    values: Vec<String>,
}

impl Matrix {
    fn from_yaml(yaml: &[Yaml]) -> Result<Matrix> {
        let mut envs = vec![];

        let mut all_tests = HashSet::new();

        for y in yaml {
            let m = match lookup_matrix(y) {
                Some (m) => m,
                None => continue,
            };
            for elt in m {
                if lookup_os(elt) == Some("linux") {
                    debug!("yaml: {:?}", lookup_env(elt));
                    let env = match lookup_env(elt) {
                        Some (env) => env,
                        None => continue,
                    };

                    // Skip features not targeted to this build.
                    let fset = match FeatureSet::decode(env) {
                        Ok(fset) => fset,
                        Err(err) => {
                            warn!("Skipping: {:?}", err);
                            continue;
                        }
                    };
                    debug!("fset: {:?}", fset);

                    if false {
                        // Respect the groupings in the `.travis.yml` file.
                        envs.push(fset);
                    } else {
                        // Break each test up so we can run more in
                        // parallel.
                        let env = fset.env.clone();
                        for val in fset.values {
                            if !all_tests.contains(&val) {
                                all_tests.insert(val.clone());
                                envs.push(FeatureSet {
                                    env: env.clone(),
                                    values: vec![val],
                                });
                            } else {
                                warn!("Duplicate: {:?}: {:?}", env, val);
                            }
                        }
                    }
                }
            }
        }

        Ok(Matrix {
            envs: envs,
        })
    }
}

impl FeatureSet {
    fn decode(text: &str) -> Result<FeatureSet> {
        // This is not general environment settings, but specific to the
        // travis file.
        let re = Regex::new(r#"^([A-Z_]+)="(.*)" TEST=sim$"#)?;

        match re.captures(text) {
            None => Err(format_err!("Invalid line: {:?}", text)),
            Some(cap) => {
                let ename = &cap[1];
                let sep = if ename == "SINGLE_FEATURES" { ' ' } else { ',' };
                let values: Vec<_> = cap[2]
                    .split(sep)
                    .map(|s| s.to_string())
                    .collect();
                debug!("name={:?} values={:?}", ename, values);
                Ok(FeatureSet {
                    env: ename.to_string(),
                    values: values,
                })
            }
        }
    }

    /// Run a test for this given feature set.  Output is captured and will be returned if there is
    /// an error.  Each will be run successively, and the first failure will be returned.
    /// Otherwise, it returns None, which means everything worked.
    fn run(&self) -> Result<Option<Output>> {
        for v in &self.values {
            let output = Command::new("bash")
               .arg("./ci/sim_run.sh")
               .current_dir("..")
               .env(&self.env, v)
               .output()?;
            if !output.status.success() {
                return Ok(Some(output));
            }
        }
        return Ok(None);
    }

    /// Convert this feature set into a textual representation
    fn textual(&self) -> String {
        use std::fmt::Write;

        let mut buf = String::new();

        write!(&mut buf, "{}:", self.env).unwrap();
        for v in &self.values {
            write!(&mut buf, " {}", v).unwrap();
        }

        buf
    }
}

fn lookup_matrix(y: &Yaml) -> Option<&Vec<Yaml>> {
    let matrix = Yaml::String("matrix".to_string());
    let include = Yaml::String("include".to_string());
    y.as_hash()?.get(&matrix)?.as_hash()?.get(&include)?.as_vec()
}

fn lookup_os(y: &Yaml) -> Option<&str> {
    let os = Yaml::String("os".to_string());

    y.as_hash()?.get(&os)?.as_str()
}

fn lookup_env(y: &Yaml) -> Option<&str> {
    let env = Yaml::String("env".to_string());

    y.as_hash()?.get(&env)?.as_str()
}
<|endoftext|>


<commit_before>//! # Parser Nodes
//!
//! Parser nodes represent the grammar that is defined
//! by the currently permissible set of commands and their
//! parameters.

#![allow(dead_code, missing_docs, unused_variables)]

use std::rc::Rc;

/// Minimum priority.
pub const PRIORITY_MINIMUM: i32 = -10000;
/// The default priority for a parameter.
pub const PRIORITY_PARAMETER: i32 = -10;
/// The default priority.
pub const PRIORITY_DEFAULT: i32 = 0;

pub trait Node {
    fn node_data(&self) -> &NodeFields;

    fn successors(&self) -> &Vec<Rc<Node>> {
        &self.node_data().successors
    }

    fn help_symbol(&self) -> String {
        self.node_data().name.to_string()
    }

    fn help_text(&self) -> &String {
        unimplemented!();
    }

    fn hidden(&self) -> bool {
        self.node_data().hidden
    }

    fn name(&self) -> &String {
        &self.node_data().name
    }

    fn priority(&self) -> i32 {
        self.node_data().priority
    }
}

/// A parse tree node.
pub struct NodeFields {
    /// Possible successor nodes. Collected while building.
    pub successors: Vec<Rc<Node>>,
    /// The name of this node.
    pub name: String,
    /// Match and complete priority.
    pub priority: i32,
    /// Hidden nodes are not completed. This doesn't modify matching.
    pub hidden: bool,
}

pub struct CommandNode {
    fields: CommandNodeFields,
}

pub struct CommandNodeFields {
    node: NodeFields,
    help: String,
    handler: Option<fn(&node: Node) -> ()>,
    parameters: Vec<Rc<ParameterNode>>,
}

impl Node for CommandNode {
    fn node_data(&self) -> &NodeFields {
        &self.fields.node
    }
}

impl CommandNode {
    pub fn handler(&self) -> Option<fn(&node: Node) -> ()> {
        self.fields.handler
    }

    /// Get the parameter nodes for this command
    pub fn parameters(&self) -> &Vec<Rc<ParameterNode>> {
        &self.fields.parameters
    }
}

pub struct WrapperNode {
    fields: WrapperNodeFields,
}

pub struct WrapperNodeFields {
    command: CommandNodeFields,
    root: Rc<Node>,
}

impl Node for WrapperNode {
    fn node_data(&self) -> &NodeFields {
        &self.fields.command.node
    }
}

pub struct ParameterNameNode {
    fields: ParameterNameNodeFields,
}

pub struct RepeatableNodeFields {
    repeatable: bool,
    repeat_marker: Option<Rc<Node>>,
}

pub struct ParameterNameNodeFields {
    node: NodeFields,
    repeatable: RepeatableNodeFields,
    help: String,
    parameter: Rc<Node>,
}

impl Node for ParameterNameNode {
    fn node_data(&self) -> &NodeFields {
        &self.fields.node
    }

    fn help_symbol(&self) -> String {
        self.fields.node.name.clone() + " " + self.fields.parameter.help_symbol().as_str()
    }

    fn help_text(&self) -> &String {
        &self.fields.help
    }
}

impl ParameterNameNode {
    pub fn repeatable(&self) -> bool {
        self.fields.repeatable.repeatable
    }

    pub fn repeat_marker(&self) -> &Option<Rc<Node>> {
        &self.fields.repeatable.repeat_marker
    }
}

pub trait ParameterNode {
    fn parameter_data(&self) -> &ParameterNodeFields;

    fn repeatable(&self) -> bool {
        self.parameter_data().repeatable.repeatable
    }

    fn repeat_marker(&self) -> &Option<Rc<Node>> {
        &self.parameter_data().repeatable.repeat_marker
    }

    fn required(&self) -> bool {
        self.parameter_data().required
    }
}

pub struct ParameterNodeFields {
    node: NodeFields,
    repeatable: RepeatableNodeFields,
    help: String,
    required: bool,
}

impl Node for ParameterNode {
    fn node_data(&self) -> &NodeFields {
        &self.parameter_data().node
    }

    fn help_symbol(&self) -> String {
        String::from("<") + self.node_data().name.as_str() +
        if self.repeatable() {
            ">..."
        } else {
            ">"
        }
    }

    fn help_text(&self) -> &String {
        &self.parameter_data().help
    }
}

pub struct FlagParameterNode {
    fields: ParameterNodeFields,
}

impl ParameterNode for FlagParameterNode {
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.fields
    }
}

pub struct NamedParameterNode {
    fields: ParameterNodeFields,
}

impl ParameterNode for NamedParameterNode {
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.fields
    }
}

pub struct SimpleParameterNode {
    fields: ParameterNodeFields,
}

impl ParameterNode for SimpleParameterNode {
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.fields
    }
}
<commit_msg>WrapperNode: Implement successors.<commit_after>//! # Parser Nodes
//!
//! Parser nodes represent the grammar that is defined
//! by the currently permissible set of commands and their
//! parameters.

#![allow(dead_code, missing_docs, unused_variables)]

use std::rc::Rc;

/// Minimum priority.
pub const PRIORITY_MINIMUM: i32 = -10000;
/// The default priority for a parameter.
pub const PRIORITY_PARAMETER: i32 = -10;
/// The default priority.
pub const PRIORITY_DEFAULT: i32 = 0;

pub trait Node {
    fn node_data(&self) -> &NodeFields;

    fn successors(&self) -> &Vec<Rc<Node>> {
        &self.node_data().successors
    }

    fn help_symbol(&self) -> String {
        self.node_data().name.to_string()
    }

    fn help_text(&self) -> &String {
        unimplemented!();
    }

    fn hidden(&self) -> bool {
        self.node_data().hidden
    }

    fn name(&self) -> &String {
        &self.node_data().name
    }

    fn priority(&self) -> i32 {
        self.node_data().priority
    }
}

/// A parse tree node.
pub struct NodeFields {
    /// Possible successor nodes. Collected while building.
    pub successors: Vec<Rc<Node>>,
    /// The name of this node.
    pub name: String,
    /// Match and complete priority.
    pub priority: i32,
    /// Hidden nodes are not completed. This doesn't modify matching.
    pub hidden: bool,
}

pub struct CommandNode {
    fields: CommandNodeFields,
}

pub struct CommandNodeFields {
    node: NodeFields,
    help: String,
    handler: Option<fn(&node: Node) -> ()>,
    parameters: Vec<Rc<ParameterNode>>,
}

impl Node for CommandNode {
    fn node_data(&self) -> &NodeFields {
        &self.fields.node
    }
}

impl CommandNode {
    pub fn handler(&self) -> Option<fn(&node: Node) -> ()> {
        self.fields.handler
    }

    /// Get the parameter nodes for this command
    pub fn parameters(&self) -> &Vec<Rc<ParameterNode>> {
        &self.fields.parameters
    }
}

pub struct WrapperNode {
    fields: WrapperNodeFields,
}

pub struct WrapperNodeFields {
    command: CommandNodeFields,
    root: Rc<Node>,
}

impl Node for WrapperNode {
    fn node_data(&self) -> &NodeFields {
        &self.fields.command.node
    }

    fn successors(&self) -> &Vec<Rc<Node>> {
        &self.fields.root.successors()
    }
}

pub struct ParameterNameNode {
    fields: ParameterNameNodeFields,
}

pub struct RepeatableNodeFields {
    repeatable: bool,
    repeat_marker: Option<Rc<Node>>,
}

pub struct ParameterNameNodeFields {
    node: NodeFields,
    repeatable: RepeatableNodeFields,
    help: String,
    parameter: Rc<Node>,
}

impl Node for ParameterNameNode {
    fn node_data(&self) -> &NodeFields {
        &self.fields.node
    }

    fn help_symbol(&self) -> String {
        self.fields.node.name.clone() + " " + self.fields.parameter.help_symbol().as_str()
    }

    fn help_text(&self) -> &String {
        &self.fields.help
    }
}

impl ParameterNameNode {
    pub fn repeatable(&self) -> bool {
        self.fields.repeatable.repeatable
    }

    pub fn repeat_marker(&self) -> &Option<Rc<Node>> {
        &self.fields.repeatable.repeat_marker
    }
}

pub trait ParameterNode {
    fn parameter_data(&self) -> &ParameterNodeFields;

    fn repeatable(&self) -> bool {
        self.parameter_data().repeatable.repeatable
    }

    fn repeat_marker(&self) -> &Option<Rc<Node>> {
        &self.parameter_data().repeatable.repeat_marker
    }

    fn required(&self) -> bool {
        self.parameter_data().required
    }
}

pub struct ParameterNodeFields {
    node: NodeFields,
    repeatable: RepeatableNodeFields,
    help: String,
    required: bool,
}

impl Node for ParameterNode {
    fn node_data(&self) -> &NodeFields {
        &self.parameter_data().node
    }

    fn help_symbol(&self) -> String {
        String::from("<") + self.node_data().name.as_str() +
        if self.repeatable() {
            ">..."
        } else {
            ">"
        }
    }

    fn help_text(&self) -> &String {
        &self.parameter_data().help
    }
}

pub struct FlagParameterNode {
    fields: ParameterNodeFields,
}

impl ParameterNode for FlagParameterNode {
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.fields
    }
}

pub struct NamedParameterNode {
    fields: ParameterNodeFields,
}

impl ParameterNode for NamedParameterNode {
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.fields
    }
}

pub struct SimpleParameterNode {
    fields: ParameterNodeFields,
}

impl ParameterNode for SimpleParameterNode {
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.fields
    }
}
<|endoftext|>


<commit_before>use parsers::*;

#[derive(Show, Eq, PartialEq, Clone)]
enum Input {
  A,
  B,
  C,
  D,
}

//need more tests :/

#[test]
fn test_seq() {
  let input = [Input::A, Input::B, Input::C, Input::D];
  let parser = seq!(literal(Input::A), literal(Input::B), literal(Input::C));
  assert_eq!( parser.parse(input.as_slice()) , Ok(((Input::A, (Input::B, Input::C)), input.slice_from(3))));
}

#[test]
fn test_seq_map() {
  let input = [Input::A, Input::B];
  let parser = seq!(literal(Input::A), literal(Input::B) to |&: (a, b)| 5u);
  let expected = Ok( (5u, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_rep() {
  let input = [Input::A, Input::B, Input::A, Input::B, Input::A, Input::C];
  let parser = rep!(seq!(literal(Input::A), literal(Input::B)));
  let expected = Ok((
    vec![(Input::A, Input::B), (Input::A, Input::B)],
    input.slice_from(4)
  ));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_or() {
  let input = [Input::A, Input::B, Input::A, Input::C];
  let parser = rep!(or!(literal(Input::A), literal(Input::B)));
  let expected = Ok((
    vec![Input::A, Input::B, Input::A],
    input.slice_from(3)
  ));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_multi_or() {
  let input = [Input::A];
  let parser = or!(literal(Input::A), literal(Input::B), literal(Input::C));
  let expected = Ok( (Input::A, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_or_map() {
  let input = [Input::B];
  let parser = or!(literal(Input::A), literal(Input::B) to |&: x| 5u);
  let expected = Ok( (5u, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_map() {
  let input = [Input::A];
  let parser = map!(literal(Input::A), |&: a| 5u);
  let expected = Ok( (5u, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_recursive_or() {
  let input = [Input::A, Input::A, Input::C];
  fn a_seq<'a>() -> Box<Parser<'a, &'a [Input], uint> + 'a> {
    Box::new(or!(
      map!(literal(Input::C), |&: _| 2u),
      map!(seq!(literal(Input::A), lazy!(a_seq())), |&: (a, seq)| 1u + seq)
    ))
  }
  let parser = a_seq();
  let expected = Ok( (4u, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );

}

#[test]
fn test_repsep() {
  let input = [Input::A, Input::B, Input::C, Input::B, Input::A, Input::A];
  let parser = repsep!(or!(literal(Input::A), literal(Input::C)) , literal(Input::B));
  let expected = Ok((vec![Input::A, Input::C, Input::A], input.slice_from(5)));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_opt() {
  let input = [Input::A, Input::A, Input::B];
  let parser = rep!(seq!(literal(Input::A), opt!(literal(Input::B))));
  let expected = Ok((vec![(Input::A, None), (Input::A, Some(Input::B))], input.slice_from(3)));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_matcher() {
  let input = [Input::A, Input::B, Input::C];
  let parser = rep!(matcher!(Input : Input::A => 4u, Input::B => 5u));
  let expected = Ok( (vec![4u, 5u], input.slice_from(2)) );
  assert_eq!( parser.parse(input.as_slice()), expected );

}

<commit_msg>Remove all trailing 'u' from integer literals<commit_after>use parsers::*;

#[derive(Show, Eq, PartialEq, Clone)]
enum Input {
  A,
  B,
  C,
  D,
}

//need more tests :/

#[test]
fn test_seq() {
  let input = [Input::A, Input::B, Input::C, Input::D];
  let parser = seq!(literal(Input::A), literal(Input::B), literal(Input::C));
  assert_eq!( parser.parse(input.as_slice()) , Ok(((Input::A, (Input::B, Input::C)), input.slice_from(3))));
}

#[test]
fn test_seq_map() {
  let input = [Input::A, Input::B];
  let parser = seq!(literal(Input::A), literal(Input::B) to |&: (a, b)| 5);
  let expected = Ok( (5, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_rep() {
  let input = [Input::A, Input::B, Input::A, Input::B, Input::A, Input::C];
  let parser = rep!(seq!(literal(Input::A), literal(Input::B)));
  let expected = Ok((
    vec![(Input::A, Input::B), (Input::A, Input::B)],
    input.slice_from(4)
  ));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_or() {
  let input = [Input::A, Input::B, Input::A, Input::C];
  let parser = rep!(or!(literal(Input::A), literal(Input::B)));
  let expected = Ok((
    vec![Input::A, Input::B, Input::A],
    input.slice_from(3)
  ));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_multi_or() {
  let input = [Input::A];
  let parser = or!(literal(Input::A), literal(Input::B), literal(Input::C));
  let expected = Ok( (Input::A, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_or_map() {
  let input = [Input::B];
  let parser = or!(literal(Input::A), literal(Input::B) to |&: x| 5);
  let expected = Ok( (5, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_map() {
  let input = [Input::A];
  let parser = map!(literal(Input::A), |&: a| 5);
  let expected = Ok( (5, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_recursive_or() {
  let input = [Input::A, Input::A, Input::C];
  fn a_seq<'a>() -> Box<Parser<'a, &'a [Input], usize> + 'a> {
    Box::new(or!(
      map!(literal(Input::C), |&: _| 2),
      map!(seq!(literal(Input::A), lazy!(a_seq())), |&: (a, seq)| 1 + seq)
    ))
  }
  let parser = a_seq();
  let expected = Ok( (4, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_repsep() {
  let input = [Input::A, Input::B, Input::C, Input::B, Input::A, Input::A];
  let parser = repsep!(or!(literal(Input::A), literal(Input::C)) , literal(Input::B));
  let expected = Ok((vec![Input::A, Input::C, Input::A], input.slice_from(5)));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_opt() {
  let input = [Input::A, Input::A, Input::B];
  let parser = rep!(seq!(literal(Input::A), opt!(literal(Input::B))));
  let expected = Ok((vec![(Input::A, None), (Input::A, Some(Input::B))], input.slice_from(3)));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_matcher() {
  let input = [Input::A, Input::B, Input::C];
  let parser = rep!(matcher!(Input : Input::A => 4, Input::B => 5));
  let expected = Ok( (vec![4, 5], input.slice_from(2)) );
  assert_eq!( parser.parse(input.as_slice()), expected );

}

<|endoftext|>