<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate docopt;
extern crate csv;
extern crate rustc_serialize;
extern crate mimir;
#[macro_use]
extern crate log;
extern crate geo;

use std::path::Path;
use mimir::rubber::Rubber;
use mimir::objects::Admin;
use std::fs;
use std::rc::Rc;
use std::collections::BTreeMap;

type AdminFromInsee = BTreeMap<String, Rc<Admin>>;

#[derive(RustcDecodable, RustcEncodable)]
pub struct Bano {
    pub id: String,
    pub nb: String,
    pub street: String,
    pub zip: String,
    pub city: String,
    pub src: String,
    pub lat: f64,
    pub lon: f64,
}

impl Bano {
    pub fn insee(&self) -> &str {
        assert!(self.id.len() >= 5);
        self.id[..5].trim_left_matches('0')
    }
    pub fn fantoir(&self) -> &str {
        assert!(self.id.len() >= 10);
        &self.id[..10]
    }
    pub fn into_addr(self, admins: &AdminFromInsee) -> mimir::Addr {
        let street_name = format!("{} ({})", self.street, self.city);
        let addr_name = format!("{} {}", self.nb, self.street);
        let addr_label = format!("{} ({})", addr_name, self.city);
        let street_id = format!("street:{}", self.fantoir().to_string());
        let admin = admins.get(&format!("admin:fr:{}", self.insee()));

        let street = mimir::Street {
            id: street_id,
            street_name: self.street,
            label: street_name.to_string(),
            administrative_regions: admin.map_or(vec![], |a| vec![a.clone()]),
            weight: 1,
            zip_codes: vec![self.zip.clone()],
            coord: mimir::Coord::new(self.lat, self.lon),
        };
        mimir::Addr {
            id: format!("addr:{};{}", self.lon, self.lat),
            house_number: self.nb,
            street: street,
            label: addr_label,
            coord: mimir::Coord::new(self.lat, self.lon),
            weight: 1,
            zip_codes: vec![self.zip.clone()],
        }
    }
}

fn index_bano<I>(cnx_string: &str, dataset: &str, files: I)
    where I: Iterator<Item = std::path::PathBuf>
{
    let doc_type = "addr";
    let mut rubber = Rubber::new(cnx_string);

    let admins_by_insee = rubber.get_admins_from_dataset(dataset)
        .unwrap_or_else(|err| {
            info!("Administratives regions not found in es db for dataset {}. (error: {})",
                  dataset,
                  err);
            vec![]
        })
        .into_iter()
        .fold(AdminFromInsee::new(), |mut a_by_insee, a| {
            a_by_insee.insert(a.id.to_string(), Rc::new(a));
            a_by_insee
        });

    let addr_index = rubber.make_index(doc_type, dataset).unwrap();
    info!("Add data in elasticsearch db.");
    for f in files {
        info!("importing {:?}...", &f);
        let mut rdr = csv::Reader::from_file(&f).unwrap().has_headers(false);

        let iter = rdr.decode().map(|r| {
            let b: Bano = r.unwrap();
            b.into_addr(&admins_by_insee)
        });
        match rubber.bulk_index(&addr_index, iter) {
            Err(e) => panic!("failed to bulk insert file {:?} because: {}", &f, e),
            Ok(nb) => info!("importing {:?}: {} addresses added.", &f, nb),
        }
    }
    rubber.publish_index(doc_type, dataset, addr_index).unwrap();
}

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_connection_string: String,
    flag_dataset: String,
}

static USAGE: &'static str = "
Usage:
    bano2mimir --input=<input> [--connection-string=<connection-string>] [--dataset=<dataset>]

    -i, --input=<input>           Bano files. Can be either a directory or a file.
    -c, --connection-string=<connection-string>
                                  Elasticsearch parameters, [default: http://localhost:9200/munin]
    -d, --dataset=<dataset>       Name of the dataset, [default: fr]
";

fn main() {
    mimir::logger_init().unwrap();
    info!("importing bano into Mimir");

    let args: Args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    let file_path = Path::new(&args.flag_input);
    if file_path.is_dir() {
        let paths: std::fs::ReadDir = fs::read_dir(&args.flag_input).unwrap();
        index_bano(&args.flag_connection_string,
                   &args.flag_dataset,
                   paths.map(|p| p.unwrap().path()));
    } else {
        index_bano(&args.flag_connection_string,
                   &args.flag_dataset,
                   std::iter::once(std::path::PathBuf::from(&args.flag_input)));
    }
}
<commit_msg>correction after review<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate docopt;
extern crate csv;
extern crate rustc_serialize;
extern crate mimir;
#[macro_use]
extern crate log;
extern crate geo;

use std::path::Path;
use mimir::rubber::Rubber;
use mimir::objects::Admin;
use std::fs;
use std::rc::Rc;
use std::collections::BTreeMap;

type AdminFromInsee = BTreeMap<String, Rc<Admin>>;

#[derive(RustcDecodable, RustcEncodable)]
pub struct Bano {
    pub id: String,
    pub nb: String,
    pub street: String,
    pub zip: String,
    pub city: String,
    pub src: String,
    pub lat: f64,
    pub lon: f64,
}

impl Bano {
    pub fn insee(&self) -> &str {
        assert!(self.id.len() >= 5);
        self.id[..5].trim_left_matches('0')
    }
    pub fn fantoir(&self) -> &str {
        assert!(self.id.len() >= 10);
        &self.id[..10]
    }
    pub fn into_addr(self, admins: &AdminFromInsee) -> mimir::Addr {
        let street_name = format!("{} ({})", self.street, self.city);
        let addr_name = format!("{} {}", self.nb, self.street);
        let addr_label = format!("{} ({})", addr_name, self.city);
        let street_id = format!("street:{}", self.fantoir().to_string());
        let admin = admins.get(&format!("admin:fr:{}", self.insee()));

        let street = mimir::Street {
            id: street_id,
            street_name: self.street,
            label: street_name.to_string(),
            administrative_regions: admin.map_or(vec![], |a| vec![a.clone()]),
            weight: 1,
            zip_codes: vec![self.zip.clone()],
            coord: mimir::Coord::new(self.lat, self.lon),
        };
        mimir::Addr {
            id: format!("addr:{};{}", self.lon, self.lat),
            house_number: self.nb,
            street: street,
            label: addr_label,
            coord: mimir::Coord::new(self.lat, self.lon),
            weight: 1,
            zip_codes: vec![self.zip.clone()],
        }
    }
}

fn index_bano<I>(cnx_string: &str, dataset: &str, files: I)
    where I: Iterator<Item = std::path::PathBuf>
{
    let doc_type = "addr";
    let mut rubber = Rubber::new(cnx_string);

    let admins_by_insee = rubber.get_admins_from_dataset(dataset)
        .unwrap_or_else(|err| {
            info!("Administratives regions not found in es db for dataset {}. (error: {})",
                  dataset,
                  err);
            vec![]
        })
        .into_iter()
        .map(|a| (a.id.to_string(), Rc::new(a)))
        .collect();

    let addr_index = rubber.make_index(doc_type, dataset).unwrap();
    info!("Add data in elasticsearch db.");
    for f in files {
        info!("importing {:?}...", &f);
        let mut rdr = csv::Reader::from_file(&f).unwrap().has_headers(false);

        let iter = rdr.decode().map(|r| {
            let b: Bano = r.unwrap();
            b.into_addr(&admins_by_insee)
        });
        match rubber.bulk_index(&addr_index, iter) {
            Err(e) => panic!("failed to bulk insert file {:?} because: {}", &f, e),
            Ok(nb) => info!("importing {:?}: {} addresses added.", &f, nb),
        }
    }
    rubber.publish_index(doc_type, dataset, addr_index).unwrap();
}

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_connection_string: String,
    flag_dataset: String,
}

static USAGE: &'static str = "
Usage:
    bano2mimir --input=<input> [--connection-string=<connection-string>] [--dataset=<dataset>]

    -i, --input=<input>           Bano files. Can be either a directory or a file.
    -c, --connection-string=<connection-string>
                                  Elasticsearch parameters, [default: http://localhost:9200/munin]
    -d, --dataset=<dataset>       Name of the dataset, [default: fr]
";

fn main() {
    mimir::logger_init().unwrap();
    info!("importing bano into Mimir");

    let args: Args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    let file_path = Path::new(&args.flag_input);
    if file_path.is_dir() {
        let paths: std::fs::ReadDir = fs::read_dir(&args.flag_input).unwrap();
        index_bano(&args.flag_connection_string,
                   &args.flag_dataset,
                   paths.map(|p| p.unwrap().path()));
    } else {
        index_bano(&args.flag_connection_string,
                   &args.flag_dataset,
                   std::iter::once(std::path::PathBuf::from(&args.flag_input)));
    }
}
<|endoftext|>


<commit_before>use error::{CliError, Usage, UsageKind};
use super::Command;

use lib::setting::Cron;

#[derive(Debug)]
pub struct Patrol;

impl Command for Patrol {
    fn allow_to_check_current_dir(&self) -> bool { false }
    fn allow_to_check_settings(&self) -> bool { false }

    fn usage(&self) -> Usage {
        return Usage::new(UsageKind::Patrol);
    }

    fn main(&self) -> Result<(), CliError> {
        let cron = try!(Cron::read());
        let cron = try!(cron.discard());
        cron.set()
    }
}
<commit_msg>[Remedy] Devide Patrol.main() by environment<commit_after>use error::{CliError, Usage, UsageKind};
use super::Command;

use lib::setting::Cron;

#[derive(Debug)]
pub struct Patrol;

impl Command for Patrol {
    fn allow_to_check_current_dir(&self) -> bool { false }
    fn allow_to_check_settings(&self) -> bool { false }

    fn usage(&self) -> Usage {
        return Usage::new(UsageKind::Patrol);
    }

    #[cfg(unix)]
    fn main(&self) -> Result<(), CliError> {
        let cron = try!(Cron::read());
        let cron = try!(cron.discard());
        cron.set()
    }
    #[cfg(windows)]
    fn main(&self) -> Result<(), CliError> {
        unimplemented!();
    }
}
<|endoftext|>


<commit_before>use cube_shell::cube_shell;
use terrain_block::BlockPosition;
use std::collections::RingBuf;

#[cfg(test)]
use std::iter::range_inclusive;
#[cfg(test)]
use cube_shell::cube_shell_area;
#[cfg(test)]
use surroundings_loader::radius_between;

pub struct SurroundingsIter {
  pub center: BlockPosition,
  pub next_distance: i32,
  pub max_distance: i32,
  pub to_load_buffer: RingBuf<BlockPosition>,
}

impl SurroundingsIter {
  pub fn new(center: BlockPosition, max_distance: i32) -> SurroundingsIter {
    let mut to_load_buffer = RingBuf::new();
    to_load_buffer.push_back(center);

    SurroundingsIter {
      center: center,
      next_distance: 0,
      max_distance: max_distance,
      to_load_buffer: to_load_buffer,
    }
  }
}

impl Iterator for SurroundingsIter {
  type Item = BlockPosition;

  #[inline]
  fn next(&mut self) -> Option<BlockPosition> {
    let r = self.to_load_buffer.pop_front();
    if r.is_some() && self.to_load_buffer.is_empty() {
      debug!("Done loading surroundings at distance {}", self.next_distance);
      if self.next_distance < self.max_distance {
        self.next_distance += 1;
        self.to_load_buffer.extend(
          cube_shell(&self.center, self.next_distance).into_iter()
        );
      } else {
        debug!("Done loading surroundings");
      }
    }
    r
  }
}

#[test]
fn shell_ordering() {
  let center = BlockPosition::new(-1, 2, 3);
  let max_distance = 4;
  let mut iter = SurroundingsIter::new(center, max_distance);

  for distance in range_inclusive(0, max_distance) {
    for _ in range(0, cube_shell_area(distance)) {
      let block_posn = iter.next().unwrap();
      assert_eq!(radius_between(&center, &block_posn), distance);
    }
  }

  assert!(iter.next().is_none());
}
<commit_msg>"Done loading surroundings" message from debug! -> info!<commit_after>use cube_shell::cube_shell;
use terrain_block::BlockPosition;
use std::collections::RingBuf;

#[cfg(test)]
use std::iter::range_inclusive;
#[cfg(test)]
use cube_shell::cube_shell_area;
#[cfg(test)]
use surroundings_loader::radius_between;

pub struct SurroundingsIter {
  pub center: BlockPosition,
  pub next_distance: i32,
  pub max_distance: i32,
  pub to_load_buffer: RingBuf<BlockPosition>,
}

impl SurroundingsIter {
  pub fn new(center: BlockPosition, max_distance: i32) -> SurroundingsIter {
    let mut to_load_buffer = RingBuf::new();
    to_load_buffer.push_back(center);

    SurroundingsIter {
      center: center,
      next_distance: 0,
      max_distance: max_distance,
      to_load_buffer: to_load_buffer,
    }
  }
}

impl Iterator for SurroundingsIter {
  type Item = BlockPosition;

  #[inline]
  fn next(&mut self) -> Option<BlockPosition> {
    let r = self.to_load_buffer.pop_front();
    if r.is_some() && self.to_load_buffer.is_empty() {
      debug!("Done loading surroundings at distance {}", self.next_distance);
      if self.next_distance < self.max_distance {
        self.next_distance += 1;
        self.to_load_buffer.extend(
          cube_shell(&self.center, self.next_distance).into_iter()
        );
      } else {
        info!("Done loading surroundings");
      }
    }
    r
  }
}

#[test]
fn shell_ordering() {
  let center = BlockPosition::new(-1, 2, 3);
  let max_distance = 4;
  let mut iter = SurroundingsIter::new(center, max_distance);

  for distance in range_inclusive(0, max_distance) {
    for _ in range(0, cube_shell_area(distance)) {
      let block_posn = iter.next().unwrap();
      assert_eq!(radius_between(&center, &block_posn), distance);
    }
  }

  assert!(iter.next().is_none());
}
<|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 std::env;
use std::path::{Path, PathBuf};
use std::io::prelude::*;
use std::fs::{canonicalize, read_dir, File};

fn write_shaders(glsl_files: Vec<PathBuf>, shader_file_path: &Path) {
    let mut shader_file = File::create(shader_file_path).unwrap();

    write!(shader_file, "/// AUTO GENERATED BY build.rs\n\n").unwrap();
    write!(shader_file, "use std::collections::HashMap;\n").unwrap();
    write!(shader_file, "lazy_static! {{\n").unwrap();
    write!(shader_file, "  pub static ref SHADERS: HashMap<&'static str, &'static str> = {{\n").unwrap();
    write!(shader_file, "    let mut h = HashMap::with_capacity({});\n", glsl_files.len()).unwrap();
    for glsl in glsl_files {
        let shader_name = glsl.file_name().unwrap().to_str().unwrap();
        // strip .glsl
        let shader_name = shader_name.replace(".glsl", "");
        let full_path = canonicalize(&glsl).unwrap();
        let full_name = full_path.as_os_str().to_str().unwrap();
        // if someone is building on a network share, I'm sorry.
        let full_name = full_name.replace("\\\\?\\", "");
        let full_name = full_name.replace("\\", "/");
        write!(shader_file, "    h.insert(\"{}\", include_str!(\"{}\"));\n",
               shader_name, full_name).unwrap();
    }
    write!(shader_file, "    h\n").unwrap();
    write!(shader_file, "  }};\n").unwrap();
    write!(shader_file, "}}\n").unwrap();
}

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap_or("out".to_owned());

    let shaders_file = Path::new(&out_dir).join("shaders.rs");
    let mut glsl_files = vec![];

    let res_dir = Path::new("res");
    for entry in read_dir(res_dir).unwrap() {
        let entry = entry.unwrap();
        let path = entry.path();
        if entry.file_name().to_str().unwrap().ends_with(".glsl") {
            glsl_files.push(path.to_owned());
        }
    }

    write_shaders(glsl_files, &shaders_file);
}
<commit_msg>Auto merge of #683 - servo:jrmuizel-rerun-if-changed, r=glennw<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::env;
use std::path::{Path, PathBuf};
use std::io::prelude::*;
use std::fs::{canonicalize, read_dir, File};

fn write_shaders(glsl_files: Vec<PathBuf>, shader_file_path: &Path) {
    let mut shader_file = File::create(shader_file_path).unwrap();

    write!(shader_file, "/// AUTO GENERATED BY build.rs\n\n").unwrap();
    write!(shader_file, "use std::collections::HashMap;\n").unwrap();
    write!(shader_file, "lazy_static! {{\n").unwrap();
    write!(shader_file, "  pub static ref SHADERS: HashMap<&'static str, &'static str> = {{\n").unwrap();
    write!(shader_file, "    let mut h = HashMap::with_capacity({});\n", glsl_files.len()).unwrap();
    for glsl in glsl_files {
        let shader_name = glsl.file_name().unwrap().to_str().unwrap();
        // strip .glsl
        let shader_name = shader_name.replace(".glsl", "");
        let full_path = canonicalize(&glsl).unwrap();
        let full_name = full_path.as_os_str().to_str().unwrap();
        // if someone is building on a network share, I'm sorry.
        let full_name = full_name.replace("\\\\?\\", "");
        let full_name = full_name.replace("\\", "/");
        write!(shader_file, "    h.insert(\"{}\", include_str!(\"{}\"));\n",
               shader_name, full_name).unwrap();
    }
    write!(shader_file, "    h\n").unwrap();
    write!(shader_file, "  }};\n").unwrap();
    write!(shader_file, "}}\n").unwrap();
}

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap_or("out".to_owned());

    let shaders_file = Path::new(&out_dir).join("shaders.rs");
    let mut glsl_files = vec![];

    println!("cargo:rerun-if-changed=res");
    let res_dir = Path::new("res");
    for entry in read_dir(res_dir).unwrap() {
        let entry = entry.unwrap();
        let path = entry.path();
        if entry.file_name().to_str().unwrap().ends_with(".glsl") {
            glsl_files.push(path.to_owned());
        }
    }

    write_shaders(glsl_files, &shaders_file);
}
<|endoftext|>


<commit_before>//! Example based on http://sourceforge.net/p/iup/iup/HEAD/tree/trunk/iup/html/examples/Lua/button.lua
//!
//! Creates four buttons. The first uses images, the second turns the first on and off, the third
//! exits the application and the last does nothing
//!

#[macro_use]
extern crate iup;

use iup::Element;
use iup::dialog::Dialog;
use iup::control::{Button, Text};
use iup::layout::{VBox, HBox, Fill};
use iup::image::{Image, ImageElement};
use iup::callback::{Action, CallbackReturn};
use iup::callback::button::{MouseButton, MouseButtonState, ButtonCb};

fn main() {
    iup::with_iup(|| {

    	// We can create a image inline to be embedded in a control...
    	let img_release = Image::with(pixels![
       		[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
			[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2],
			[1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
	      	[1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
			[1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
		 	[1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
		 	[1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
		 	[1,1,3,3,3,3,3,3,4,4,3,3,3,3,2,2],
		  	[1,1,3,3,3,3,3,4,4,4,4,3,3,3,2,2],
		   	[1,1,3,3,3,3,3,4,4,4,4,3,3,3,2,2],
			[1,1,3,3,3,3,3,3,4,4,3,3,3,3,2,2],
		   	[1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
		   	[1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
			[1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
		   	[1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
		   	[1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],
		   	[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]
    	]).set_colors([(0, 0, 0), (215,215,215), (40, 40, 40), (30, 50, 210), (240, 0, 0)]);

    	// Creates a text box
    	let mut text = Text::new()
    	        			.set_attrib("READONLY", "YES")
    	   					.set_attrib("EXPAND", "YES");

    	// Creates a button with image
    	let mut btn_image = Button::with_title("Button with image")
    							.set_attrib_handle("IMAGE", img_release)
    							.set_button_cb(move |(_, button, state, _, _, _)| {
    								if button == MouseButton::Button1 {
    									text.set_attrib("VALUE", format!("Odd button {}", match state {
    										MouseButtonState::Pressed => "pressed",
    										MouseButtonState::Released => "released",
    									}));
    								}
    							});

    	// Creates a [useless] button
    	let btn_big = Button::with_title("Big useless button")
    							.set_attrib("SIZE", "0.125x0.125");

    	// Creates a button entitled Exit
    	let btn_exit = Button::with_title("Exit")
    							.set_action(|_| CallbackReturn::Close);

    	// Creates a button entitled 'Activate'
    	let btn_on_off = Button::with_title("Activate")
    							.set_action(move |_| {
	    							if btn_image.attrib("ACTIVE").unwrap() == "YES" {
	    								btn_image.set_attrib("ACTIVE", "NO");
	    							} else {
	    								btn_image.set_attrib("ACTIVE", "YES");
	    							}
	    						});

    	// Creates a dialog window
    	Dialog::new(
    		VBox::new(elements![
    			HBox::new(elements![
    				Fill::new(), btn_image, btn_on_off, btn_exit, Fill::new()
    			]),
    			text, btn_big
    		])
    	).set_attrib("TITLE", "IupButton")
    	 .set_attrib("RESIZE", "NO")		// Turn of resize
    	 .set_attrib("MENUBOX", "NO")		// ... menu box
    	 .set_attrib("MAXBOX", "NO")		// ... maximize
    	 .set_attrib("MINBOX", "NO")		// and minimize
    	 .show()

	}).unwrap();
}
<commit_msg>Fix example identation<commit_after>//! Example based on http://sourceforge.net/p/iup/iup/HEAD/tree/trunk/iup/html/examples/Lua/button.lua
//!
//! Creates four buttons. The first uses images, the second turns the first on and off, the third
//! exits the application and the last does nothing
//!

#[macro_use]
extern crate iup;

use iup::Element;
use iup::dialog::Dialog;
use iup::control::{Button, Text};
use iup::layout::{VBox, HBox, Fill};
use iup::image::{Image, ImageElement};
use iup::callback::{Action, CallbackReturn};
use iup::callback::button::{MouseButton, MouseButtonState, ButtonCb};

fn main() {
    iup::with_iup(|| {

        // We can create a image inline to be embedded in a control...
        let img_release = Image::with(pixels![
            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2],
            [1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
            [1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
            [1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
            [1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
            [1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
            [1,1,3,3,3,3,3,3,4,4,3,3,3,3,2,2],
            [1,1,3,3,3,3,3,4,4,4,4,3,3,3,2,2],
            [1,1,3,3,3,3,3,4,4,4,4,3,3,3,2,2],
            [1,1,3,3,3,3,3,3,4,4,3,3,3,3,2,2],
            [1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
            [1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
            [1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
            [1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2],
            [1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],
            [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]
        ]).set_colors([(0, 0, 0), (215,215,215), (40, 40, 40), (30, 50, 210), (240, 0, 0)]);

        // Creates a text box
        let mut text = Text::new()
                            .set_attrib("READONLY", "YES")
                            .set_attrib("EXPAND", "YES");

        // Creates a button with image
        let mut btn_image = Button::with_title("Button with image")
                                .set_attrib_handle("IMAGE", img_release)
                                .set_button_cb(move |(_, button, state, _, _, _)| {
                                    if button == MouseButton::Button1 {
                                        text.set_attrib("VALUE", format!("Odd button {}", match state {
                                            MouseButtonState::Pressed => "pressed",
                                            MouseButtonState::Released => "released",
                                        }));
                                    }
                                });

        // Creates a [useless] button
        let btn_big = Button::with_title("Big useless button")
                                .set_attrib("SIZE", "0.125x0.125");

        // Creates a button entitled Exit
        let btn_exit = Button::with_title("Exit")
                                .set_action(|_| CallbackReturn::Close);

        // Creates a button entitled 'Activate'
        let btn_on_off = Button::with_title("Activate")
                                .set_action(move |_| {
                                    if btn_image.attrib("ACTIVE").unwrap() == "YES" {
                                        btn_image.set_attrib("ACTIVE", "NO");
                                    } else {
                                        btn_image.set_attrib("ACTIVE", "YES");
                                    }
                                });

        // Creates a dialog window
        Dialog::new(
            VBox::new(elements![
                HBox::new(elements![
                    Fill::new(), btn_image, btn_on_off, btn_exit, Fill::new()
                ]),
                text, btn_big
            ])
        ).set_attrib("TITLE", "IupButton")
         .set_attrib("RESIZE", "NO")        // Turn of resize
         .set_attrib("MENUBOX", "NO")       // ... menu box
         .set_attrib("MAXBOX", "NO")        // ... maximize
         .set_attrib("MINBOX", "NO")        // and minimize
         .show()

    }).unwrap();
}
<|endoftext|>


<commit_before>extern crate kvm;
extern crate memmap;

use kvm::{Exit, IoDirection, System, Vcpu, VirtualMachine};
use memmap::{Mmap, Protection};

fn main() {
    let mut anon_mmap = Mmap::anonymous(2 * (1 << 20), Protection::ReadWrite)
                            .unwrap();
    let slice = unsafe { anon_mmap.as_mut_slice() };

    slice[0x100000] = 0xe4;
    slice[0x100001] = 0x01;

    let sys = System::initialize().unwrap();

    let mut vm = VirtualMachine::create(&sys).unwrap();

    vm.set_user_memory_region(0, slice, 0).unwrap();

    let mut vcpu = Vcpu::create(&mut vm).unwrap();

    let mut cpuid = sys.get_supported_cpuid().unwrap();
    vcpu.set_cpuid2(&mut cpuid).unwrap();

    let mut sregs = vcpu.get_sregs().unwrap();

    sregs.cs.base = 0x0;
    sregs.cs.limit = 0xffffffff;
    sregs.cs.selector = 0x8;
    sregs.cs._type = 0xb;
    sregs.cs.present = 1;
    sregs.cs.dpl = 0;
    sregs.cs.db = 0;
    sregs.cs.s = 1;
    sregs.cs.l = 0;
    sregs.cs.g = 1;
    sregs.cs.avl = 0;

    sregs.ss.base = 0x0;
    sregs.ss.limit = 0xffffffff;
    sregs.ss.selector = 0;
    sregs.ss._type = 0;
    sregs.ss.present = 0;
    sregs.ss.dpl = 0;
    sregs.ss.db = 1;
    sregs.ss.s = 0;
    sregs.ss.l = 0;
    sregs.ss.g = 1;
    sregs.ss.avl = 0;

    sregs.ds.base = 0x0;
    sregs.ds.limit = 0xffffffff;
    sregs.ds.selector = 0;
    sregs.ds._type = 0;
    sregs.ds.present = 0;
    sregs.ds.dpl = 0;
    sregs.ds.db = 1;
    sregs.ds.s = 0;
    sregs.ds.l = 0;
    sregs.ds.g = 1;
    sregs.ds.avl = 0;

    sregs.es.base = 0x0;
    sregs.es.limit = 0xffffffff;
    sregs.es.selector = 0;
    sregs.es._type = 0;
    sregs.es.present = 0;
    sregs.es.dpl = 0;
    sregs.es.db = 1;
    sregs.es.s = 0;
    sregs.es.l = 0;
    sregs.es.g = 1;
    sregs.es.avl = 0;

    sregs.fs.base = 0x0;
    sregs.fs.limit = 0xffffffff;
    sregs.fs.selector = 0;
    sregs.fs._type = 0;
    sregs.fs.present = 0;
    sregs.fs.dpl = 0;
    sregs.fs.db = 1;
    sregs.fs.s = 0;
    sregs.fs.l = 0;
    sregs.fs.g = 1;
    sregs.fs.avl = 0;

    sregs.gs.base = 0x0;
    sregs.gs.limit = 0xffffffff;
    sregs.gs.selector = 0;
    sregs.gs._type = 0;
    sregs.gs.present = 0;
    sregs.gs.dpl = 0;
    sregs.gs.db = 1;
    sregs.gs.s = 0;
    sregs.gs.l = 0;
    sregs.gs.g = 1;
    sregs.gs.avl = 0;

    sregs.cr0 = 0x50033;
    sregs.cr4 = 0x1046b0;

    vcpu.set_sregs(&sregs).unwrap();

    let mut regs = vcpu.get_regs().unwrap();
    regs.rip = 0x100000;
    regs.rflags = 0x246;
    vcpu.set_regs(&regs).unwrap();
    let run = unsafe { vcpu.run() }.unwrap();
    assert!(run.exit_reason == Exit::Io);
    let io = unsafe { *run.io() };
    assert!(io.direction == IoDirection::In);
    assert!(io.size == 1);
    assert!(io.port == 0x1);
    unsafe {
        println!("{:#?}", *run.io());
    }
}
<commit_msg>Update and document example<commit_after>// In this example we will construct a single CPU x86 VM which will execute
// "inb 0x01" at ring 0 with paging disabled

extern crate kvm;
extern crate memmap;

use kvm::{Capability, Exit, IoDirection, System, Vcpu, VirtualMachine};
use memmap::{Mmap, Protection};

fn main() {
    // Allocate 2MB for the guest memory
    let mut anon_mmap = Mmap::anonymous(2 * (1 << 20), Protection::ReadWrite)
                            .unwrap();
    let slice = unsafe { anon_mmap.as_mut_slice() };

    // Write the "inb 0x01" instruction at 1MB
    slice[0x100000] = 0xe4;
    slice[0x100001] = 0x01;

    // Initialize the KVM system
    let sys = System::initialize().unwrap();

    // Create a Virtual Machine
    let mut vm = VirtualMachine::create(&sys).unwrap();

    // Ensure that the VM supports memory backing with user memory
    assert!(vm.check_capability(Capability::UserMemory) > 0);
    // Set the 2 MB range to start at physical address 0
    vm.set_user_memory_region(0, slice, 0).unwrap();

    // Create a new VCPU
    let mut vcpu = Vcpu::create(&mut vm).unwrap();

    // Set supported CPUID (KVM fails without doing this)
    let mut cpuid = sys.get_supported_cpuid().unwrap();
    vcpu.set_cpuid2(&mut cpuid).unwrap();

    // Setup the special registers
    let mut sregs = vcpu.get_sregs().unwrap();

    // Set the code segment to have base 0, limit 4GB (flat segmentation)
    sregs.cs.base = 0x0;
    sregs.cs.limit = 0xffffffff;
    sregs.cs.selector = 0x8;
    sregs.cs._type = 0xb;
    sregs.cs.present = 1;
    sregs.cs.dpl = 0;
    sregs.cs.db = 0;
    sregs.cs.s = 1;
    sregs.cs.l = 0;
    sregs.cs.g = 1;
    sregs.cs.avl = 0;

    // We don't need to populate the GDT if we have our segments setup
    // cr0 - protected mode on, paging disabled
    sregs.cr0 = 0x50033;

    // Set the special registers
    vcpu.set_sregs(&sregs).unwrap();

    let mut regs = vcpu.get_regs().unwrap();
    // set the instruction pointer to 1 MB
    regs.rip = 0x100000;
    regs.rflags = 0x2;
    vcpu.set_regs(&regs).unwrap();

    // Actually run the VCPU
    let run = unsafe { vcpu.run() }.unwrap();

    // Ensure that the exit reason we get back indicates that the I/O
    // instruction was executed
    assert!(run.exit_reason == Exit::Io);
    let io = unsafe { *run.io() };
    assert!(io.direction == IoDirection::In);
    assert!(io.size == 1);
    assert!(io.port == 0x1);
    unsafe {
        println!("{:#?}", *run.io());
    }
}
<|endoftext|>


<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! External, remote flash abstraction.
//!
//! This crate provides the [`Flash`] (and related) traits, which represent
//! *abstract flash devices*. An abstract flash device is a region of memory
//! that can be transactionally read or written. Such a "device" can range
//! from a simple Rust slice to a remote SPI flash device (or even a subregion of
//! it!).
//!
//! [`Flash`]: trait.Flash.html

use core::convert::TryInto;

use static_assertions::assert_obj_safe;

use zerocopy::AsBytes;
use zerocopy::FromBytes;

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use crate::io;
use crate::mem::Arena;

/// A [`Flash`] error.
///
/// All of these errors are non-retryable; a [`Flash`] implementation should
/// block until the operation succeeds.
///
/// [`Flash`]: trait.Flash.html
#[derive(Copy, Clone, Debug)]
pub enum Error {
    /// Indicates that an operation failed because the requested
    /// operation was outside of the device's address space.
    OutOfRange,

    /// Indicates that the device is locked in some manner and cannot
    /// be affected by the operation.
    Locked,

    /// Indicates that an internal invariant was violated, such as running out
    /// of memory.
    Internal,

    /// Indicates that an unspecified error occured.
    Unspecified,
}

/// Provides access to a flash-like storage device.
///
/// This trait provides abstract operations on a device, as if it were a
/// block of random-access memory. It is the implementation's responsibility
/// to implement these operations efficiently with respect to the underlying
/// device.
///
/// The `Flash` trait comes implemented for `[u8]`.
pub trait Flash {
    /// Returns the size, in bytes, of this device.
    fn size(&self) -> Result<u32, Error>;

    /// Attempts to read `out.len()` bytes starting at `offset`.
    fn read(&self, offset: Ptr, out: &mut [u8]) -> Result<(), Error>;

    /// Attempts to write `out.len()` bytes starting at `offset`.
    ///
    /// Note that this function is not guaranteed to succeed (and be
    /// reflected in the return value of `read`) until `flush()` is called.
    /// This is to permit a `Flash` implementation to buffer writes before
    /// sending them out.
    ///
    /// Implementations are, as an optimization, permitted to assume that
    /// writes will be serial and localized, so as to minimize clearing
    /// operations on flash hardware.
    fn program(&mut self, offset: Ptr, buf: &[u8]) -> Result<(), Error>;

    /// Flushes any pending `program()` operations.
    fn flush(&mut self) -> Result<(), Error> {
        Ok(())
    }
}
assert_obj_safe!(Flash);

impl<F: Flash> Flash for &mut F {
    #[inline]
    fn size(&self) -> Result<u32, Error> {
        F::size(self)
    }

    #[inline]
    fn read(&self, offset: Ptr, out: &mut [u8]) -> Result<(), Error> {
        F::read(self, offset, out)
    }

    #[inline]
    fn program(&mut self, offset: Ptr, buf: &[u8]) -> Result<(), Error> {
        F::program(self, offset, buf)
    }

    #[inline]
    fn flush(&mut self) -> Result<(), Error> {
        F::flush(self)
    }
}

/// A [`Flash`] type that allows for zero-copy reads.
///
/// This trait allows implementations that can support a zero-copy read,
/// perhaps due to their inherently-buffering nature, to do so directly.
///
/// Normal [`Flash`] implementations can be made to support zero-copy
/// reads by combining them with an [`Arena`]; see [`ArenaFlash`].
///
/// `[u8]` implements this trait with no overhead.
///
/// [`Flash`]: trait.Flash.html
/// [`ArenaFlash]: struct.ArenaFlash.html
pub trait FlashZero: Flash {
    /// Attempts to zero-copy read the given region out of this device.
    fn read_zerocopy(&self, slice: Region) -> Result<&[u8], Error>;

    /// Hints to the implementation that it can release any buffered contents
    /// it is currently holding.
    ///
    /// See [`Arena::reset()`].
    ///
    /// [`Arena::reset()`]: ../../mem/trait.Arena.html#tymethod.reset
    fn reset(&mut self) -> Result<(), Error> {
        Ok(())
    }
}
assert_obj_safe!(FlashZero);

impl<F: FlashZero> FlashZero for &mut F {
    #[inline]
    fn read_zerocopy(&self, slice: Region) -> Result<&[u8], Error> {
        F::read_zerocopy(self, slice)
    }

    #[inline]
    fn reset(&mut self) -> Result<(), Error> {
        F::reset(self)
    }
}

/// Shim for supporting "zero-copy" reads on a [`Flash`] via an [`Arena`].
///
/// This type wraps a [`Flash`] type, plus an [`Arena`], and implements
/// zero-copy reads by first allocating a buffer on the arena and then
/// using that allocation to perform a read.
///
/// [`Flash`]: trait.Flash.html
/// [`Arena`]: ../../mem/trait.Arena.html
pub struct ArenaFlash<F, A>(pub F, pub A);

impl<F: Flash, A> Flash for ArenaFlash<F, A> {
    #[inline]
    fn size(&self) -> Result<u32, Error> {
        self.0.size()
    }

    #[inline]
    fn read(&self, offset: Ptr, out: &mut [u8]) -> Result<(), Error> {
        self.0.read(offset, out)
    }

    #[inline]
    fn program(&mut self, offset: Ptr, buf: &[u8]) -> Result<(), Error> {
        self.0.program(offset, buf)
    }

    #[inline]
    fn flush(&mut self) -> Result<(), Error> {
        self.0.flush()
    }
}

impl<F: Flash, A: Arena> FlashZero for ArenaFlash<F, A> {
    fn read_zerocopy(&self, slice: Region) -> Result<&[u8], Error> {
        let Self(flash, arena) = self;
        let buf = arena
            .alloc(slice.len as usize)
            .map_err(|_| Error::Internal)?;
        flash.read(slice.ptr, buf)?;
        Ok(buf)
    }

    #[inline]
    fn reset(&mut self) -> Result<(), Error> {
        Ok(self.1.reset())
    }
}

/// A [`Read`]/[`Write`] implementation for operating on a [`Flash`] serially.
///
/// [`Read`]: ../../io/read/trait.Read.html
/// [`Write`]: ../../io/write/trait.Write.html
/// [`Flash`]: trait.Flash.html
pub struct FlashIo<F> {
    flash: F,
    cursor: u32,
    len: u32,
}

impl<F: Flash> FlashIo<F> {
    /// Creates a new `FlashIo`, reading/writing from the beginning of `flash`.
    pub fn new(flash: F) -> Result<Self, Error> {
        let len = flash.size()?;
        Ok(Self {
            flash,
            cursor: 0,
            len,
        })
    }

    /// Skips the cursor `bytes` bytes forward.
    ///
    /// This operation always succeeds, but attempting to read past the end of
    /// flash will always result in an error.
    pub fn skip(&mut self, bytes: usize) {
        self.cursor = self.cursor.saturating_add(bytes as u32);
    }
}

impl<F: Flash> io::Read for FlashIo<F> {
    fn read_bytes(&mut self, out: &mut [u8]) -> Result<(), io::Error> {
        self.flash
            .read(Ptr::new(self.cursor), out)
            .map_err(|_| io::Error::Internal)?;
        self.cursor += out.len() as u32;
        Ok(())
    }

    fn remaining_data(&self) -> usize {
        self.len.saturating_sub(self.cursor) as usize
    }
}

impl<F: Flash> io::Write for FlashIo<F> {
    fn write_bytes(&mut self, buf: &[u8]) -> Result<(), io::Error> {
        self.flash
            .program(Ptr::new(self.cursor), buf)
            .map_err(|_| io::Error::Internal)?;
        self.cursor += buf.len() as u32;
        Ok(())
    }
}

/// An abstract pointer into a [`Flash`] type.
///
/// A `Ptr` needs to be used in conjunction with a [`Flash`]
/// implementation to be read from or written to.
///
/// [`Flash`]: trait.Flash.html
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, AsBytes, FromBytes)]
#[repr(transparent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Ptr {
    /// The abstract address of this pointer.
    pub address: u32,
}

impl Ptr {
    /// Convenience method for creating a `Ptr` without having to use
    /// a struct literal.
    pub const fn new(address: u32) -> Self {
        Self { address }
    }
}

/// A region within  a [`Flash`] type.
///
/// Much like a [`Ptr`], a `Region` needs to be interpreted with
/// respect to a [`Flash`] implementation.
///
/// [`Flash`]: trait.Flash.html
/// [`Ptr`]: struct.Ptr.html
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, AsBytes, FromBytes)]
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Region {
    /// The base pointer for this slice.
    #[cfg_attr(feature = "serde", serde(flatten))]
    pub ptr: Ptr,
    /// The length of the slice, in bytes.
    pub len: u32,
}

impl Region {
    /// Convenience method for creating a `Region` without having to use
    /// a struct literal.
    pub const fn new(ptr: u32, len: u32) -> Self {
        Self {
            ptr: Ptr::new(ptr),
            len,
        }
    }
}

/// An unspecified out-of-bounds error.
#[derive(Copy, Clone, Debug)]
pub struct OutOfBounds;

impl Flash for [u8] {
    fn size(&self) -> Result<u32, Error> {
        self.len().try_into().map_err(|_| Error::Unspecified)
    }

    fn read(&self, offset: Ptr, out: &mut [u8]) -> Result<(), Error> {
        let start = offset.address as usize;
        let end = start.checked_add(out.len()).ok_or(Error::OutOfRange)?;
        if end >= self.len() {
            return Err(Error::OutOfRange);
        }

        out.copy_from_slice(&self[start..end]);
        Ok(())
    }

    fn program(&mut self, offset: Ptr, buf: &[u8]) -> Result<(), Error> {
        let start = offset.address as usize;
        let end = start.checked_add(buf.len()).ok_or(Error::OutOfRange)?;
        if end >= self.len() {
            return Err(Error::OutOfRange);
        }

        self[start..end].copy_from_slice(buf);
        Ok(())
    }
}

impl FlashZero for [u8] {
    fn read_zerocopy(&self, offset: Region) -> Result<&[u8], Error> {
        let start = offset.ptr.address as usize;
        let end = start
            .checked_add(offset.len as usize)
            .ok_or(Error::OutOfRange)?;
        if end >= self.len() {
            return Err(Error::OutOfRange);
        }

        Ok(&self[start..end])
    }
}
<commit_msg>[hardware] Add SubFlash and expand built-in Flash impls<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! External, remote flash abstraction.
//!
//! This crate provides the [`Flash`] (and related) traits, which represent
//! *abstract flash devices*. An abstract flash device is a region of memory
//! that can be transactionally read or written. Such a "device" can range
//! from a simple Rust slice to a remote SPI flash device (or even a subregion of
//! it!).
//!
//! [`Flash`]: trait.Flash.html

use core::convert::TryInto;

use static_assertions::assert_obj_safe;

use zerocopy::AsBytes;
use zerocopy::FromBytes;

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use crate::io;
use crate::mem::Arena;

/// A [`Flash`] error.
///
/// All of these errors are non-retryable; a [`Flash`] implementation should
/// block until the operation succeeds.
///
/// [`Flash`]: trait.Flash.html
#[derive(Copy, Clone, Debug)]
pub enum Error {
    /// Indicates that an operation failed because the requested
    /// operation was outside of the device's address space.
    OutOfRange,

    /// Indicates that the device is locked in some manner and cannot
    /// be affected by the operation.
    Locked,

    /// Indicates that an internal invariant was violated, such as running out
    /// of memory.
    Internal,

    /// Indicates that an unspecified error occured.
    Unspecified,
}

/// Provides access to a flash-like storage device.
///
/// This trait provides abstract operations on a device, as if it were a
/// block of random-access memory. It is the implementation's responsibility
/// to implement these operations efficiently with respect to the underlying
/// device.
pub trait Flash {
    /// Returns the size, in bytes, of this device.
    fn size(&self) -> Result<u32, Error>;

    /// Attempts to read `out.len()` bytes starting at `offset`.
    fn read(&self, offset: Ptr, out: &mut [u8]) -> Result<(), Error>;

    /// Attempts to write `out.len()` bytes starting at `offset`.
    ///
    /// Note that this function is not guaranteed to succeed (and be
    /// reflected in the return value of `read`) until `flush()` is called.
    /// This is to permit a `Flash` implementation to buffer writes before
    /// sending them out.
    ///
    /// Implementations are, as an optimization, permitted to assume that
    /// writes will be serial and localized, so as to minimize clearing
    /// operations on flash hardware.
    fn program(&mut self, offset: Ptr, buf: &[u8]) -> Result<(), Error>;

    /// Flushes any pending `program()` operations.
    fn flush(&mut self) -> Result<(), Error> {
        Ok(())
    }
}
assert_obj_safe!(Flash);

impl<F: Flash> Flash for &F {
    #[inline]
    fn size(&self) -> Result<u32, Error> {
        F::size(self)
    }

    #[inline]
    fn read(&self, offset: Ptr, out: &mut [u8]) -> Result<(), Error> {
        F::read(self, offset, out)
    }

    #[inline]
    fn program(&mut self, _: Ptr, _: &[u8]) -> Result<(), Error> {
        Err(Error::Locked)
    }

    #[inline]
    fn flush(&mut self) -> Result<(), Error> {
        Err(Error::Locked)
    }
}

impl<F: Flash> Flash for &mut F {
    #[inline]
    fn size(&self) -> Result<u32, Error> {
        F::size(self)
    }

    #[inline]
    fn read(&self, offset: Ptr, out: &mut [u8]) -> Result<(), Error> {
        F::read(self, offset, out)
    }

    #[inline]
    fn program(&mut self, offset: Ptr, buf: &[u8]) -> Result<(), Error> {
        F::program(self, offset, buf)
    }

    #[inline]
    fn flush(&mut self) -> Result<(), Error> {
        F::flush(self)
    }
}

/// A [`Flash`] type that allows for zero-copy reads.
///
/// This trait allows implementations that can support a zero-copy read,
/// perhaps due to their inherently-buffering nature, to do so directly.
///
/// Normal [`Flash`] implementations can be made to support zero-copy
/// reads by combining them with an [`Arena`]; see [`ArenaFlash`].
///
/// [`Flash`]: trait.Flash.html
/// [`ArenaFlash`]: struct.ArenaFlash.html
pub trait FlashZero: Flash {
    /// Attempts to zero-copy read the given region out of this device.
    fn read_zerocopy(&self, slice: Region) -> Result<&[u8], Error>;

    /// Hints to the implementation that it can release any buffered contents
    /// it is currently holding.
    ///
    /// See [`Arena::reset()`].
    ///
    /// [`Arena::reset()`]: ../../mem/trait.Arena.html#tymethod.reset
    fn reset(&mut self) -> Result<(), Error> {
        Ok(())
    }
}
assert_obj_safe!(FlashZero);

// NOTE: implementing for &impl FlashZero doesn't make sense, because that
// would result in an unresettable FlashZero.

impl<F: FlashZero> FlashZero for &mut F {
    #[inline]
    fn read_zerocopy(&self, slice: Region) -> Result<&[u8], Error> {
        F::read_zerocopy(self, slice)
    }

    #[inline]
    fn reset(&mut self) -> Result<(), Error> {
        F::reset(self)
    }
}

/// Adapter for working with a sub-region of a [`Flash`] type.
///
/// Reads and writes on the device will be constrained to a given [`Region`].
/// This is especially useful for operating on a blob contained within another
/// region of flash.
///
/// There is no requirement that [`Region`] actually overlap with the address
/// space of `F`; the [`Flash`] implementation is still responsible for doing
/// bounds checks, after offsets are bounds-checked within `Region`.
#[derive(Copy, Clone)]
pub struct SubFlash<F>(pub F, pub Region);

impl<F: Flash> SubFlash<F> {
    /// Creates a new `SubFlash` representing the entirety of the given device.
    pub fn full(flash: F) -> Result<Self, Error> {
        let region = Region::new(0, flash.size()?);
        Ok(Self(flash, region))
    }
}

impl<F> SubFlash<F> {
    /// Interprets `region` as a subregion of this `SubFlash`, returning a new
    /// `SubFlash` that represents that region.
    pub fn reslice(self, region: Region) -> Option<Self> {
        if region.len >= self.1.len {
            return None;
        }

        Some(Self(
            self.0,
            Region::new(
                self.1.ptr.address.checked_add(region.ptr.address)?,
                region.len,
            ),
        ))
    }
}

impl<F: Flash> Flash for SubFlash<F> {
    #[inline]
    fn size(&self) -> Result<u32, Error> {
        Ok(self.1.len)
    }

    #[inline]
    fn read(&self, offset: Ptr, out: &mut [u8]) -> Result<(), Error> {
        if offset.address >= self.1.len {
            return Err(Error::OutOfRange);
        }
        let offset = offset
            .address
            .checked_add(self.1.ptr.address)
            .ok_or(Error::OutOfRange)?;

        self.0.read(Ptr::new(offset), out)
    }

    #[inline]
    fn program(&mut self, offset: Ptr, buf: &[u8]) -> Result<(), Error> {
        if offset.address >= self.1.len {
            return Err(Error::OutOfRange);
        }
        let offset = offset
            .address
            .checked_add(self.1.ptr.address)
            .ok_or(Error::OutOfRange)?;

        self.0.program(Ptr::new(offset), buf)
    }

    #[inline]
    fn flush(&mut self) -> Result<(), Error> {
        self.0.flush()
    }
}

impl<F: FlashZero> FlashZero for SubFlash<F> {
    #[inline]
    fn read_zerocopy(&self, slice: Region) -> Result<&[u8], Error> {
        if slice.ptr.address > self.1.len {
            return Err(Error::OutOfRange);
        }
        let offset = slice
            .ptr
            .address
            .checked_add(self.1.ptr.address)
            .ok_or(Error::OutOfRange)?;

        self.0.read_zerocopy(Region::new(offset, slice.len))
    }

    #[inline]
    fn reset(&mut self) -> Result<(), Error> {
        self.0.reset()
    }
}

/// Adapter for supporting "zero-copy" reads on a [`Flash`] via an [`Arena`].
///
/// This type wraps a [`Flash`] type, plus an [`Arena`], and implements
/// zero-copy reads by first allocating a buffer on the arena and then
/// using that allocation to perform a read.
///
/// [`Flash`]: trait.Flash.html
/// [`Arena`]: ../../mem/trait.Arena.html
#[derive(Copy, Clone)]
pub struct ArenaFlash<F, A>(pub F, pub A);

impl<F: Flash, A> Flash for ArenaFlash<F, A> {
    #[inline]
    fn size(&self) -> Result<u32, Error> {
        self.0.size()
    }

    #[inline]
    fn read(&self, offset: Ptr, out: &mut [u8]) -> Result<(), Error> {
        self.0.read(offset, out)
    }

    #[inline]
    fn program(&mut self, offset: Ptr, buf: &[u8]) -> Result<(), Error> {
        self.0.program(offset, buf)
    }

    #[inline]
    fn flush(&mut self) -> Result<(), Error> {
        self.0.flush()
    }
}

impl<F: Flash, A: Arena> FlashZero for ArenaFlash<F, A> {
    fn read_zerocopy(&self, slice: Region) -> Result<&[u8], Error> {
        let Self(flash, arena) = self;
        let buf = arena
            .alloc(slice.len as usize)
            .map_err(|_| Error::Internal)?;
        flash.read(slice.ptr, buf)?;
        Ok(buf)
    }

    #[inline]
    fn reset(&mut self) -> Result<(), Error> {
        Ok(self.1.reset())
    }
}

/// Adapter for converting RAM-backed storage into a [`FlashZero`].
///
/// For the purposes of this type, "RAM-backed" means that `AsRef<[u8]>`
/// is implemented.
///
/// [`FlashZero`]: traits.Flash.html
#[derive(Copy, Clone)]
pub struct Ram<Bytes>(pub Bytes);

impl<Bytes: AsRef<[u8]>> Flash for Ram<Bytes> {
    fn size(&self) -> Result<u32, Error> {
        self.0
            .as_ref()
            .len()
            .try_into()
            .map_err(|_| Error::Unspecified)
    }

    fn read(&self, offset: Ptr, out: &mut [u8]) -> Result<(), Error> {
        let start = offset.address as usize;
        let end = start.checked_add(out.len()).ok_or(Error::OutOfRange)?;
        if end > self.0.as_ref().len() {
            return Err(Error::OutOfRange);
        }

        out.copy_from_slice(&self.0.as_ref()[start..end]);
        Ok(())
    }

    fn program(&mut self, _: Ptr, _: &[u8]) -> Result<(), Error> {
        return Err(Error::Locked);
    }
}

impl<Bytes: AsRef<[u8]>> FlashZero for Ram<Bytes> {
    fn read_zerocopy(&self, offset: Region) -> Result<&[u8], Error> {
        let start = offset.ptr.address as usize;
        let end = start
            .checked_add(offset.len as usize)
            .ok_or(Error::OutOfRange)?;
        if end > self.0.as_ref().len() {
            return Err(Error::OutOfRange);
        }

        Ok(&self.0.as_ref()[start..end])
    }
}

/// Adapter for converting mutable, RAM-backed storage into a [`FlashZero`].
///
/// For the purposes of this type, "RAM-backed" means that `AsRef<[u8]>`
/// and `AsMut<[u8]>` are implemented.
///
/// [`FlashZero`]: traits.Flash.html
#[derive(Copy, Clone)]
pub struct RamMut<Bytes>(pub Bytes);

impl<Bytes: AsRef<[u8]> + AsMut<[u8]>> Flash for RamMut<Bytes> {
    fn size(&self) -> Result<u32, Error> {
        self.0
            .as_ref()
            .len()
            .try_into()
            .map_err(|_| Error::Unspecified)
    }

    fn read(&self, offset: Ptr, out: &mut [u8]) -> Result<(), Error> {
        let start = offset.address as usize;
        let end = start.checked_add(out.len()).ok_or(Error::OutOfRange)?;
        if end > self.0.as_ref().len() {
            return Err(Error::OutOfRange);
        }

        out.copy_from_slice(&self.0.as_ref()[start..end]);
        Ok(())
    }

    fn program(&mut self, offset: Ptr, buf: &[u8]) -> Result<(), Error> {
        let start = offset.address as usize;
        let end = start.checked_add(buf.len()).ok_or(Error::OutOfRange)?;
        if end > self.0.as_ref().len() {
            return Err(Error::OutOfRange);
        }

        self.0.as_mut()[start..end].copy_from_slice(buf);
        Ok(())
    }
}

impl<Bytes: AsRef<[u8]> + AsMut<[u8]>> FlashZero for RamMut<Bytes> {
    fn read_zerocopy(&self, offset: Region) -> Result<&[u8], Error> {
        let start = offset.ptr.address as usize;
        let end = start
            .checked_add(offset.len as usize)
            .ok_or(Error::OutOfRange)?;
        if end > self.0.as_ref().len() {
            return Err(Error::OutOfRange);
        }

        Ok(&self.0.as_ref()[start..end])
    }
}

/// A [`Read`]/[`Write`] implementation for operating on a [`Flash`] serially.
///
/// [`Read`]: ../../io/read/trait.Read.html
/// [`Write`]: ../../io/write/trait.Write.html
/// [`Flash`]: trait.Flash.html
#[derive(Copy, Clone)]
pub struct FlashIo<F> {
    flash: F,
    cursor: u32,
    len: u32,
}

impl<F: Flash> FlashIo<F> {
    /// Creates a new `FlashIo`, reading/writing from the beginning of `flash`.
    pub fn new(flash: F) -> Result<Self, Error> {
        let len = flash.size()?;
        Ok(Self {
            flash,
            cursor: 0,
            len,
        })
    }

    /// Skips the cursor `bytes` bytes forward.
    ///
    /// This operation always succeeds, but attempting to read past the end of
    /// flash will always result in an error.
    pub fn skip(&mut self, bytes: usize) {
        self.cursor = self.cursor.saturating_add(bytes as u32);
    }
}

impl<F: Flash> io::Read for FlashIo<F> {
    fn read_bytes(&mut self, out: &mut [u8]) -> Result<(), io::Error> {
        self.flash
            .read(Ptr::new(self.cursor), out)
            .map_err(|_| io::Error::Internal)?;
        self.cursor += out.len() as u32;
        Ok(())
    }

    fn remaining_data(&self) -> usize {
        self.len.saturating_sub(self.cursor) as usize
    }
}

impl<F: Flash> io::Write for FlashIo<F> {
    fn write_bytes(&mut self, buf: &[u8]) -> Result<(), io::Error> {
        self.flash
            .program(Ptr::new(self.cursor), buf)
            .map_err(|_| io::Error::Internal)?;
        self.cursor += buf.len() as u32;
        Ok(())
    }
}

/// An abstract pointer into a [`Flash`] type.
///
/// A `Ptr` needs to be used in conjunction with a [`Flash`]
/// implementation to be read from or written to.
///
/// [`Flash`]: trait.Flash.html
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, AsBytes, FromBytes)]
#[repr(transparent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Ptr {
    /// The abstract address of this pointer.
    pub address: u32,
}

impl Ptr {
    /// Convenience method for creating a `Ptr` without having to use
    /// a struct literal.
    pub const fn new(address: u32) -> Self {
        Self { address }
    }
}

/// A region within  a [`Flash`] type.
///
/// Much like a [`Ptr`], a `Region` needs to be interpreted with
/// respect to a [`Flash`] implementation.
///
/// [`Flash`]: trait.Flash.html
/// [`Ptr`]: struct.Ptr.html
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, AsBytes, FromBytes)]
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Region {
    /// The base pointer for this slice.
    #[cfg_attr(feature = "serde", serde(flatten))]
    pub ptr: Ptr,
    /// The length of the slice, in bytes.
    pub len: u32,
}

impl Region {
    /// Convenience method for creating a `Region` without having to use
    /// a struct literal.
    pub const fn new(ptr: u32, len: u32) -> Self {
        Self {
            ptr: Ptr::new(ptr),
            len,
        }
    }
}
<|endoftext|>


<commit_before>extern crate squirrel;

fn main() {
    let mut vm = squirrel::VM::new();
    vm.func0("hello", || {
        println!("Hello, world!");
    });
    vm.eval("
        ::hello();
    ");
}
<commit_msg>Updated example to test capturing closure called from squirrel.<commit_after>extern crate squirrel;

fn main() {
    let mut vm = squirrel::VM::new();
    let name = "Peter";
    vm.func0("hello", |&:| {
        println!("Hello, {}!", name);
    });
    vm.eval("
        ::hello();
    ");
}
<|endoftext|>


<commit_before>use std;
use base::*;
use super::{LoudsTrie, NodeID, LoudsPos, LinkID, INVALID_LINK_ID};

struct History<'a> {
    trie_: &'a LoudsTrie,
    node_id_: NodeID,
    louds_pos_: LoudsPos,
    link_id_: LinkID,
    key_pos_: u32,
    //key_id_: u32,
}

impl<'a> History<'a> {
    fn new(trie: &'a LoudsTrie, node_id: NodeID, louds_pos: LoudsPos,
           link_id: LinkID, key_pos: u32) -> History<'a> {
        History { trie_: trie, node_id_: node_id, louds_pos_: louds_pos,
                  link_id_: link_id, key_pos_: key_pos }
    }
}

struct State<'a> {
    history_: Vec<History<'a> >,
    key_buf_: Vec<u8>,
}

impl<'a> State<'a> {
    fn new() -> State<'a> {
        State { history_: Vec::new(), key_buf_: Vec::new() }
    }

    fn push<'b>(&mut self, key: &'b[u8], trie: &'a LoudsTrie, node_id: NodeID,
                louds_pos: LoudsPos, link_id: LinkID) {
        self.key_buf_.extend(key);
        assert!(self.key_buf_.len() <= std::u32::MAX as usize);
        self.history_.push(History::new(trie, node_id, louds_pos, link_id,
                                        self.key_buf_.len() as u32));
    }

    fn get_key(&self) -> &[u8] {
        &self.key_buf_[..]
    }

    fn pop(&mut self) -> Option<History<'a> > {
        self.history_.pop()
    }

    fn get_node_id(&self) -> NodeID {
        self.history_.last().unwrap().node_id_
    }

    fn get_link_id(&self) -> LinkID {
        self.history_.last().unwrap().link_id_
    }
}

pub struct Nav<'a> {
    state_: State<'a>,
    trie_: &'a LoudsTrie,
}

// For lookups, marisa does caching based on the input character.
// We can't do that here. May want to remove or rethink the cache
// implementation in light of this.

impl<'a> Nav<'a> {
    pub fn new(trie: &'a LoudsTrie) -> Nav<'a> {
        Nav { state_: State::new(), trie_: trie }
    }

    pub fn has_child(&self) -> bool {
        self.trie_.has_child(self.state_.get_node_id())
    }
    pub fn go_to_child(&mut self) -> bool {
        let init_node_id = self.state_.get_node_id();
        if let Some((node_id, louds_pos)) = self.trie_.child_pos(init_node_id) {
            let mut trie = self.trie_;
            loop {
                if trie.link_flags_.at(node_id.0 as usize) {
                    let (node_id, link_id) =
                        trie.get_linked_ids(node_id.0 as usize);
                    // Proceed either to next trie or tail
                    match &trie.next_trie_ {
                        &Some(ref next_trie) => {
                            trie = &**next_trie;
                            continue;
                        },
                        &None => {
                            // FIXME: Shouldn't need this temporary vector.
                            //        'restore' should return an iterator, and
                            //        state.push should consume it.
                            let mut v = Vec::new();
                            trie.tail_.restore(node_id.0 as usize, &mut v);

                            // Not sure if these values are correct/useful.
                            // If some stuff is only needed for some nodes...
                            // should reflect that in the types we use
                            self.state_.push(&v, trie, node_id, louds_pos,
                                             link_id);
                        }
                    }
                } else {
                    let node_char = [ trie.bases_[node_id.0 as usize] ];
                    self.state_.push(&node_char, trie, node_id, louds_pos,
                                     INVALID_LINK_ID);
                }
                return true;
            }
        }
        false
    }
    pub fn has_sibling(&self) -> bool {
        panic!("not implemented")
    }
    pub fn go_to_sibling(&mut self) -> bool {
        panic!("not implemented")
    }
    pub fn has_parent(&self) -> bool {
        panic!("not implemented")
    }
    pub fn go_to_parent(&self) -> bool {
        panic!("not implemented")
    }
    pub fn is_terminal(&self) -> bool {
        panic!("not implemented")
    }
    pub fn get_string(&self) -> &str {
        panic!("not implemented")
    }
    pub fn is_end(&self) -> bool {
        panic!("not implemented")
    }

}

/*

bool LoudsTrie::lookup(Agent &agent) const {
  MARISA_DEBUG_IF(!agent.has_state(), MARISA_STATE_ERROR);

  State &state = agent.state();
  state.lookup_init();
  while (state.query_pos() < agent.query().length()) {
    if (!find_child(agent)) {
      return false;
    }
  }
  if (!terminal_flags_[state.node_id()]) {
    return false;
  }
  agent.set_key(agent.query().ptr(), agent.query().length());
  agent.set_key(terminal_flags_.rank1(state.node_id()));
  return true;
}

bool LoudsTrie::find_child(Agent &agent) const {
  MARISA_DEBUG_IF(agent.state().query_pos() >= agent.query().length(),
      MARISA_BOUND_ERROR);

  State &state = agent.state();
  const std::size_t cache_id = get_cache_id(state.node_id(),
      agent.query()[state.query_pos()]);
  if (state.node_id() == cache_[cache_id].parent()) {
    if (cache_[cache_id].extra() != MARISA_INVALID_EXTRA) {
      if (!match(agent, cache_[cache_id].link())) {
        return false;
      }
    } else {
      state.set_query_pos(state.query_pos() + 1);
    }
    state.set_node_id(cache_[cache_id].child());
    return true;
  }

  std::size_t louds_pos = louds_.select0(state.node_id()) + 1;
  if (!louds_[louds_pos]) {
    return false;
  }
  state.set_node_id(louds_pos - state.node_id() - 1);
  std::size_t link_id = MARISA_INVALID_LINK_ID;
  do {
    if (link_flags_[state.node_id()]) {
      link_id = update_link_id(link_id, state.node_id());
      const std::size_t prev_query_pos = state.query_pos();
      if (match(agent, get_link(state.node_id(), link_id))) {
        return true;
      } else if (state.query_pos() != prev_query_pos) {
        return false;
      }
    } else if (bases_[state.node_id()] ==
        (UInt8)agent.query()[state.query_pos()]) {
      state.set_query_pos(state.query_pos() + 1);
      return true;
    }
    state.set_node_id(state.node_id() + 1);
    ++louds_pos;
  } while (louds_[louds_pos]);
  return false;
}

std::size_t LoudsTrie::get_cache_id(std::size_t node_id, char label) const {
  return (node_id ^ (node_id << 5) ^ (UInt8)label) & cache_mask_;
}

std::size_t LoudsTrie::get_cache_id(std::size_t node_id) const {
  return node_id & cache_mask_;
}

bool LoudsTrie::match(Agent &agent, std::size_t link) const {
  if (next_trie_.get() != NULL) {
    return next_trie_->match_(agent, link);
  } else {
    return tail_.match(agent, link);
  }
}

bool LoudsTrie::match_(Agent &agent, std::size_t node_id) const {
  MARISA_DEBUG_IF(agent.state().query_pos() >= agent.query().length(),
      MARISA_BOUND_ERROR);
  MARISA_DEBUG_IF(node_id == 0, MARISA_RANGE_ERROR);

  State &state = agent.state();
  for ( ; ; ) {
    const std::size_t cache_id = get_cache_id(node_id);
    if (node_id == cache_[cache_id].child()) {
      if (cache_[cache_id].extra() != MARISA_INVALID_EXTRA) {
        if (!match(agent, cache_[cache_id].link())) {
          return false;
        }
      } else if (cache_[cache_id].label() ==
          agent.query()[state.query_pos()]) {
        state.set_query_pos(state.query_pos() + 1);
      } else {
        return false;
      }

      node_id = cache_[cache_id].parent();
      if (node_id == 0) {
        return true;
      } else if (state.query_pos() >= agent.query().length()) {
        return false;
      }
      continue;
    }

    if (link_flags_[node_id]) {
      if (next_trie_.get() != NULL) {
        if (!match(agent, get_link(node_id))) {
          return false;
        }
      } else if (!tail_.match(agent, get_link(node_id))) {
        return false;
      }
    } else if (bases_[node_id] == (UInt8)agent.query()[state.query_pos()]) {
      state.set_query_pos(state.query_pos() + 1);
    } else {
      return false;
    }

    if (node_id <= num_l1_nodes_) {
      return true;
    } else if (state.query_pos() >= agent.query().length()) {
      return false;
    }
    node_id = louds_.select1(node_id) - node_id - 1;
  }
}

bool Tail::match(Agent &agent, std::size_t offset) const {
  MARISA_DEBUG_IF(buf_.empty(), MARISA_STATE_ERROR);
  MARISA_DEBUG_IF(agent.state().query_pos() >= agent.query().length(),
      MARISA_BOUND_ERROR);

  State &state = agent.state();
  if (end_flags_.empty()) {
    const char * const ptr = &buf_[offset] - state.query_pos();
    do {
      if (ptr[state.query_pos()] != agent.query()[state.query_pos()]) {
        return false;
      }
      state.set_query_pos(state.query_pos() + 1);
      if (ptr[state.query_pos()] == '\0') {
        return true;
      }
    } while (state.query_pos() < agent.query().length());
    return false;
  } else {
    do {
      if (buf_[offset] != agent.query()[state.query_pos()]) {
        return false;
      }
      state.set_query_pos(state.query_pos() + 1);
      if (end_flags_[offset++]) {
        return true;
      }
    } while (state.query_pos() < agent.query().length());
    return false;
  }
}

*/
<commit_msg>has_sibling<commit_after>use std;
use base::*;
use super::{LoudsTrie, NodeID, LoudsPos, LinkID, INVALID_LINK_ID};

struct History<'a> {
    trie_: &'a LoudsTrie,
    node_id_: NodeID,
    louds_pos_: LoudsPos,
    link_id_: LinkID,
    key_pos_: u32,
    //key_id_: u32,
}

impl<'a> History<'a> {
    fn new(trie: &'a LoudsTrie, node_id: NodeID, louds_pos: LoudsPos,
           link_id: LinkID, key_pos: u32) -> History<'a> {
        History { trie_: trie, node_id_: node_id, louds_pos_: louds_pos,
                  link_id_: link_id, key_pos_: key_pos }
    }
}

struct State<'a> {
    history_: Vec<History<'a> >,
    key_buf_: Vec<u8>,
}

impl<'a> State<'a> {
    fn new() -> State<'a> {
        State { history_: Vec::new(), key_buf_: Vec::new() }
    }

    fn push<'b>(&mut self, key: &'b[u8], trie: &'a LoudsTrie, node_id: NodeID,
                louds_pos: LoudsPos, link_id: LinkID) {
        self.key_buf_.extend(key);
        assert!(self.key_buf_.len() <= std::u32::MAX as usize);
        self.history_.push(History::new(trie, node_id, louds_pos, link_id,
                                        self.key_buf_.len() as u32));
    }

    fn get_key(&self) -> &[u8] {
        &self.key_buf_[..]
    }

    fn pop(&mut self) -> Option<History<'a> > {
        self.history_.pop()
    }

    fn get_node_id(&self) -> NodeID {
        self.history_.last().unwrap().node_id_
    }

    fn get_link_id(&self) -> LinkID {
        self.history_.last().unwrap().link_id_
    }
}

pub struct Nav<'a> {
    state_: State<'a>,
    trie_: &'a LoudsTrie,
}

// For lookups, marisa does caching based on the input character.
// We can't do that here. May want to remove or rethink the cache
// implementation in light of this.

impl<'a> Nav<'a> {
    pub fn new(trie: &'a LoudsTrie) -> Nav<'a> {
        Nav { state_: State::new(), trie_: trie }
    }

    pub fn has_child(&self) -> bool {
        self.trie_.has_child(self.state_.get_node_id())
    }
    pub fn go_to_child(&mut self) -> bool {
        let init_node_id = self.state_.get_node_id();
        if let Some((node_id, louds_pos)) = self.trie_.child_pos(init_node_id) {
            let mut trie = self.trie_;
            loop {
                if trie.link_flags_.at(node_id.0 as usize) {
                    let (node_id, link_id) =
                        trie.get_linked_ids(node_id.0 as usize);
                    // Proceed either to next trie or tail
                    match &trie.next_trie_ {
                        &Some(ref next_trie) => {
                            trie = &**next_trie;
                            continue;
                        },
                        &None => {
                            // FIXME: Shouldn't need this temporary vector.
                            //        'restore' should return an iterator, and
                            //        state.push should consume it.
                            let mut v = Vec::new();
                            trie.tail_.restore(node_id.0 as usize, &mut v);

                            // Not sure if these values are correct/useful.
                            // If some stuff is only needed for some nodes...
                            // should reflect that in the types we use
                            self.state_.push(&v, trie, node_id, louds_pos,
                                             link_id);
                        }
                    }
                } else {
                    let node_char = [ trie.bases_[node_id.0 as usize] ];
                    self.state_.push(&node_char, trie, node_id, louds_pos,
                                     INVALID_LINK_ID);
                }
                return true;
            }
        }
        false
    }
    pub fn has_sibling(&self) -> bool {
        // FIXME: Is this all...?
        self.state_.history_.last().map(|h| {
            h.trie_.louds_.at(h.louds_pos_.0 as usize + 1)
        }).unwrap_or(false)
    }
    pub fn go_to_sibling(&mut self) -> bool {
        // pop history and string
        // increase louds_pos and node_id by 1 if we have a sibling
        // get string (factor this out?)
        // push new history & string

        panic!("not implemented")
    }
    pub fn has_parent(&self) -> bool {
        panic!("not implemented")
    }
    pub fn go_to_parent(&self) -> bool {
        panic!("not implemented")
    }
    pub fn is_terminal(&self) -> bool {
        panic!("not implemented")
    }
    pub fn get_string(&self) -> &str {
        panic!("not implemented")
    }
    pub fn is_end(&self) -> bool {
        panic!("not implemented")
    }

}

/*

bool LoudsTrie::lookup(Agent &agent) const {
  MARISA_DEBUG_IF(!agent.has_state(), MARISA_STATE_ERROR);

  State &state = agent.state();
  state.lookup_init();
  while (state.query_pos() < agent.query().length()) {
    if (!find_child(agent)) {
      return false;
    }
  }
  if (!terminal_flags_[state.node_id()]) {
    return false;
  }
  agent.set_key(agent.query().ptr(), agent.query().length());
  agent.set_key(terminal_flags_.rank1(state.node_id()));
  return true;
}

bool LoudsTrie::find_child(Agent &agent) const {
  MARISA_DEBUG_IF(agent.state().query_pos() >= agent.query().length(),
      MARISA_BOUND_ERROR);

  State &state = agent.state();
  const std::size_t cache_id = get_cache_id(state.node_id(),
      agent.query()[state.query_pos()]);
  if (state.node_id() == cache_[cache_id].parent()) {
    if (cache_[cache_id].extra() != MARISA_INVALID_EXTRA) {
      if (!match(agent, cache_[cache_id].link())) {
        return false;
      }
    } else {
      state.set_query_pos(state.query_pos() + 1);
    }
    state.set_node_id(cache_[cache_id].child());
    return true;
  }

  std::size_t louds_pos = louds_.select0(state.node_id()) + 1;
  if (!louds_[louds_pos]) {
    return false;
  }
  state.set_node_id(louds_pos - state.node_id() - 1);
  std::size_t link_id = MARISA_INVALID_LINK_ID;
  do {
    if (link_flags_[state.node_id()]) {
      link_id = update_link_id(link_id, state.node_id());
      const std::size_t prev_query_pos = state.query_pos();
      if (match(agent, get_link(state.node_id(), link_id))) {
        return true;
      } else if (state.query_pos() != prev_query_pos) {
        return false;
      }
    } else if (bases_[state.node_id()] ==
        (UInt8)agent.query()[state.query_pos()]) {
      state.set_query_pos(state.query_pos() + 1);
      return true;
    }
    state.set_node_id(state.node_id() + 1);
    ++louds_pos;
  } while (louds_[louds_pos]);
  return false;
}

std::size_t LoudsTrie::get_cache_id(std::size_t node_id, char label) const {
  return (node_id ^ (node_id << 5) ^ (UInt8)label) & cache_mask_;
}

std::size_t LoudsTrie::get_cache_id(std::size_t node_id) const {
  return node_id & cache_mask_;
}

bool LoudsTrie::match(Agent &agent, std::size_t link) const {
  if (next_trie_.get() != NULL) {
    return next_trie_->match_(agent, link);
  } else {
    return tail_.match(agent, link);
  }
}

bool LoudsTrie::match_(Agent &agent, std::size_t node_id) const {
  MARISA_DEBUG_IF(agent.state().query_pos() >= agent.query().length(),
      MARISA_BOUND_ERROR);
  MARISA_DEBUG_IF(node_id == 0, MARISA_RANGE_ERROR);

  State &state = agent.state();
  for ( ; ; ) {
    const std::size_t cache_id = get_cache_id(node_id);
    if (node_id == cache_[cache_id].child()) {
      if (cache_[cache_id].extra() != MARISA_INVALID_EXTRA) {
        if (!match(agent, cache_[cache_id].link())) {
          return false;
        }
      } else if (cache_[cache_id].label() ==
          agent.query()[state.query_pos()]) {
        state.set_query_pos(state.query_pos() + 1);
      } else {
        return false;
      }

      node_id = cache_[cache_id].parent();
      if (node_id == 0) {
        return true;
      } else if (state.query_pos() >= agent.query().length()) {
        return false;
      }
      continue;
    }

    if (link_flags_[node_id]) {
      if (next_trie_.get() != NULL) {
        if (!match(agent, get_link(node_id))) {
          return false;
        }
      } else if (!tail_.match(agent, get_link(node_id))) {
        return false;
      }
    } else if (bases_[node_id] == (UInt8)agent.query()[state.query_pos()]) {
      state.set_query_pos(state.query_pos() + 1);
    } else {
      return false;
    }

    if (node_id <= num_l1_nodes_) {
      return true;
    } else if (state.query_pos() >= agent.query().length()) {
      return false;
    }
    node_id = louds_.select1(node_id) - node_id - 1;
  }
}

bool Tail::match(Agent &agent, std::size_t offset) const {
  MARISA_DEBUG_IF(buf_.empty(), MARISA_STATE_ERROR);
  MARISA_DEBUG_IF(agent.state().query_pos() >= agent.query().length(),
      MARISA_BOUND_ERROR);

  State &state = agent.state();
  if (end_flags_.empty()) {
    const char * const ptr = &buf_[offset] - state.query_pos();
    do {
      if (ptr[state.query_pos()] != agent.query()[state.query_pos()]) {
        return false;
      }
      state.set_query_pos(state.query_pos() + 1);
      if (ptr[state.query_pos()] == '\0') {
        return true;
      }
    } while (state.query_pos() < agent.query().length());
    return false;
  } else {
    do {
      if (buf_[offset] != agent.query()[state.query_pos()]) {
        return false;
      }
      state.set_query_pos(state.query_pos() + 1);
      if (end_flags_[offset++]) {
        return true;
      }
    } while (state.query_pos() < agent.query().length());
    return false;
  }
}

*/
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::request_manager::RequestManager;
use diem_config::config::{PeerNetworkId, UpstreamConfig};
use netcore::transport::ConnectionOrigin;
use std::{collections::HashMap, time::Duration};

const NUM_CHUNKS_TO_PROCESS: u64 = 50;
const NUM_PICKS_TO_MAKE: u64 = 1000;

#[test]
fn test_request_manager_invalid_chunk() {
    let (mut request_manager, validators) = generate_request_manager_and_test_validators(10, 4);

    // Process multiple invalid chunk responses from validator 0
    for _ in 0..NUM_CHUNKS_TO_PROCESS {
        request_manager.process_invalid_chunk(&validators[0]);
    }

    // Calculate pick counts for the validators
    let pick_counts = calculate_pick_counts_for_validators(&mut request_manager, NUM_PICKS_TO_MAKE);

    // Verify validator 0 is chosen less than the other validators
    let validator_0_count = pick_counts.get(&validators[0]).unwrap_or(&0);
    assert!(validator_0_count < pick_counts.get(&validators[1]).unwrap());
    assert!(validator_0_count < pick_counts.get(&validators[2]).unwrap());
    assert!(validator_0_count < pick_counts.get(&validators[3]).unwrap());
}

#[test]
fn test_remove_requests() {
    let (mut request_manager, validators) = generate_request_manager_and_test_validators(0, 2);

    request_manager.add_request(1, vec![validators[0].clone()]);
    request_manager.add_request(3, vec![validators[1].clone()]);
    request_manager.add_request(5, vec![validators[0].clone()]);
    request_manager.add_request(10, vec![validators[0].clone()]);
    request_manager.add_request(12, vec![validators[1].clone()]);

    request_manager.remove_requests(5);

    assert!(request_manager.get_last_request_time(1).is_none());
    assert!(request_manager.get_last_request_time(3).is_none());
    assert!(request_manager.get_last_request_time(5).is_some());
    assert!(request_manager.get_last_request_time(10).is_some());
    assert!(request_manager.get_last_request_time(12).is_some());
}

#[test]
fn test_request_manager_request_metadata() {
    let (mut request_manager, validators) = generate_request_manager_and_test_validators(0, 2);

    assert!(request_manager.get_first_request_time(1).is_none());

    request_manager.add_request(1, vec![validators[0].clone()]);
    request_manager.check_timeout(1).unwrap();
    request_manager.add_request(1, vec![validators[1].clone()]);
    assert!(request_manager.peer_score(&validators[0]).unwrap() < 99.0);
    assert!(request_manager.peer_score(&validators[1]).unwrap() > 99.0);
    assert!(
        request_manager.get_first_request_time(1).unwrap()
            <= request_manager.get_last_request_time(1).unwrap()
    );
}

/// Picks a peer to send a chunk request to (multiple times) and constructs a pick count
/// for each of the chosen peers.
fn calculate_pick_counts_for_validators(
    request_manager: &mut RequestManager,
    number_of_picks_to_execute: u64,
) -> HashMap<PeerNetworkId, u64> {
    let mut pick_counts = HashMap::new();

    for _ in 0..number_of_picks_to_execute {
        let picked_peers = request_manager.pick_peers();
        assert_eq!(1, picked_peers.len()); // Ensure only one validator per multicast level

        let picked_peer = picked_peers[0].clone();
        let counter = pick_counts.entry(picked_peer).or_insert(0);
        *counter += 1;
    }

    pick_counts
}

/// Generates a new request manager with a specified number of validator peers enabled.
fn generate_request_manager_and_test_validators(
    request_timeout: u64,
    num_validators: u64,
) -> (RequestManager, Vec<PeerNetworkId>) {
    let mut request_manager = RequestManager::new(
        UpstreamConfig::default(),
        Duration::from_secs(request_timeout),
        Duration::from_secs(30),
        HashMap::new(),
    );

    let mut validators = Vec::new();
    for _ in 0..num_validators {
        let validator = PeerNetworkId::random_validator();
        request_manager.enable_peer(validator.clone(), ConnectionOrigin::Outbound);
        validators.push(validator);
    }

    (request_manager, validators)
}
<commit_msg>[State Sync] Further cleanups to request manager unit tests<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::request_manager::RequestManager;
use diem_config::config::{PeerNetworkId, UpstreamConfig};
use netcore::transport::ConnectionOrigin;
use std::{collections::HashMap, time::Duration};

const NUM_CHUNKS_TO_PROCESS: u64 = 50;
const NUM_PICKS_TO_MAKE: u64 = 1000;

#[test]
fn test_invalid_chunk() {
    let (mut request_manager, validators) = generate_request_manager_and_test_validators(10, 4);

    // Process multiple invalid chunk responses from validator 0
    for _ in 0..NUM_CHUNKS_TO_PROCESS {
        request_manager.process_invalid_chunk(&validators[0]);
    }

    // Calculate pick counts for the validators
    let pick_counts = calculate_pick_counts_for_validators(&mut request_manager, NUM_PICKS_TO_MAKE);

    // Verify validator 0 is chosen less often than the other validators
    let validator_0_count = pick_counts.get(&validators[0]).unwrap_or(&0);
    assert!(validator_0_count < pick_counts.get(&validators[1]).unwrap());
    assert!(validator_0_count < pick_counts.get(&validators[2]).unwrap());
    assert!(validator_0_count < pick_counts.get(&validators[3]).unwrap());
}

#[test]
fn test_remove_requests() {
    let (mut request_manager, validators) = generate_request_manager_and_test_validators(0, 2);

    let validator_0 = vec![validators[0].clone()];
    let validator_1 = vec![validators[1].clone()];

    // Add version requests to request manager
    request_manager.add_request(1, validator_0.clone());
    request_manager.add_request(3, validator_1.clone());
    request_manager.add_request(5, validator_0.clone());
    request_manager.add_request(10, validator_0);
    request_manager.add_request(12, validator_1);

    // Remove all request versions below 5
    request_manager.remove_requests(5);

    // Verify versions updated correctly
    assert!(request_manager.get_last_request_time(1).is_none());
    assert!(request_manager.get_last_request_time(3).is_none());
    assert!(request_manager.get_last_request_time(5).is_some());
    assert!(request_manager.get_last_request_time(10).is_some());
    assert!(request_manager.get_last_request_time(12).is_some());
}

#[test]
fn test_request_metadata() {
    let (mut request_manager, validators) = generate_request_manager_and_test_validators(0, 2);

    let validator_0 = validators[0].clone();
    let validator_1 = validators[1].clone();

    // Verify first request time doesn't exist for missing request
    assert!(request_manager.get_first_request_time(1).is_none());

    // Add versions requests to request manager
    request_manager.add_request(1, vec![validator_0.clone()]);
    request_manager.check_timeout(1).unwrap();
    request_manager.add_request(1, vec![validator_1.clone()]);

    // Verify scores are affected by request timeouts and that request metadata is updated
    assert!(request_manager.peer_score(&validator_0).unwrap() < 99.0);
    assert!(request_manager.peer_score(&validator_1).unwrap() > 99.0);
    assert!(
        request_manager.get_first_request_time(1).unwrap()
            <= request_manager.get_last_request_time(1).unwrap()
    );
}

/// Picks a peer to send a chunk request to (multiple times) and constructs a pick count
/// for each of the chosen peers.
fn calculate_pick_counts_for_validators(
    request_manager: &mut RequestManager,
    number_of_picks_to_execute: u64,
) -> HashMap<PeerNetworkId, u64> {
    let mut pick_counts = HashMap::new();

    for _ in 0..number_of_picks_to_execute {
        let picked_peers = request_manager.pick_peers();
        assert_eq!(1, picked_peers.len()); // Ensure only one validator per multicast level

        let picked_peer = picked_peers[0].clone();
        let counter = pick_counts.entry(picked_peer).or_insert(0);
        *counter += 1;
    }

    pick_counts
}

/// Generates a new request manager with a specified number of validator peers enabled.
fn generate_request_manager_and_test_validators(
    request_timeout: u64,
    num_validators: u64,
) -> (RequestManager, Vec<PeerNetworkId>) {
    let mut request_manager = RequestManager::new(
        UpstreamConfig::default(),
        Duration::from_secs(request_timeout),
        Duration::from_secs(30),
        HashMap::new(),
    );

    let mut validators = Vec::new();
    for _ in 0..num_validators {
        let validator = PeerNetworkId::random_validator();
        request_manager.enable_peer(validator.clone(), ConnectionOrigin::Outbound);
        validators.push(validator);
    }

    (request_manager, validators)
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use parking_lot::{RwLock, Mutex};
use threadpool::ThreadPool;
use num_cpus;
use bifrost_hasher::{hash_str, hash_bytes};
use raft::{RaftService, IS_LEADER};
use rpc;
use utils::bincode;
use serde;
use super::super::{OpType};
use super::super::super::RaftMsg;
use super::*;

lazy_static! {
    pub static ref THREAD_POOL: Mutex<ThreadPool> = Mutex::new(ThreadPool::new(num_cpus::get()));
}

pub struct Subscriber {
    pub session_id: u64,
    pub client: Arc<SyncServiceClient>
}

pub struct Subscriptions {
    next_id: u64,
    subscribers: HashMap<u64, Subscriber>,
    suber_subs: HashMap<u64, HashSet<u64>>, //suber_id -> sub_id
    subscriptions: HashMap<SubKey, HashSet<u64>>, // key -> sub_id
    sub_suber: HashMap<u64, u64>,
    sub_to_key: HashMap<u64, SubKey>, //sub_id -> sub_key
}

impl Subscriptions {

    pub fn new() -> Subscriptions {
        Subscriptions {
            next_id: 0,
            subscribers: HashMap::new(),
            suber_subs: HashMap::new(),
            subscriptions: HashMap::new(),
            sub_suber: HashMap::new(),
            sub_to_key: HashMap::new(),
        }
    }

    pub fn subscribe(&mut self, key: SubKey, address: &String, session_id: u64) -> Result<u64, ()> {
        let sub_service_id = DEFAULT_SERVICE_ID;
        let suber_id = hash_str(address);
        let suber_exists = self.subscribers.contains_key(&suber_id);
        let sub_id = self.next_id;
        let require_reload_suber = if suber_exists {
            let session_match = self.subscribers.get(&suber_id).unwrap().session_id == session_id;
            if !session_match {
                self.remove_subscriber(suber_id);
                true
            } else {false}
        } else {true};
        if !self.subscribers.contains_key(&suber_id) {
            self.subscribers.insert(suber_id, Subscriber {
                session_id: session_id,
                client: {
                    if let Ok(client) = rpc::DEFAULT_CLIENT_POOL.get(address) {
                        SyncServiceClient::new(sub_service_id, &client)
                    } else {
                        return Err(());
                    }
                }
            });
        }
        self.suber_subs.entry(suber_id).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.subscriptions.entry(key).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.sub_to_key.insert(sub_id, key);
        self.sub_suber.insert(sub_id, suber_id);

        self.next_id += 1;
        Ok(sub_id)
    }

    pub fn remove_subscriber(&mut self, suber_id: u64) {
        let suber_subs = if let Some(sub_ids) = self.suber_subs.get(&suber_id) {
            sub_ids.iter().cloned().collect()
        } else {Vec::<u64>::new()};
        for subs_id in suber_subs {
            self.remove_subscription(subs_id)
        }
        self.subscribers.remove(&suber_id);
        self.suber_subs.remove(&suber_id);
    }

    pub fn remove_subscription(&mut self, id: u64) {
        let sub_key = self.sub_to_key.remove(&id);
        if let Some(sub_key) = sub_key {
            if let Some(ref mut sub_subers) = self.subscriptions.get_mut(&sub_key) {
                sub_subers.remove(&id);
                self.sub_suber.remove(&id);
            }
        }
    }
}

pub struct SMCallback {
    pub subscriptions: Arc<RwLock<Subscriptions>>,
    pub raft_service: Arc<RaftService>,
    pub sm_id: u64,
}

impl SMCallback {
    pub fn new(state_machine_id: u64, raft_service: Arc<RaftService>) -> SMCallback {
        let meta = raft_service.meta.read();
        let sm = meta.state_machine.read();
        let subs = sm.configs.subscriptions.clone();
        SMCallback {
            subscriptions: subs,
            raft_service: raft_service.clone(),
            sm_id: state_machine_id,
        }
    }
    pub fn notify<R>(&self, func: &RaftMsg<R>, data: R)
    where R: serde::Serialize + Send + Sync {
        if !IS_LEADER.get() {return;}
        let (fn_id, op_type, pattern_data) = func.encode();
        match op_type {
            OpType::SUBSCRIBE => {
                let pattern_id = hash_bytes(&pattern_data.as_slice());
                let raft_sid = self.raft_service.options.service_id;
                let sm_id = self.sm_id;
                let key = (raft_sid, sm_id, fn_id, pattern_id);
                let svr_subs = self.subscriptions.read();
                if let Some(sub_ids) = svr_subs.subscriptions.get(&key) {
                    let data = bincode::serialize(&data);
                    for sub_id in sub_ids {
                        if let Some(subscriber_id) = svr_subs.sub_suber.get(&sub_id) {
                            if let Some(subscriber) = svr_subs.subscribers.get(&subscriber_id) {
                                let data = data.clone();
                                let client = subscriber.client.clone();
                                THREAD_POOL.lock().execute(move || {
                                    client.notify(&key, &data);
                                });
                            }
                        }
                    }
                }
            },
            _ => {
                panic!("Cannot notify on {:?}")
            }
        }
    }
}

pub fn notify<R, F>(callback: &Option<SMCallback>, func: &RaftMsg<R>, data: F)
    where F: Fn() -> R,
          R: serde::Serialize + Send + Sync {
    if let Some(ref callback) = *callback {
        callback.notify(func, data());
    }
}<commit_msg>response with error on notify<commit_after>use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use parking_lot::{RwLock, Mutex};
use threadpool::ThreadPool;
use num_cpus;
use bifrost_hasher::{hash_str, hash_bytes};
use raft::{RaftService, IS_LEADER};
use rpc;
use utils::bincode;
use serde;
use super::super::{OpType};
use super::super::super::RaftMsg;
use super::*;

lazy_static! {
    pub static ref THREAD_POOL: Mutex<ThreadPool> = Mutex::new(ThreadPool::new(num_cpus::get()));
}

pub struct Subscriber {
    pub session_id: u64,
    pub client: Arc<SyncServiceClient>
}

pub struct Subscriptions {
    next_id: u64,
    subscribers: HashMap<u64, Subscriber>,
    suber_subs: HashMap<u64, HashSet<u64>>, //suber_id -> sub_id
    subscriptions: HashMap<SubKey, HashSet<u64>>, // key -> sub_id
    sub_suber: HashMap<u64, u64>,
    sub_to_key: HashMap<u64, SubKey>, //sub_id -> sub_key
}

impl Subscriptions {

    pub fn new() -> Subscriptions {
        Subscriptions {
            next_id: 0,
            subscribers: HashMap::new(),
            suber_subs: HashMap::new(),
            subscriptions: HashMap::new(),
            sub_suber: HashMap::new(),
            sub_to_key: HashMap::new(),
        }
    }

    pub fn subscribe(&mut self, key: SubKey, address: &String, session_id: u64) -> Result<u64, ()> {
        let sub_service_id = DEFAULT_SERVICE_ID;
        let suber_id = hash_str(address);
        let suber_exists = self.subscribers.contains_key(&suber_id);
        let sub_id = self.next_id;
        let require_reload_suber = if suber_exists {
            let session_match = self.subscribers.get(&suber_id).unwrap().session_id == session_id;
            if !session_match {
                self.remove_subscriber(suber_id);
                true
            } else {false}
        } else {true};
        if !self.subscribers.contains_key(&suber_id) {
            self.subscribers.insert(suber_id, Subscriber {
                session_id: session_id,
                client: {
                    if let Ok(client) = rpc::DEFAULT_CLIENT_POOL.get(address) {
                        SyncServiceClient::new(sub_service_id, &client)
                    } else {
                        return Err(());
                    }
                }
            });
        }
        self.suber_subs.entry(suber_id).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.subscriptions.entry(key).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.sub_to_key.insert(sub_id, key);
        self.sub_suber.insert(sub_id, suber_id);

        self.next_id += 1;
        Ok(sub_id)
    }

    pub fn remove_subscriber(&mut self, suber_id: u64) {
        let suber_subs = if let Some(sub_ids) = self.suber_subs.get(&suber_id) {
            sub_ids.iter().cloned().collect()
        } else {Vec::<u64>::new()};
        for subs_id in suber_subs {
            self.remove_subscription(subs_id)
        }
        self.subscribers.remove(&suber_id);
        self.suber_subs.remove(&suber_id);
    }

    pub fn remove_subscription(&mut self, id: u64) {
        let sub_key = self.sub_to_key.remove(&id);
        if let Some(sub_key) = sub_key {
            if let Some(ref mut sub_subers) = self.subscriptions.get_mut(&sub_key) {
                sub_subers.remove(&id);
                self.sub_suber.remove(&id);
            }
        }
    }
}

pub struct SMCallback {
    pub subscriptions: Arc<RwLock<Subscriptions>>,
    pub raft_service: Arc<RaftService>,
    pub sm_id: u64,
}

pub enum NotifyFailure {
    IsNotLeader,
    OpTypeNotSubscribe,
    CannotFindSubscription
}

impl SMCallback {
    pub fn new(state_machine_id: u64, raft_service: Arc<RaftService>) -> SMCallback {
        let meta = raft_service.meta.read();
        let sm = meta.state_machine.read();
        let subs = sm.configs.subscriptions.clone();
        SMCallback {
            subscriptions: subs,
            raft_service: raft_service.clone(),
            sm_id: state_machine_id,
        }
    }
    pub fn notify<R>(&self, func: &RaftMsg<R>, data: R) -> Result<(), NotifyFailure>
    where R: serde::Serialize + Send + Sync {
        if !IS_LEADER.get() {return Err(NotifyFailure::IsNotLeader);}
        let (fn_id, op_type, pattern_data) = func.encode();
        match op_type {
            OpType::SUBSCRIBE => {
                let pattern_id = hash_bytes(&pattern_data.as_slice());
                let raft_sid = self.raft_service.options.service_id;
                let sm_id = self.sm_id;
                let key = (raft_sid, sm_id, fn_id, pattern_id);
                let svr_subs = self.subscriptions.read();
                if let Some(sub_ids) = svr_subs.subscriptions.get(&key) {
                    let data = bincode::serialize(&data);
                    for sub_id in sub_ids {
                        if let Some(subscriber_id) = svr_subs.sub_suber.get(&sub_id) {
                            if let Some(subscriber) = svr_subs.subscribers.get(&subscriber_id) {
                                let data = data.clone();
                                let client = subscriber.client.clone();
                                THREAD_POOL.lock().execute(move || {
                                    client.notify(&key, &data);
                                });
                            }
                        }
                    }
                } else {
                    return Err(NotifyFailure::CannotFindSubscription)
                }
            },
            _ => {
                return Err(NotifyFailure::OpTypeNotSubscribe)
            }
        }
        return Ok(());
    }
}

pub fn notify<R, F>(callback: &Option<SMCallback>, func: &RaftMsg<R>, data: F)
    where F: Fn() -> R,
          R: serde::Serialize + Send + Sync {
    if let Some(ref callback) = *callback {
        callback.notify(func, data());
    }
}<|endoftext|>