<commit_before>//***********************************************************************
//  Copyright 2006 John A. Trangenstein
//
//  This software is made available for research and instructional use
//  only.e available for research and instructional use
//  only.
//  You may copy and use this software without charge for these
//  non-commercial purposes, provided that the copyright notice and
//  associated text is reproduced on all copies.
//  For all other uses (including distribution of modified versions),
//  please contact the author at
//    John A. Trangenstein
//    Department of Mathematics
//    Duke University
//    Durham, NC 27708-0320
//    USA
//  or
//    johnt@math.duke.edu
//
//  This software is made available "as is" without any assurance that it
//  is completely correct, or that it will work for your purposes.
//  Use the software at your own risk.
//***********************************************************************

// Permission to publish the translation of the code
// was graciously granted by Prof. John A. Trangenstein

// The MIT License (MIT)
//
// Copyright (c) 2015 Alexander Samoilov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#![feature(duration_span)]

extern crate argparse;

use std::time::Duration;
use std::cmp;
use std::process::exit;
use argparse::{ArgumentParser, StoreTrue, Store};

struct Options {
    verbose: bool,
    num_steps: usize,
    num_cells: usize,
    num_runs: usize,
}

fn do_computation(nsteps: usize, ncells: usize, tmax: f64, ifirst: usize, ilast: usize,
                  statelft: f64, statergt: f64, velocity: f64, dt: f64,
                  fc: usize, lc: usize, x: &Vec<f64>, u: &mut Vec<f64>)
{
    let mut istep   =   0;
    let mut t       =   0.0f64;
    let mut flux    =   vec![0.0f64; x.len()];

    // loop over timesteps
    while istep < nsteps && t < tmax {

        // right boundary condition: outgoing wave
        for ic in ncells .. lc {
            u[ic]=u[ncells-1];
        }
        // left boundary condition: specified value
        for ic in 0 .. fc {
            u[ic]=statelft;
        }

        // upwind fluxes times dt (ie, flux time integral over cell side)
        // assumes velocity > 0
        let vdt=velocity*dt;
        for ie in ifirst .. ilast+1 {
            flux[ie]=vdt*u[ie-1];
        }

        // conservative difference
        for ic in ifirst .. ilast {
            u[ic] -= (flux[ic+1]-flux[ic]) / (x[ic+1]-x[ic])
        }

        // update time and step number
        t       +=  dt;
        istep   +=  1
    }
}

fn main() {
    let mut options = Options {
        verbose:   false,
        num_steps: 2000,
        num_cells: 2000,
        num_runs:  10,
    };

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Time elapsing of model PDE for scalar conservation law.");
        ap.refer(&mut options.verbose)
            .add_option(&["-v", "--verbose"], StoreTrue,
            "set verbose");
        ap.refer(&mut options.num_steps)
            .add_option(&["-t", "--num_steps"], Store,
            "set number of time steps");
        ap.refer(&mut options.num_cells)
            .add_option(&["-n", "--num_cells"], Store,
            "set number of grid cells");
        ap.refer(&mut options.num_runs)
            .add_option(&["-b", "--num_runs"], Store,
            "set number of runs");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }

    if options.verbose {
        println!("number of time steps : {} number of grid cells : {} number of runs : {}",
                 options.num_steps, options.num_cells, options.num_runs);
    }

    // problem-specific parameters:
    const jump     : f64   =  0.0f64;
    const x_left   : f64   = -0.2f64;
    const x_right  : f64   =  1.0f64;
    const statelft : f64   =  2.0f64;
    const statergt : f64   =  0.0f64;
    const velocity : f64   =  1.0f64;

    const tmax     : f64   =  0.8f64;
    const cfl      : f64   =  0.9f64;

    // array bounds:
    let   nsteps           = options.num_steps;
    let   ncells           = options.num_cells;
    const fc       : usize = 2;
    let   lc               = ncells+1;
    const ifirst   : usize = 1;
    let   ilast            = ncells-1;

    // work arrays
    // #   double precision
    // #  &  u(-2:ncells+1),
    // #  &  x(0:ncells),
    // #  &  flux(0:ncells)

    let mut u    = vec![0.0f64; ncells+4];
    let mut x    = vec![0.0f64; ncells+1];

    //  uniform mesh:
    let dx = (x_right-x_left) / ncells as f64;
    for ie in ifirst .. ilast+1 {
        x[ie] = x_left + ie as f64 * dx;
    }

    // initial values for diffential equation:
    let ijump = cmp::max(ifirst as isize -1,
                         cmp::min((ncells as f64 * (jump-x_left)/(x_right-x_left) + 0.5) as isize,
                                  (ilast+1) as isize)) as usize;
    if options.verbose {
        println!("ijump : {}", ijump);
    }

    // stable timestep (independent of time for linear advection):
    let mut mindx = std::f64::MAX;
    for ic in ifirst .. ilast {
        mindx = mindx.min(x[ic+2]-x[ic+1]);
    }
    let dt = cfl*mindx/velocity.abs();

    let d = Duration::span(||{
        for r in 0..options.num_runs {
            if options.verbose {
                println!("run number : {}", r);
            }

            // left state to left of jump
            for ic in ifirst .. ijump-1 {
                u[ic+3] = statelft;
            }

            // volume-weighted average in cell containing jump
            let frac = (jump-x_left-ijump as f64 *dx)/(x_right-x_left);
            u[ijump+3] = statelft*frac+statergt*(1.0f64-frac);

            // right state to right of jump
            for ic in ijump+1 .. ilast {
                u[ic+3]=statergt;
            }

            do_computation(nsteps, ncells, tmax, ifirst, ilast,
                           statelft, statergt, velocity, dt, fc, lc, &x, &mut u);
        }
    });
    println!("elapsed time: {}", d.as_secs() as f64 + d.subsec_nanos() as f64 / 1.0e9f64);
}
<commit_msg>use `windows(2)` and `fold` to find `min` dx.<commit_after>//***********************************************************************
//  Copyright 2006 John A. Trangenstein
//
//  This software is made available for research and instructional use
//  only.e available for research and instructional use
//  only.
//  You may copy and use this software without charge for these
//  non-commercial purposes, provided that the copyright notice and
//  associated text is reproduced on all copies.
//  For all other uses (including distribution of modified versions),
//  please contact the author at
//    John A. Trangenstein
//    Department of Mathematics
//    Duke University
//    Durham, NC 27708-0320
//    USA
//  or
//    johnt@math.duke.edu
//
//  This software is made available "as is" without any assurance that it
//  is completely correct, or that it will work for your purposes.
//  Use the software at your own risk.
//***********************************************************************

// Permission to publish the translation of the code
// was graciously granted by Prof. John A. Trangenstein

// The MIT License (MIT)
//
// Copyright (c) 2015 Alexander Samoilov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#![feature(duration_span)]

extern crate argparse;

use std::time::Duration;
use std::cmp;
use std::process::exit;
use argparse::{ArgumentParser, StoreTrue, Store};

struct Options {
    verbose: bool,
    num_steps: usize,
    num_cells: usize,
    num_runs: usize,
}

fn do_computation(nsteps: usize, ncells: usize, tmax: f64, ifirst: usize, ilast: usize,
                  statelft: f64, statergt: f64, velocity: f64, dt: f64,
                  fc: usize, lc: usize, x: &Vec<f64>, u: &mut Vec<f64>)
{
    let mut istep   =   0;
    let mut t       =   0.0f64;
    let mut flux    =   vec![0.0f64; x.len()];

    // loop over timesteps
    while istep < nsteps && t < tmax {

        // right boundary condition: outgoing wave
        for ic in ncells .. lc {
            u[ic]=u[ncells-1];
        }
        // left boundary condition: specified value
        for ic in 0 .. fc {
            u[ic]=statelft;
        }

        // upwind fluxes times dt (ie, flux time integral over cell side)
        // assumes velocity > 0
        let vdt=velocity*dt;
        for ie in ifirst .. ilast+1 {
            flux[ie]=vdt*u[ie-1];
        }

        // conservative difference
        for ic in ifirst .. ilast {
            u[ic] -= (flux[ic+1]-flux[ic]) / (x[ic+1]-x[ic])
        }

        // update time and step number
        t       +=  dt;
        istep   +=  1
    }
}

fn main() {
    let mut options = Options {
        verbose:   false,
        num_steps: 2000,
        num_cells: 2000,
        num_runs:  10,
    };

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Time elapsing of model PDE for scalar conservation law.");
        ap.refer(&mut options.verbose)
            .add_option(&["-v", "--verbose"], StoreTrue,
            "set verbose");
        ap.refer(&mut options.num_steps)
            .add_option(&["-t", "--num_steps"], Store,
            "set number of time steps");
        ap.refer(&mut options.num_cells)
            .add_option(&["-n", "--num_cells"], Store,
            "set number of grid cells");
        ap.refer(&mut options.num_runs)
            .add_option(&["-b", "--num_runs"], Store,
            "set number of runs");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }

    if options.verbose {
        println!("number of time steps : {} number of grid cells : {} number of runs : {}",
                 options.num_steps, options.num_cells, options.num_runs);
    }

    // problem-specific parameters:
    const jump     : f64   =  0.0f64;
    const x_left   : f64   = -0.2f64;
    const x_right  : f64   =  1.0f64;
    const statelft : f64   =  2.0f64;
    const statergt : f64   =  0.0f64;
    const velocity : f64   =  1.0f64;

    const tmax     : f64   =  0.8f64;
    const cfl      : f64   =  0.9f64;

    // array bounds:
    let   nsteps           = options.num_steps;
    let   ncells           = options.num_cells;
    const fc       : usize = 2;
    let   lc               = ncells+1;
    const ifirst   : usize = 1;
    let   ilast            = ncells-1;

    // work arrays
    // #   double precision
    // #  &  u(-2:ncells+1),
    // #  &  x(0:ncells),
    // #  &  flux(0:ncells)

    let mut u    = vec![0.0f64; ncells+4];
    let mut x    = vec![0.0f64; ncells+1];

    //  uniform mesh:
    let dx = (x_right-x_left) / ncells as f64;
    for ie in ifirst .. ilast+1 {
        x[ie] = x_left + ie as f64 * dx;
    }

    // initial values for diffential equation:
    let ijump = cmp::max(ifirst as isize -1,
                         cmp::min((ncells as f64 * (jump-x_left)/(x_right-x_left) + 0.5) as isize,
                                  (ilast+1) as isize)) as usize;
    if options.verbose {
        println!("ijump : {}", ijump);
    }

    // stable timestep (independent of time for linear advection):
    // https://doc.rust-lang.org/std/primitive.slice.html#method.windows
    let min_dx = x.windows(2) // iterator for adjacent pairs of a slice
                  .map(|w| w[1]-w[0]) // i.e. [x[0], x[1]], [x[1], x[2]] ...
                  .fold(std::f64::MAX, |x1, x2| x1.min(x2)); // `fold` to find `min`

    let dt = cfl*min_dx/velocity.abs();

    let d = Duration::span(||{
        for r in 0..options.num_runs {
            if options.verbose {
                println!("run number : {}", r);
            }

            // left state to left of jump
            for ic in ifirst .. ijump-1 {
                u[ic+3] = statelft;
            }

            // volume-weighted average in cell containing jump
            let frac = (jump-x_left-ijump as f64 *dx)/(x_right-x_left);
            u[ijump+3] = statelft*frac+statergt*(1.0f64-frac);

            // right state to right of jump
            for ic in ijump+1 .. ilast {
                u[ic+3]=statergt;
            }

            do_computation(nsteps, ncells, tmax, ifirst, ilast,
                           statelft, statergt, velocity, dt, fc, lc, &x, &mut u);
        }
    });
    println!("elapsed time: {}", d.as_secs() as f64 + d.subsec_nanos() as f64 / 1.0e9f64);
}
<|endoftext|>


<commit_before>//! TODO Fill in

use render;
use gdk_pixbuf::Pixbuf;
use glib::translate::ToGlibPtr;
use std::fmt::{self, Display, Formatter};
use std::default::Default;
use std::rc::Rc;
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use super::object::{Object, Objectable};
use super::class::{self, Class, ClassBuilder};
use super::{GLOBAL_SIGNALS, signal};

#[derive(Clone, Debug)]
pub struct AwesomeState {
    // TODO Fill in
    dummy: i32
}

pub struct Awesome<'lua>(Table<'lua>);

// TODO Not an object, remove this! It's a global
impl_objectable!(Awesome, AwesomeState);

impl Default for AwesomeState {
    fn default() -> Self {
        AwesomeState {
            dummy: 0
        }
    }
}

impl <'lua> Awesome<'lua> {
    fn new(lua: &Lua) -> rlua::Result<Object> {
        // TODO FIXME
        let class = class::button_class(lua)?;
        Ok(Awesome::allocate(lua, class)?.build())
    }
}

impl Display for AwesomeState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Awesome: {:p}", self)
    }
}

impl <'lua> ToLua<'lua> for Awesome<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl UserData for AwesomeState {}

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    property_setup(lua, method_setup(lua, Class::builder(lua, Some(Rc::new(Awesome::new)), None, None)?)?)?
        .save_class("awesome")?
        .build()
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Fill in rest
    builder.method("connect_signal".into(), lua.create_function(connect_signal))?
           .method("register_xproperty".into(), lua.create_function(register_xproperty))?
           .method("xkb_get_group_names".into(), lua.create_function(xkb_get_group_names))?
           .method("restart".into(), lua.create_function(restart))?
           .method("load_image".into(), lua.create_function(load_image))?
           .method("quit".into(), lua.create_function(quit))
}

fn connect_signal<'lua>(lua: &'lua Lua, (name, func): (String, rlua::Function<'lua>))
                        -> rlua::Result<()> {
    let global_signals = lua.globals().get::<_, Table>(GLOBAL_SIGNALS)?;
    let fake_object = lua.create_table();
    fake_object.set("signals", global_signals)?;
    signal::connect_signal(lua, fake_object.into(), name, &[func])
}

/// Registers a new X property
/// This actually does nothing, since this is Wayland.
fn register_xproperty<'lua>(_: &'lua Lua, _: Value<'lua>) -> rlua::Result<()> {
    warn!("register_xproperty not supported");
    Ok(())
}

/// Get layout short names
fn xkb_get_group_names<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<()> {
    warn!("xkb_get_group_names not supported");
    Ok(())
}

/// Restart Awesome by restarting the Lua thread
fn restart<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<()> {
    use lua::{self, LuaQuery};
    if let Err(err) = lua::send(LuaQuery::Restart) {
        warn!("Could not restart Lua thread {:#?}", err);
    }
    Ok(())
}

/// Load an image from the given path
/// Returns either a cairo surface as light user data, nil and an error message
fn load_image<'lua>(lua: &'lua Lua, file_path: String) -> rlua::Result<Value<'lua>> {
    let pixbuf = Pixbuf::new_from_file(file_path.as_str())
        .map_err(|err| rlua::Error::RuntimeError(format!("{}", err)))?;
    let surface = render::load_surface_from_pixbuf(pixbuf);
    // UGH, I wanted to do to_glib_full, but that isn't defined apparently
    // So now I have to ignore the lifetime completely and just forget about the surface.
    let surface_ptr = surface.to_glib_none().0;
    ::std::mem::forget(surface);
    rlua::LightUserData(surface_ptr as _).to_lua(lua)
}

fn quit<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<()> {
    ::rustwlc::terminate();
    Ok(())
}

fn property_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    builder.dummy_property("version".into(), "0".to_lua(lua)?)?
           .dummy_property("themes_path".into(), "/usr/share/awesome/themes".to_lua(lua)?)?
           .dummy_property("conffile".into(), "".to_lua(lua)?)
}
<commit_msg>Implemented awesome.{disconnect,emit}_signal<commit_after>//! TODO Fill in

use render;
use gdk_pixbuf::Pixbuf;
use glib::translate::ToGlibPtr;
use std::fmt::{self, Display, Formatter};
use std::default::Default;
use std::rc::Rc;
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use super::object::{Object, Objectable};
use super::class::{self, Class, ClassBuilder};
use super::{GLOBAL_SIGNALS, signal};

#[derive(Clone, Debug)]
pub struct AwesomeState {
    // TODO Fill in
    dummy: i32
}

pub struct Awesome<'lua>(Table<'lua>);

// TODO Not an object, remove this! It's a global
impl_objectable!(Awesome, AwesomeState);

impl Default for AwesomeState {
    fn default() -> Self {
        AwesomeState {
            dummy: 0
        }
    }
}

impl <'lua> Awesome<'lua> {
    fn new(lua: &Lua) -> rlua::Result<Object> {
        // TODO FIXME
        let class = class::button_class(lua)?;
        Ok(Awesome::allocate(lua, class)?.build())
    }
}

impl Display for AwesomeState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Awesome: {:p}", self)
    }
}

impl <'lua> ToLua<'lua> for Awesome<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl UserData for AwesomeState {}

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    property_setup(lua, method_setup(lua, Class::builder(lua, Some(Rc::new(Awesome::new)), None, None)?)?)?
        .save_class("awesome")?
        .build()
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Fill in rest
    builder.method("connect_signal".into(), lua.create_function(connect_signal))?
           .method("disconnect_signal".into(), lua.create_function(disconnect_signal))?
           .method("emit_signal".into(), lua.create_function(emit_signal))?
           .method("register_xproperty".into(), lua.create_function(register_xproperty))?
           .method("xkb_get_group_names".into(), lua.create_function(xkb_get_group_names))?
           .method("restart".into(), lua.create_function(restart))?
           .method("load_image".into(), lua.create_function(load_image))?
           .method("quit".into(), lua.create_function(quit))
}

fn connect_signal<'lua>(lua: &'lua Lua, (name, func): (String, rlua::Function<'lua>))
                        -> rlua::Result<()> {
    let global_signals = lua.globals().get::<_, Table>(GLOBAL_SIGNALS)?;
    let fake_object = lua.create_table();
    fake_object.set("signals", global_signals)?;
    signal::connect_signal(lua, fake_object.into(), name, &[func])
}

fn disconnect_signal<'lua>(lua: &'lua Lua, name: String) -> rlua::Result<()> {
    let global_signals = lua.globals().get::<_, Table>(GLOBAL_SIGNALS)?;
    let fake_object = lua.create_table();
    fake_object.set("signals", global_signals)?;
    signal::disconnect_signal(lua, fake_object.into(), name)
}

fn emit_signal<'lua>(lua: &'lua Lua, (name, args): (String, Value))
                     -> rlua::Result<()> {
    let global_signals = lua.globals().get::<_, Table>(GLOBAL_SIGNALS)?;
    let fake_object = lua.create_table();
    fake_object.set("signals", global_signals)?;
    signal::emit_signal(lua, fake_object.into(), name, args)
}

/// Registers a new X property
/// This actually does nothing, since this is Wayland.
fn register_xproperty<'lua>(_: &'lua Lua, _: Value<'lua>) -> rlua::Result<()> {
    warn!("register_xproperty not supported");
    Ok(())
}

/// Get layout short names
fn xkb_get_group_names<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<()> {
    warn!("xkb_get_group_names not supported");
    Ok(())
}

/// Restart Awesome by restarting the Lua thread
fn restart<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<()> {
    use lua::{self, LuaQuery};
    if let Err(err) = lua::send(LuaQuery::Restart) {
        warn!("Could not restart Lua thread {:#?}", err);
    }
    Ok(())
}

/// Load an image from the given path
/// Returns either a cairo surface as light user data, nil and an error message
fn load_image<'lua>(lua: &'lua Lua, file_path: String) -> rlua::Result<Value<'lua>> {
    let pixbuf = Pixbuf::new_from_file(file_path.as_str())
        .map_err(|err| rlua::Error::RuntimeError(format!("{}", err)))?;
    let surface = render::load_surface_from_pixbuf(pixbuf);
    // UGH, I wanted to do to_glib_full, but that isn't defined apparently
    // So now I have to ignore the lifetime completely and just forget about the surface.
    let surface_ptr = surface.to_glib_none().0;
    ::std::mem::forget(surface);
    rlua::LightUserData(surface_ptr as _).to_lua(lua)
}

fn quit<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<()> {
    ::rustwlc::terminate();
    Ok(())
}

fn property_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    builder.dummy_property("version".into(), "0".to_lua(lua)?)?
           .dummy_property("themes_path".into(), "/usr/share/awesome/themes".to_lua(lua)?)?
           .dummy_property("conffile".into(), "".to_lua(lua)?)
}
<|endoftext|>


<commit_before>extern crate gio;
extern crate glib;
extern crate gtk;

use std::cell::RefCell;
use std::rc::Rc;

use gio::prelude::*;
use glib::clone;
use gtk::{prelude::*, Application, ApplicationWindow, Button};

#[derive(Default)]
struct State {
    started: bool,
    count: i32,
}

impl State {
    fn new() -> Self {
        Self {
            started: false,
            count: 0,
        }
    }
}

fn main() {
    let application =
        Application::new(Some("com.github.gtk-rs.examples.basic"), Default::default())
            .expect("failed to initialize GTK application");

    let state = Rc::new(RefCell::new(State::new()));

    {
        let state2 = Rc::new(RefCell::new(State::new()));

        application.connect_activate(clone!(@weak state, @weak state2 => move |app| {
            state.borrow_mut().started = true;

            let window = ApplicationWindow::new(app);
            window.set_title("First GTK+ Program");
            window.set_default_size(350, 70);

            let button = Button::new_with_label("Click me!");
            button.connect_clicked(clone!(@weak state, @weak state2 => move |_| {
                let mut state = state.borrow_mut();
                let mut state2 = state2.borrow_mut();
                println!("Clicked (started: {}): {} - {}!", state.started, state.count, state2.count);
                state.count += 1;
                state2.count += 1;
            }));
            window.add(&button);

            window.show_all();
        }));
    }

    application.run(&[]);
}
<commit_msg>Fix clone_macro example<commit_after>extern crate gio;
extern crate glib;
extern crate gtk;

use std::cell::RefCell;
use std::rc::Rc;

use gio::prelude::*;
use glib::clone;
use gtk::{prelude::*, Application, ApplicationWindow, Button};

#[derive(Default)]
struct State {
    started: bool,
    count: i32,
}

impl State {
    fn new() -> Self {
        Self {
            started: false,
            count: 0,
        }
    }
}

fn main() {
    let application =
        Application::new(Some("com.github.gtk-rs.examples.basic"), Default::default())
            .expect("failed to initialize GTK application");

    let state = Rc::new(RefCell::new(State::new()));

    {
        let state2 = Rc::new(RefCell::new(State::new()));

        application.connect_activate(clone!(@weak state, @strong state2 => move |app| {
            state.borrow_mut().started = true;

            let window = ApplicationWindow::new(app);
            window.set_title("First GTK+ Program");
            window.set_default_size(350, 70);

            let button = Button::new_with_label("Click me!");
            button.connect_clicked(clone!(@weak state, @weak state2 => move |_| {
                let mut state = state.borrow_mut();
                let mut state2 = state2.borrow_mut();
                println!("Clicked (started: {}): {} - {}!", state.started, state.count, state2.count);
                state.count += 1;
                state2.count += 1;
            }));
            window.add(&button);

            window.show_all();
        }));
    }

    application.run(&[]);
}
<|endoftext|>


<commit_before>#[feature(macro_rules)];
use std::{cast};

// emulating C++ classes using Traits as vtables, could the safety be improved?

pub trait Foo {
	fn foo(&self,i:int);
}

pub struct CppClass<RawDataStruct,TraitInterface> {
	priv vtable_ptr: *(),	// you must not change this :(
							// it is a ptr to the vtable
	dat:RawDataStruct
}

impl<Struct,Trait> Deref<Struct> for  CppClass<Struct,Trait> {
	fn deref<'a> (&'a self)->&'a Struct { &self.dat }
}
impl<Struct,Trait> DerefMut<Struct> for  CppClass<Struct,Trait> {
	fn deref_mut<'a> (&'a mut self)->&'a mut Struct { &mut self.dat }
}
/*
// TODO - we can't get this to work.
impl<Struct,T> Deref<T> for  CppClass<Struct,&'static T> {
	fn deref<'a> (&'a self)->&'a T { //&'a self.as_trait()
		unsafe {cast::transmute::<_,&'a T>( (self.vtable_ptr, &self.dat) )}
	}
}
impl<Struct,T> DerefMut<T> for  CppClass<Struct,&'static T> {
	fn deref_mut<'a> (&'a mut self)->&'a mut T { //&'a self.as_trait()
		unsafe {cast::transmute::<_,&'a mut T>( (self.vtable_ptr, &mut self.dat) )}
	}
}
*/

impl<Struct,Trait>  CppClass<Struct,Trait> {
	pub fn as_trait<'a>(&'a self)->Trait  {
	    unsafe {
			cast::transmute::<_,Trait>( (self.vtable_ptr, &self.dat) )
		}
	}
	pub fn data<'a>(&'a self)->&'a Struct { &'a self.dat }
	pub fn data_mut<'a>(&'a mut self)->&'a mut Struct { &'a mut self.dat }
}

macro_rules! new_class {

	($tname:ty for $sname:ident { $($field:ident : $val:expr),* })=>{
		// todo: we can't make initializer list work for arbitrary type,
		// so add another rule to accept a constructor function for non ident type.
		CppClass::<$sname,& $tname> {
			vtable_ptr:unsafe {
				let null_obj=cast::transmute::<_,&'static $sname>(0);
				let (vt,_):(*u8,*u8)=
					cast::transmute(null_obj as &'static $tname);
				cast::transmute(vt)
			},

			dat: $sname { $($field: $val),* }
		}
	}
}

struct Banana { x:int }
impl Foo for Banana {
	fn foo(&self,i:int) {
		println!("hello from banana.foo {:?} {:?} {:?}",i, self.x, i+self.x);
	}
}

fn main() {
	let mut b :CppClass<Banana,&Foo> = new_class!( Foo for Banana  {x:10} );
	b.dat.x=10;
	// can you write to 'vtable_ptr' unsafely?

	b.as_trait().foo(3);

}

<commit_msg>added data accessors, but couldn't get deref to return trait automatically<commit_after>#[feature(macro_rules)];
use std::{cast};

// emulating C++ classes using Traits as vtables, could the safety be improved?

pub trait Foo {
	fn foo(&self,i:int);
}

pub struct CppClass<RawDataStruct,TraitInterface> {
	priv vtable_ptr: *(),	// you must not change this :(
							// it is a ptr to the vtable
	dat:RawDataStruct
}

impl<Struct,Trait> Deref<Struct> for  CppClass<Struct,Trait> {
	fn deref<'a> (&'a self)->&'a Struct { &self.dat }
}
impl<Struct,Trait> DerefMut<Struct> for  CppClass<Struct,Trait> {
	fn deref_mut<'a> (&'a mut self)->&'a mut Struct { &mut self.dat }
}
/*
// TODO - we can't get this to work.
impl<Struct,T> Deref<T> for  CppClass<Struct,&'static T> {
	fn deref<'a> (&'a self)->&'a T { //&'a self.as_trait()
		unsafe {cast::transmute::<_,&'a T>( (self.vtable_ptr, &self.dat) )}
	}
}
impl<Struct,T> DerefMut<T> for  CppClass<Struct,&'static T> {
	fn deref_mut<'a> (&'a mut self)->&'a mut T { //&'a self.as_trait()
		unsafe {cast::transmute::<_,&'a mut T>( (self.vtable_ptr, &mut self.dat) )}
	}
}
*/

impl<Struct,Trait>  CppClass<Struct,Trait> {
	pub fn as_trait<'a>(&'a self)->Trait  {
	    unsafe {
			cast::transmute::<_,Trait>( (self.vtable_ptr, &self.dat) )
		}
	}
	pub fn data<'a>(&'a self)->&'a Struct { &'a self.dat }
	pub fn data_mut<'a>(&'a mut self)->&'a mut Struct { &'a mut self.dat }
}

macro_rules! new_class {

	($tname:ty for $sname:ident { $($field:ident : $val:expr),* })=>{
		// todo: we can't make initializer list work for arbitrary type,
		// so add another rule to accept a constructor function for non ident type.
		CppClass::<$sname,& $tname> {
			vtable_ptr:unsafe {
				let null_obj=cast::transmute::<_,&'static $sname>(0);
				let (vt,_):(*u8,*u8)=
					cast::transmute(null_obj as &'static $tname);
				cast::transmute(vt)
			},

			dat: $sname { $($field: $val),* }
		}
	}
}

struct Banana { x:int }
impl Foo for Banana {
	fn foo(&self,i:int) {
		println!("hello from banana.foo {:?} {:?} {:?}",i, self.x, i+self.x);
	}
}

macro_rules! repeat {
	(($it:ident=$it_init:expr ; $condition:expr ; $inc:expr)  $($e:expr);*)=>
	{
		{
			let mut $it=$it_init;
			while $condition {
				let ret={$($e);*};
				$inc;
				ret
			}
		}

	}
}

fn main() {
	let mut b :CppClass<Banana,&Foo> = new_class!( Foo for Banana  {x:10} );
	b.dat.x=10;
	// can you write to 'vtable_ptr' unsafely?

	b.as_trait().foo(3);

	repeat!{(i=0; i<10; i+=1)
		println!("{}",i)
	}

}
<|endoftext|>


<commit_before>use serde_json;

// TODO: use when new version drops
//use serialport::{SerialPortInfo,UsbPortInfo,SerialPortType};

use std::fmt;
use std::sync::mpsc::Sender;

#[derive( Clone, Debug)]
pub struct SubscriptionRequest {
  pub sub_id: String,
  pub subscriber: Sender<SerialResponse>,
}

/// Represents the valid json requests that can be made
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SerialRequest {
  // TODO: Divorce subscriptions from port open/close?
  // Right now port is only closed when last subscriber
  // unsubscribes
  /// Open a port for reading
  Open { port: String },
  /// Take control of a port for writing
  WriteLock { port: String },
  /// Release control of a port for writing
  /// If no port is given, release all write locks
  /// for all ports
  ReleaseWriteLock { port: Option<String> },
  /// Write data, only works if we have control
  Write {
    port: String,
    data: String,
    base64: Option<bool>,
  },
  /// Close a port or subscription
  Close { port: Option<String> },
  /// List serial ports
  List{},
}

impl fmt::Display for SerialRequest {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    let json = serde_json::to_string(self).unwrap_or("Display SerialRequest: Serialization Failed!"
                                                       .to_string());
    write!(f, "{}", json)
  }
}

/// Represents the valid serial responses that can be made
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SerialResponse {
  /// Error response
  Error {
    description: String,
    display: String,
  },
  /// Data that was read from port
  Read {
    port: String,
    data: String,
    base64: Option<bool>,
  },
  /// Port was closed
  Closed { port: String },
  /// Port was closed
  Opened { port: String },
  /// Command successful
  Ok { msg: String },
  /// List serial ports response
  List { ports: Vec<String> },
}

/*
// TODO: Uncomment when new serialport module version drops
/// Needed for Serde Support as
/// SerialPortInfo is in seperate module
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(remote = "SerialPortInfo")]
pub struct SerialPortInfoDef {
    /// The short name of the serial port
    pub port_name: String,
    /// The hardware device type that exposes this port
    pub port_type: SerialPortType,

}

#[derive(Serialize, Deserialize)]
#[serde(remote = "sp::SerialPortType")]
/// The physical type of a `SerialPort`
pub enum SerialPortTypeDef {
    /// The serial port is connected via USB
    UsbPort(UsbPortInfoDef),
    /// The serial port is connected via PCI (permanent port)
    PciPort,
    /// The serial port is connected via Bluetooth
    BluetoothPort,
    /// It can't be determined how the serial port is connected
    Unknown,
}

#[derive(Serialize, Deserialize)]
#[serde(remote = "UsbPortInfo")]
pub struct UsbPortInfoDef {
    /// Vender ID
    pub vid: u16,
    /// Product ID
    pub pid: u16,
    /// Serial number (arbitrary string)
    pub serial_number: Option<String>,
    /// Manufacturer (arbitrary string)
    pub manufacturer: Option<String>,
    /// Product name (arbitrary string)
    pub product: Option<String>,
}
*/

impl fmt::Display for SerialResponse {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    let json = serde_json::to_string(self).unwrap_or("Display SerialResponse: Serialization Failed!"
                                                       .to_string());
    write!(f, "{}", json)
  }
}
<commit_msg>Slight format tweak<commit_after>use serde_json;

// TODO: use when new version drops
//use serialport::{SerialPortInfo,UsbPortInfo,SerialPortType};

use std::fmt;
use std::sync::mpsc::Sender;

#[derive( Clone, Debug)]
pub struct SubscriptionRequest {
  pub sub_id: String,
  pub subscriber: Sender<SerialResponse>,
}

/// Represents the valid json requests that can be made
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SerialRequest {
  // TODO: Divorce subscriptions from port open/close?
  // Right now port is only closed when last subscriber
  // unsubscribes
  /// Open a port for reading
  Open { port: String },
  /// Take control of a port for writing
  WriteLock { port: String },
  /// Release control of a port for writing
  /// If no port is given, release all write locks
  /// for all ports
  ReleaseWriteLock { port: Option<String> },
  /// Write data, only works if we have control
  Write {
    port: String,
    data: String,
    base64: Option<bool>,
  },
  /// Close a port or subscription
  Close { port: Option<String> },
  /// List serial ports
  List {},
}

impl fmt::Display for SerialRequest {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    let json = serde_json::to_string(self).unwrap_or("Display SerialRequest: Serialization Failed!"
                                                       .to_string());
    write!(f, "{}", json)
  }
}

/// Represents the valid serial responses that can be made
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SerialResponse {
  /// Error response
  Error {
    description: String,
    display: String,
  },
  /// Data that was read from port
  Read {
    port: String,
    data: String,
    base64: Option<bool>,
  },
  /// Port was closed
  Closed { port: String },
  /// Port was closed
  Opened { port: String },
  /// Command successful
  Ok { msg: String },
  /// List serial ports response
  List { ports: Vec<String> },
}

/*
// TODO: Uncomment when new serialport module version drops
/// Needed for Serde Support as
/// SerialPortInfo is in seperate module
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(remote = "SerialPortInfo")]
pub struct SerialPortInfoDef {
    /// The short name of the serial port
    pub port_name: String,
    /// The hardware device type that exposes this port
    pub port_type: SerialPortType,

}

#[derive(Serialize, Deserialize)]
#[serde(remote = "sp::SerialPortType")]
/// The physical type of a `SerialPort`
pub enum SerialPortTypeDef {
    /// The serial port is connected via USB
    UsbPort(UsbPortInfoDef),
    /// The serial port is connected via PCI (permanent port)
    PciPort,
    /// The serial port is connected via Bluetooth
    BluetoothPort,
    /// It can't be determined how the serial port is connected
    Unknown,
}

#[derive(Serialize, Deserialize)]
#[serde(remote = "UsbPortInfo")]
pub struct UsbPortInfoDef {
    /// Vender ID
    pub vid: u16,
    /// Product ID
    pub pid: u16,
    /// Serial number (arbitrary string)
    pub serial_number: Option<String>,
    /// Manufacturer (arbitrary string)
    pub manufacturer: Option<String>,
    /// Product name (arbitrary string)
    pub product: Option<String>,
}
*/

impl fmt::Display for SerialResponse {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    let json = serde_json::to_string(self).unwrap_or("Display SerialResponse: Serialization Failed!"
                                                       .to_string());
    write!(f, "{}", json)
  }
}
<|endoftext|>


<commit_before>// Vecs act sort of like arrays, but allow more flexibility
#[test]
fn making_an_empty_vec() {
  let vector: Vec<()> = __
  assert!(vector.len() == 0);
}

// The vec! macro makes it easier to instantiate a vec
#[test]
fn vec_macro() {
  let vector = __
  assert!(vector.len() == 4);
}

// Elements can be added to mutable Vecs
#[test]
fn adding_to_vecs() {
  let mut vector = vec![0, 1, 2];
  vector.__(3);
  assert!(vector.len() == 4);
}

// Elements can also be remove from mutable Vecs
#[test]
fn removing_from_end_of_vecs() {
  let mut vector = vec![0, 1, 2, 3];
  vector.__();
  assert!(vector.len() == 3);
}

// The elements removed can also be stored to another variable
#[test]
fn storing_vec_elements(){
  let mut vector = vec![0, 1, 2, 3];
  let num = vector.__();
  assert!(num == 3);
}

// Vecs can change size to fit their contents
// Vecs do still need to be declared as mutable in order to change
#[test]
fn changing_size_of_vecs() {
  let mut vector = vec![1, 2, 3];
  __
  assert!(vector.len() == 4);
  __
  assert!(vector.len() == 3);
}

// Vecs have a certain maximum capacity at any given point
// When this capacity is reached, they will allocate more memory
#[test]
fn capacity() {
  let mut vector = vec![1, 2, 3, 4];
  assert_eq!(vector.capacity(), 4);
  vector.__;
  assert_eq!(vector.capacity(), 8);
  vector.pop();
  assert_eq!(vector.capacity(), __);
}

// This extra memory can also be deallocated when its no longer needed
#[test]
fn shrink_vecs() {
  let mut vector = vec![1, 2, 3, 4, 5];
  assert_eq!(vector.capacity(), 5);
  vector.pop();
  assert_eq!(vector.capacity(), __);
  vector.shrink_to_fit();
  assert_eq!(vector.capacity(), __);
}

// Vecs can reserve more space in order to prevent allocating several times
#[test]
fn reserve() {
  let mut vector = vec![1];
  vector.reserve(__);
  assert_eq!(vector.capacity(), 8);
}

// You can also cut Vecs down to size
#[test]
fn truncate() {
  let mut vector = vec![1, 2, 3, 4, 5];
  vector.__;
  assert_eq!(vector, vec![1, 2]);
}

// New elements can be stuffed into mutable Vecors
#[test]
fn insert() {
  let mut vector = vec![1, 2, 3, 4, 5];
  vector.insert(2, 6);
  assert_eq!(vector, __);
}

// Elements can also be deleted a particular position in a Vector
#[test]
fn remove() {
  let mut vector = vec![1, 2, 3, 4, 5];
  vector.remove(__);
  assert_eq!(vector, vec![2, 3, 4, 5])
}
<commit_msg>Add more koans to vec.rs<commit_after>// Vecs act sort of like arrays, but allow more flexibility
#[test]
fn making_an_empty_vec() {
  let vector: Vec<()> = __
  assert!(vector.len() == 0);
}

// The vec! macro makes it easier to instantiate a vec
#[test]
fn vec_macro() {
  let vector = __
  assert!(vector.len() == 4);
}

// Elements can be added to mutable Vecs
#[test]
fn adding_to_vecs() {
  let mut vector = vec![0, 1, 2];
  vector.__(3);
  assert!(vector.len() == 4);
}

// Elements can also be remove from mutable Vecs
#[test]
fn removing_from_end_of_vecs() {
  let mut vector = vec![0, 1, 2, 3];
  vector.__();
  assert!(vector.len() == 3);
}

// The elements removed can also be stored to another variable
#[test]
fn storing_vec_elements(){
  let mut vector = vec![0, 1, 2, 3];
  let num = vector.__();
  assert!(num == 3);
}

// Vecs can change size to fit their contents
// Vecs do still need to be declared as mutable in order to change
#[test]
fn changing_size_of_vecs() {
  let mut vector = vec![1, 2, 3];
  __
  assert!(vector.len() == 4);
  __
  assert!(vector.len() == 3);
}

// Vecs have a certain maximum capacity at any given point
// When this capacity is reached, they will allocate more memory
#[test]
fn capacity() {
  let mut vector = vec![1, 2, 3, 4];
  assert_eq!(vector.capacity(), 4);
  vector.__;
  assert_eq!(vector.capacity(), 8);
  vector.pop();
  assert_eq!(vector.capacity(), __);
}

// This extra memory can also be deallocated when its no longer needed
#[test]
fn shrink_vecs() {
  let mut vector = vec![1, 2, 3, 4, 5];
  assert_eq!(vector.capacity(), 5);
  vector.pop();
  assert_eq!(vector.capacity(), __);
  vector.shrink_to_fit();
  assert_eq!(vector.capacity(), __);
}

// Vecs can reserve more space in order to prevent allocating several times
#[test]
fn reserve() {
  let mut vector = vec![1];
  vector.reserve(__);
  assert_eq!(vector.capacity(), 8);
}

// You can also cut Vecs down to size
#[test]
fn truncate() {
  let mut vector = vec![1, 2, 3, 4, 5];
  vector.__;
  assert_eq!(vector, vec![1, 2]);
}

// New elements can be stuffed into mutable Vecors
#[test]
fn insert() {
  let mut vector = vec![1, 2, 3, 4, 5];
  vector.insert(2, 6);
  assert_eq!(vector, __);
}

// Elements can also be deleted a particular position in a Vector
#[test]
fn remove() {
  let mut vector = vec![1, 2, 3, 4, 5];
  vector.remove(__);
  assert_eq!(vector, vec![2, 3, 4, 5])
}

// We created an empty Vec in our first example,
// now let's check if a Vec is empty
#[test]
fn empty_vecs() {
  let mut vector = vec![""; 0];
  assert!(vector.is_empty()); // should return true
  assert!(!vector.is_empty()); // should return false
}

// Elements of a Vec can be accessed by their index.
// note: Vecs in Rust are zero-indexed
#[test]
fn vec_indices() {
  let vector = vec!["red", "green", "refactor"];
  assert_eq!(Some(&"green"), vector.get(__));
}

// You can also easily grab a Vec's first and last elements using the respective method
#[test]
fn first_and_last() {
  let vector = vec![false, true];
  assert_eq!(vector.__, Some(&false));
  assert_eq!(vector.__, Some(&true));
}

// It's also easy to check if a Vec contains a particular value
#[test]
fn contains_element() {
  let vector = vec!["Google", "Twitter", "Mozilla"];
  assert!(vector.contains(__));
  assert!(!vector.contains(__));
}

// Similar to contains(), you can also check if a Vec begins with a particular element
#[test]
fn starts_with() {
  let vector = vec![0, 2, 4, 6];
  assert!(vector.starts_with(&[__]));
}

// starts_with() can also accept multiple elements
#[test]
fn starts_with_2() {
  let vector = vec![0, 2, 4, 6];
  assert!(vector.starts_with(__));
}

// The same can be said for ends_with
#[test]
fn ends_with() {
  let vector = __;
  assert!(vector.ends_with(&[6]));
  assert!(vector.ends_with(&[2, 4, 6]));
}

// Reversing a Vec is pretty easy in Rust
#[test]
fn reverse_vecs() {
  let mut vector = vec![1, 2, 3];
  assert_eq!(vector.first(), Some(&3));
}

// You can also just swap two elements in a Vec
#[test]
fn trading_spaces() {
  let mut vector = vec![false, true];
  assert_eq!(vector.first(), Some(&true));
}

// Vecs can be broken up into equally sized chunks
#[test]
fn chunking() {
  let vector = vec![1, 2, 1, 2];
  for chunk in vector.chunks(2) {
    assert_eq!(chunk, &[__, __]);
  }
}

// Vecs can be split at a specified index
#[test]
fn splitting() {
  let vector = vec!["Ruby", "Rust", "Python", "C++"];
  let (langs1, langs2) = vector.split_at(__);
  assert_eq!(langs1, &["Ruby", "Rust"]);
  assert_eq!(langs2, &[__, __]);
}

// Or if you don't know the specific index, you can supply a conditon at which to split
// The new groups will not include the elements that match the condition
#[test]
fn more_splitting() {
  let vector = vec![1, 3, 4, 7, 9];
  for num in vector.split(|x| __ ) {
    assert!(!num.contains(&4));
  };
}
<|endoftext|>


<commit_before>use rusqlite::{SqliteConnection, SqliteTransaction, SqliteError};
use rusqlite::types::{ToSql, FromSql};
use rustc_serialize::json::{Json, ParserError};
use jmap::util::{FromJson, ParseError};
use jmap::contact::Contact;
use std::error::Error;
use std::convert::From;
use std::fmt;
use self::DbError::*;

use std::path::Path;

const VERSION: u32 = 1;

const CREATE_SQL: [&'static str; 6] = [
r###"
CREATE TABLE records (
    rowid       INTEGER PRIMARY KEY,
    id          TEXT NOT NULL,
    userid      INTEGER NOT NULL,
    type        INTEGER NOT NULL,
    modseq      INTEGER NOT NULL,
    json        TEXT NOT NULL,
    UNIQUE( id, userid )
);
"###,
r###"
CREATE INDEX idx_record_id_userid          ON records ( id, userid );
"###,
r###"
CREATE INDEX idx_record_userid_type        ON records ( userid, type );
"###,
r###"
CREATE INDEX idx_record_userid_type_modseq ON records ( userid, type, modseq );
"###,
r###"
CREATE TABLE modseq (
    userid      INTEGER NOT NULL,
    type        INTEGER NOT NULL,
    modseq      INTEGER NOT NULL,
    UNIQUE( userid, type )
);
"###,
r###"
CREATE INDEX idx_userid_type ON modseq ( userid, type );
"###,
];

/*
const UPGRADE_SQL: [&'static str; 1] = [
    // v1
    ""
];
*/

#[derive(Clone, PartialEq, Debug)]
pub enum DbError {
    InternalError(String),
}

impl Error for DbError {
    fn description(&self) -> &str {
        match *self {
            InternalError(_) => "internal database error",
        }
    }
}

impl fmt::Display for DbError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            InternalError(ref e) => format!("internal database error: {}", e),
        }.to_string())
    }
}

impl From<SqliteError> for DbError {
    fn from(e: SqliteError) -> DbError {
        InternalError(format!("sqlite: {}", e))
    }
}

impl From<ParserError> for DbError {
    fn from(e: ParserError) -> DbError {
        InternalError(format!("json: {}", e))
    }
}

impl From<ParseError> for DbError {
    fn from(e: ParseError) -> DbError {
        InternalError(format!("jmap: {}", e))
    }
}

pub type Transaction<'a> = SqliteTransaction<'a>;

#[derive(Debug)]
pub struct Db {
    conn: SqliteConnection,
}

impl Db {
    pub fn open() -> Result<Db,DbError> {
        //let conn = try!(SqliteConnection::open_in_memory());
        let conn = try!(SqliteConnection::open(&Path::new("db.sqlite")));
        let db = Db {
            conn: conn,
        };

        try!(db.upgrade());

        Ok(db)
    }

    pub fn transaction(&self) -> Result<Transaction,DbError> {
        match self.conn.transaction() {
            Ok(t) => Ok(t),
            Err(e) => Err(DbError::from(e)),
        }
    }

    fn exec(&self, sql: &str) -> Result<(),DbError> {
        let mut stmt = try!(self.conn.prepare(sql));
        try!(stmt.execute(&[]));
        Ok(())
    }

    fn exec_value<T>(&self, sql: &str, params: &[&ToSql]) -> Result<Option<T>,DbError> where T: FromSql {
        let mut stmt = try!(self.conn.prepare(sql));
        let mut res = try!(stmt.query(params));

        match res.next() {
            None       => Ok(None),
            Some(next) =>
                match next {
                    Err(e)   => Err(InternalError(format!("sqlite: {}", e))),
                    Ok(next) => {
                        let v: T = next.get(0);
                        Ok(Some(v))
                    },
            }
        }
    }

    fn version(&self) -> Result<u32,DbError> {
        let v = try!(self.exec_value::<i32>("PRAGMA user_version", &[])).unwrap();
        Ok(v as u32)
    }

    fn set_version(&self, v: u32) -> Result<(),DbError> {
        try!(self.exec(format!("PRAGMA user_version = {}", v as i32).as_ref()));
        Ok(())
    }

    fn upgrade(&self) -> Result<(),DbError> {
        let txn = try!(self.transaction());

        let ver = try!(self.version());
        if ver == VERSION { return Ok(()) }

        // new database
        if ver == 0 {
            for sql in CREATE_SQL.iter() {
                try!(self.exec(sql));
            }
        }

        /*
        // existing database, upgrade required
        else {
            // XXX
        }
        */

        try!(self.set_version(VERSION));

        try!(txn.commit());

        println!("upgraded db to version {}", VERSION);

        Ok(())
    }

    pub fn get_records(&self, userid: i64, ids: Option<&Vec<String>>) -> Result<Vec<Contact>,DbError> {
        let objtype = 1; // XXX contacts are type 1 for now

        let mut sql = "SELECT json FROM records WHERE userid = ? AND type = ?".to_string();
        let mut params: Vec<&ToSql> = vec!(&userid, &objtype);

        if let Some(ref ids) = ids {
            sql.push_str(" AND id IN ( ");

            let mut i = ids.iter();
            if let Some(id) = i.next() {
                sql.push_str("?");
                params.push(id);
            }
            for id in i {
                sql.push_str(",?");
                params.push(id);
            }

            sql.push_str(" )");
        }

        let mut stmt = try!(self.conn.prepare(sql.as_ref()));
        let res = try!(stmt.query(params.as_ref()));

        let mut records: Vec<Contact> = Vec::new();
        for row in res {
            if let Ok(ref r) = row {
                let json = try!(Json::from_str((r.get::<String>(0)).as_ref()));
                records.push(try!(Contact::from_json(&json)));
            }
        }

        Ok(records)
    }
}
<commit_msg>Function to get current state for record type<commit_after>use rusqlite::{SqliteConnection, SqliteTransaction, SqliteError};
use rusqlite::types::{ToSql, FromSql};
use rustc_serialize::json::{Json, ParserError};
use jmap::util::{FromJson, ParseError};
use jmap::contact::Contact;
use std::error::Error;
use std::convert::From;
use std::fmt;
use self::DbError::*;

use std::path::Path;

const VERSION: u32 = 1;

const CREATE_SQL: [&'static str; 6] = [
r###"
CREATE TABLE records (
    rowid       INTEGER PRIMARY KEY,
    id          TEXT NOT NULL,
    userid      INTEGER NOT NULL,
    type        INTEGER NOT NULL,
    modseq      INTEGER NOT NULL,
    json        TEXT NOT NULL,
    UNIQUE( id, userid )
);
"###,
r###"
CREATE INDEX idx_record_id_userid          ON records ( id, userid );
"###,
r###"
CREATE INDEX idx_record_userid_type        ON records ( userid, type );
"###,
r###"
CREATE INDEX idx_record_userid_type_modseq ON records ( userid, type, modseq );
"###,
r###"
CREATE TABLE modseq (
    userid      INTEGER NOT NULL,
    type        INTEGER NOT NULL,
    modseq      INTEGER NOT NULL,
    UNIQUE( userid, type )
);
"###,
r###"
CREATE INDEX idx_userid_type ON modseq ( userid, type );
"###,
];

/*
const UPGRADE_SQL: [&'static str; 1] = [
    // v1
    ""
];
*/

#[derive(Clone, PartialEq, Debug)]
pub enum DbError {
    InternalError(String),
}

impl Error for DbError {
    fn description(&self) -> &str {
        match *self {
            InternalError(_) => "internal database error",
        }
    }
}

impl fmt::Display for DbError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            InternalError(ref e) => format!("internal database error: {}", e),
        }.to_string())
    }
}

impl From<SqliteError> for DbError {
    fn from(e: SqliteError) -> DbError {
        InternalError(format!("sqlite: {}", e))
    }
}

impl From<ParserError> for DbError {
    fn from(e: ParserError) -> DbError {
        InternalError(format!("json: {}", e))
    }
}

impl From<ParseError> for DbError {
    fn from(e: ParseError) -> DbError {
        InternalError(format!("jmap: {}", e))
    }
}

pub type Transaction<'a> = SqliteTransaction<'a>;

#[derive(Debug)]
pub struct Db {
    conn: SqliteConnection,
}

impl Db {
    pub fn open() -> Result<Db,DbError> {
        //let conn = try!(SqliteConnection::open_in_memory());
        let conn = try!(SqliteConnection::open(&Path::new("db.sqlite")));
        let db = Db {
            conn: conn,
        };

        try!(db.upgrade());

        Ok(db)
    }

    pub fn transaction(&self) -> Result<Transaction,DbError> {
        match self.conn.transaction() {
            Ok(t) => Ok(t),
            Err(e) => Err(DbError::from(e)),
        }
    }

    fn exec(&self, sql: &str) -> Result<(),DbError> {
        let mut stmt = try!(self.conn.prepare(sql));
        try!(stmt.execute(&[]));
        Ok(())
    }

    fn exec_value<T>(&self, sql: &str, params: &[&ToSql]) -> Result<Option<T>,DbError> where T: FromSql {
        let mut stmt = try!(self.conn.prepare(sql));
        let mut res = try!(stmt.query(params));

        match res.next() {
            None       => Ok(None),
            Some(next) =>
                match next {
                    Err(e)   => Err(InternalError(format!("sqlite: {}", e))),
                    Ok(next) => {
                        let v: T = next.get(0);
                        Ok(Some(v))
                    },
            }
        }
    }

    fn version(&self) -> Result<u32,DbError> {
        let v = try!(self.exec_value::<i32>("PRAGMA user_version", &[])).unwrap();
        Ok(v as u32)
    }

    fn set_version(&self, v: u32) -> Result<(),DbError> {
        try!(self.exec(format!("PRAGMA user_version = {}", v as i32).as_ref()));
        Ok(())
    }

    fn upgrade(&self) -> Result<(),DbError> {
        let txn = try!(self.transaction());

        let ver = try!(self.version());
        if ver == VERSION { return Ok(()) }

        // new database
        if ver == 0 {
            for sql in CREATE_SQL.iter() {
                try!(self.exec(sql));
            }
        }

        /*
        // existing database, upgrade required
        else {
            // XXX
        }
        */

        try!(self.set_version(VERSION));

        try!(txn.commit());

        println!("upgraded db to version {}", VERSION);

        Ok(())
    }

    pub fn get_state(&self, userid: i64) -> Result<String,DbError> {
        let objtype = 1; // XXX contacts are type 1 for now

        let params: Vec<&ToSql> = vec!(&userid, &objtype);
        let sv = try!(self.exec_value::<i64>("SELECT modseq FROM modseq WHERE userid = ? AND type = ?", params.as_ref()));
        match sv {
            None    => Ok("0".to_string()),
            Some(v) => Ok(v.to_string()),
        }
    }

    pub fn get_records(&self, userid: i64, ids: Option<&Vec<String>>) -> Result<Vec<Contact>,DbError> {
        let objtype = 1; // XXX contacts are type 1 for now

        let mut sql = "SELECT json FROM records WHERE userid = ? AND type = ?".to_string();
        let mut params: Vec<&ToSql> = vec!(&userid, &objtype);

        if let Some(ref ids) = ids {
            sql.push_str(" AND id IN ( ");

            let mut i = ids.iter();
            if let Some(id) = i.next() {
                sql.push_str("?");
                params.push(id);
            }
            for id in i {
                sql.push_str(",?");
                params.push(id);
            }

            sql.push_str(" )");
        }

        let mut stmt = try!(self.conn.prepare(sql.as_ref()));
        let res = try!(stmt.query(params.as_ref()));

        let mut records: Vec<Contact> = Vec::new();
        for row in res {
            if let Ok(ref r) = row {
                let json = try!(Json::from_str((r.get::<String>(0)).as_ref()));
                records.push(try!(Contact::from_json(&json)));
            }
        }

        Ok(records)
    }
}
<|endoftext|>


<commit_before>//! The state of the program including interactions (moving around), last query, search
//! results and current selection

use crate::common::{Prompt, Text};
use crate::fuzzy::Candidate;

/// Possible updates done to the State
#[derive(Debug, Clone)]
pub enum StateUpdate {
    /// The query has changed
    Query,
    /// Any other update
    All,
}

impl Default for StateUpdate {
    fn default() -> Self {
        Self::All
    }
}

/// Current state of the program
#[derive(Debug, Clone, Default)]
pub struct State {
    search: Option<Prompt>,
    matches: Vec<Candidate>,
    pool_len: usize,
    selection_idx: usize,
    last_update: StateUpdate,
}

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

    pub fn set_search(&mut self, search: Prompt) {
        self.search = Some(search);
        self.last_update = StateUpdate::Query;
    }

    pub fn query(&self) -> String {
        match &self.search {
            Some(sb) => sb.as_string(),
            None => "".into(),
        }
    }

    pub fn cursor_until_end(&self) -> usize {
        match &self.search {
            Some(sb) => sb.cursor_until_end(),
            None => 0,
        }
    }

    pub fn set_matches(&mut self, matches: (Vec<Candidate>, usize)) {
        self.matches = matches.0;
        self.pool_len = matches.1;

        if self.selection_idx >= self.max_selection() {
            self.selection_idx = self.max_selection();
        }

        self.last_update = StateUpdate::All;
    }

    pub fn matches(&self) -> &Vec<Candidate> {
        &self.matches
    }

    pub fn pool_len(&self) -> usize {
        self.pool_len
    }

    pub fn last_update(&self) -> &StateUpdate {
        &self.last_update
    }

    pub fn select_up(&mut self) {
        if self.selection_idx == 0 {
            self.selection_idx = self.max_selection();
        } else {
            self.selection_idx -= 1;
        }
        self.last_update = StateUpdate::All;
    }

    pub fn select_down(&mut self) {
        if self.selection_idx == self.max_selection() {
            self.selection_idx = 0;
        } else {
            self.selection_idx += 1;
        }
        self.last_update = StateUpdate::All;
    }

    pub fn selection_idx(&self) -> usize {
        self.selection_idx
    }

    pub fn selection(&self) -> Option<Text> {
        self.matches.get(self.selection_idx).map(|candidate| candidate.text.clone())
    }

    fn max_selection(&self) -> usize {
        let len = self.matches.len();

        if len == 0 {
            0
        } else {
            len - 1
        }
    }
}
<commit_msg>Fix format in state.rs mod<commit_after>//! The state of the program including interactions (moving around), last query, search
//! results and current selection

use crate::common::{Prompt, Text};
use crate::fuzzy::Candidate;

/// Possible updates done to the State
#[derive(Debug, Clone)]
pub enum StateUpdate {
    /// The query has changed
    Query,
    /// Any other update
    All,
}

impl Default for StateUpdate {
    fn default() -> Self {
        Self::All
    }
}

/// Current state of the program
#[derive(Debug, Clone, Default)]
pub struct State {
    search: Option<Prompt>,
    matches: Vec<Candidate>,
    pool_len: usize,
    selection_idx: usize,
    last_update: StateUpdate,
}

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

    pub fn set_search(&mut self, search: Prompt) {
        self.search = Some(search);
        self.last_update = StateUpdate::Query;
    }

    pub fn query(&self) -> String {
        match &self.search {
            Some(sb) => sb.as_string(),
            None => "".into(),
        }
    }

    pub fn cursor_until_end(&self) -> usize {
        match &self.search {
            Some(sb) => sb.cursor_until_end(),
            None => 0,
        }
    }

    pub fn set_matches(&mut self, matches: (Vec<Candidate>, usize)) {
        self.matches = matches.0;
        self.pool_len = matches.1;

        if self.selection_idx >= self.max_selection() {
            self.selection_idx = self.max_selection();
        }

        self.last_update = StateUpdate::All;
    }

    pub fn matches(&self) -> &Vec<Candidate> {
        &self.matches
    }

    pub fn pool_len(&self) -> usize {
        self.pool_len
    }

    pub fn last_update(&self) -> &StateUpdate {
        &self.last_update
    }

    pub fn select_up(&mut self) {
        if self.selection_idx == 0 {
            self.selection_idx = self.max_selection();
        } else {
            self.selection_idx -= 1;
        }
        self.last_update = StateUpdate::All;
    }

    pub fn select_down(&mut self) {
        if self.selection_idx == self.max_selection() {
            self.selection_idx = 0;
        } else {
            self.selection_idx += 1;
        }
        self.last_update = StateUpdate::All;
    }

    pub fn selection_idx(&self) -> usize {
        self.selection_idx
    }

    pub fn selection(&self) -> Option<Text> {
        self.matches
            .get(self.selection_idx)
            .map(|candidate| candidate.text.clone())
    }

    fn max_selection(&self) -> usize {
        let len = self.matches.len();

        if len == 0 {
            0
        } else {
            len - 1
        }
    }
}
<|endoftext|>


<commit_before>//! Types related to topic metadata for introspection by clients.
//! Example: `KafkaClient::topics()`.

use std::collections::hash_map;
use std::fmt;

use super::KafkaClient;
use super::state::{ClientState, TopicPartitions, TopicPartitionIter, TopicPartition};

// public re-export
pub use super::state::Broker;

/// A view on the loaded metadata about topics and their partitions.
pub struct Topics<'a> {
    state: &'a ClientState
}

impl<'a> Topics<'a> {
    /// Constructs a view of the currently loaded topic metadata from
    /// the specified kafka client.
    #[inline]
    pub fn new(client: &KafkaClient) -> Topics {
        Topics { state: &client.state }
    }

    /// Retrieves the number of the underlying topics.
    #[inline]
    pub fn len(&self) -> usize {
        self.state.num_topics()
    }

    /// Provides an iterator over the underlying topics.
    #[inline]
    pub fn iter(&'a self) -> TopicIter<'a> {
        TopicIter::new(self.state)
    }

    /// A conveniece method to return an iterator the topics' names.
    #[inline]
    pub fn names(&'a self) -> TopicNames<'a> {
        TopicNames { iter: self.state.topic_partitions().keys() }
    }

    /// A convenience method to determine whether the specified topic
    /// is known.
    #[inline]
    pub fn contains(&'a self, topic: &str) -> bool {
        self.state.contains_topic(topic)
    }

    /// Retrieves the partitions of a specified topic.
    #[inline]
    pub fn partitions(&'a self, topic: &str) -> Option<Partitions<'a>> {
        self.state.partitions_for(topic).map(|tp| Partitions {
            state: self.state,
            tp: tp,
        })
    }
}

impl<'a> fmt::Debug for Topics<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "Topics {{ topics: ["));
        let mut ts = self.iter();
        if let Some(t) = ts.next() {
            try!(write!(f, "{:?}", t));
        }
        for t in ts {
            try!(write!(f, ", {:?}", t));
        }
        write!(f, "] }}")
    }
}

impl<'a> IntoIterator for &'a Topics<'a> {
    type Item=Topic<'a>;
    type IntoIter=TopicIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a> IntoIterator for Topics<'a> {
    type Item=Topic<'a>;
    type IntoIter=TopicIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        TopicIter::new(self.state)
    }
}

/// An interator over topics.
pub struct TopicIter<'a> {
    state: &'a ClientState,
    iter: hash_map::Iter<'a, String, TopicPartitions>,
}

impl<'a> TopicIter<'a> {
    fn new(state: &'a ClientState) -> TopicIter<'a> {
        TopicIter {
            state: state,
            iter: state.topic_partitions().iter()
        }
    }
}

impl<'a> Iterator for TopicIter<'a> {
    type Item=Topic<'a>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(name, tps) | Topic {
            state: self.state,
            name: &name[..],
            tp: tps,
        })
    }
}

/// An iterator over the topic names.
pub struct TopicNames<'a> {
    iter: hash_map::Keys<'a, String, TopicPartitions>,
}

impl<'a> Iterator for TopicNames<'a> {
    type Item=&'a str;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|s| &s[..])
    }
}

/// A view on the loaded metadata for a particular topic.
pub struct Topic<'a> {
    state: &'a ClientState,
    name: &'a str,
    tp: &'a TopicPartitions,
}

impl<'a> Topic<'a> {
    /// Retrieves the name of this topic.
    #[inline]
    pub fn name(&self) -> &str {
        self.name
    }

    /// Retrieves the list of all partitions for this topic.
    #[inline]
    pub fn partitions(&self) -> Partitions<'a> {
        Partitions {
            state: self.state,
            tp: self.tp,
        }
    }
}

impl<'a> fmt::Debug for Topic<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Topic {{ name: {}, partitions: {:?} }}",
               self.name, self.partitions())
    }
}

/// Metadata relevant to partitions of a particular topic.
pub struct Partitions<'a> {
    state: &'a ClientState,
    tp: &'a TopicPartitions,
}

impl<'a> Partitions<'a> {
    /// Retrieves the number of the topic's partitions.
    #[inline]
    pub fn len(&self) -> usize {
        self.tp.len()
    }

    /// Tests for `.len() > 0`.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.tp.is_empty()
    }

    /// Retrieves an iterator of the partitions of the underlying topic.
    #[inline]
    pub fn iter(&self) -> PartitionIter<'a> {
        PartitionIter::new(self.state, self.tp)
    }

    /// Finds a specified partition identified by its id.
    #[inline]
    pub fn partition(&self, partition_id: i32) -> Option<Partition<'a>> {
        self.tp.partition(partition_id).map(|p| Partition::new(self.state, p, partition_id))
    }

    /// Convenience method to retrieve the identifiers of all
    /// currently "available" partitions.  Such partitions are known
    /// to have a leader broker and can be sent messages to.
    #[inline]
    pub fn available_ids(&self) -> Vec<i32> {
        self.tp.iter()
            .filter_map(|(id, p)| p.broker(self.state).map(|_| id))
            .collect()
    }
}

impl<'a> fmt::Debug for Partitions<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "Partitions {{ ["));
        let mut ps = self.iter();
        if let Some(p) = ps.next() {
            try!(write!(f, "{:?}", p));
        }
        for p in ps {
            try!(write!(f, ", {:?}", p));
        }
        write!(f, "] }}")
    }
}

impl<'a> IntoIterator for &'a Partitions<'a> {
    type Item=Partition<'a>;
    type IntoIter=PartitionIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a> IntoIterator for Partitions<'a> {
    type Item=Partition<'a>;
    type IntoIter=PartitionIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        PartitionIter::new(self.state, self.tp)
    }
}

/// An interator over a topic's partitions.
pub struct PartitionIter<'a> {
    state: &'a ClientState,
    iter: TopicPartitionIter<'a>,
}

impl<'a> PartitionIter<'a> {
    fn new(state: &'a ClientState, tp: &'a TopicPartitions) -> Self {
        PartitionIter { state: state, iter: tp.iter() }
    }
}

impl<'a> Iterator for PartitionIter<'a> {
    type Item=Partition<'a>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(id, p)| Partition::new(self.state, p, id))
    }
}

/// Metadata about a particular topic partition.
///
/// A partition can be seen as either available or not by
/// `kafka-rust`.  "Available" partitions are partitions with an
/// assigned leader broker and can be send messages to or fetched
/// messages from.  Non-available partitions are ignored by
/// `kafka-rust`.  Whether or not a partition is currently "available"
/// can be determined by testing for `partition.leader().is_some()` or
/// more directly through `partition.available()`.
pub struct Partition<'a> {
    state: &'a ClientState,
    partition: &'a TopicPartition,
    id: i32,
}

impl<'a> Partition<'a> {
    fn new(state: &'a ClientState, partition: &'a TopicPartition, id: i32) -> Partition<'a> {
        Partition { state: state, partition: partition, id: id }
    }

    /// Retrieves the identifier of this topic partition.
    #[inline]
    pub fn id(&self) -> i32 {
        self.id
    }

    /// Retrieves the current leader broker of this partition - if
    /// any.  A partition with a leader is said to be "available".
    #[inline]
    pub fn leader(&self) -> Option<&Broker> {
        self.partition.broker(self.state)
    }

    /// Determines whether this partition is currently "available".
    /// See `Partition::leader()`.
    pub fn available(&self) -> bool {
        self.leader().is_some()
    }
}

impl<'a> fmt::Debug for Partition<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Partition {{ id: {}, leader: {:?} }}", self.id(), self.leader())
    }
}
<commit_msg>#! Rustfmt<commit_after>//! Types related to topic metadata for introspection by clients.
//! Example: `KafkaClient::topics()`.

use std::collections::hash_map;
use std::fmt;

use super::KafkaClient;
use super::state::{ClientState, TopicPartitions, TopicPartitionIter, TopicPartition};

// public re-export
pub use super::state::Broker;

/// A view on the loaded metadata about topics and their partitions.
pub struct Topics<'a> {
    state: &'a ClientState,
}

impl<'a> Topics<'a> {
    /// Constructs a view of the currently loaded topic metadata from
    /// the specified kafka client.
    #[inline]
    pub fn new(client: &KafkaClient) -> Topics {
        Topics { state: &client.state }
    }

    /// Retrieves the number of the underlying topics.
    #[inline]
    pub fn len(&self) -> usize {
        self.state.num_topics()
    }

    /// Provides an iterator over the underlying topics.
    #[inline]
    pub fn iter(&'a self) -> TopicIter<'a> {
        TopicIter::new(self.state)
    }

    /// A conveniece method to return an iterator the topics' names.
    #[inline]
    pub fn names(&'a self) -> TopicNames<'a> {
        TopicNames { iter: self.state.topic_partitions().keys() }
    }

    /// A convenience method to determine whether the specified topic
    /// is known.
    #[inline]
    pub fn contains(&'a self, topic: &str) -> bool {
        self.state.contains_topic(topic)
    }

    /// Retrieves the partitions of a specified topic.
    #[inline]
    pub fn partitions(&'a self, topic: &str) -> Option<Partitions<'a>> {
        self.state.partitions_for(topic).map(|tp| {
            Partitions {
                state: self.state,
                tp: tp,
            }
        })
    }
}

impl<'a> fmt::Debug for Topics<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "Topics {{ topics: ["));
        let mut ts = self.iter();
        if let Some(t) = ts.next() {
            try!(write!(f, "{:?}", t));
        }
        for t in ts {
            try!(write!(f, ", {:?}", t));
        }
        write!(f, "] }}")
    }
}

impl<'a> IntoIterator for &'a Topics<'a> {
    type Item=Topic<'a>;
    type IntoIter=TopicIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a> IntoIterator for Topics<'a> {
    type Item=Topic<'a>;
    type IntoIter=TopicIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        TopicIter::new(self.state)
    }
}

/// An interator over topics.
pub struct TopicIter<'a> {
    state: &'a ClientState,
    iter: hash_map::Iter<'a, String, TopicPartitions>,
}

impl<'a> TopicIter<'a> {
    fn new(state: &'a ClientState) -> TopicIter<'a> {
        TopicIter {
            state: state,
            iter: state.topic_partitions().iter(),
        }
    }
}

impl<'a> Iterator for TopicIter<'a> {
    type Item=Topic<'a>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(name, tps)| {
            Topic {
                state: self.state,
                name: &name[..],
                tp: tps,
            }
        })
    }
}

/// An iterator over the topic names.
pub struct TopicNames<'a> {
    iter: hash_map::Keys<'a, String, TopicPartitions>,
}

impl<'a> Iterator for TopicNames<'a> {
    type Item=&'a str;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|s| &s[..])
    }
}

/// A view on the loaded metadata for a particular topic.
pub struct Topic<'a> {
    state: &'a ClientState,
    name: &'a str,
    tp: &'a TopicPartitions,
}

impl<'a> Topic<'a> {
    /// Retrieves the name of this topic.
    #[inline]
    pub fn name(&self) -> &str {
        self.name
    }

    /// Retrieves the list of all partitions for this topic.
    #[inline]
    pub fn partitions(&self) -> Partitions<'a> {
        Partitions {
            state: self.state,
            tp: self.tp,
        }
    }
}

impl<'a> fmt::Debug for Topic<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "Topic {{ name: {}, partitions: {:?} }}",
               self.name,
               self.partitions())
    }
}

/// Metadata relevant to partitions of a particular topic.
pub struct Partitions<'a> {
    state: &'a ClientState,
    tp: &'a TopicPartitions,
}

impl<'a> Partitions<'a> {
    /// Retrieves the number of the topic's partitions.
    #[inline]
    pub fn len(&self) -> usize {
        self.tp.len()
    }

    /// Tests for `.len() > 0`.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.tp.is_empty()
    }

    /// Retrieves an iterator of the partitions of the underlying topic.
    #[inline]
    pub fn iter(&self) -> PartitionIter<'a> {
        PartitionIter::new(self.state, self.tp)
    }

    /// Finds a specified partition identified by its id.
    #[inline]
    pub fn partition(&self, partition_id: i32) -> Option<Partition<'a>> {
        self.tp.partition(partition_id).map(|p| Partition::new(self.state, p, partition_id))
    }

    /// Convenience method to retrieve the identifiers of all
    /// currently "available" partitions.  Such partitions are known
    /// to have a leader broker and can be sent messages to.
    #[inline]
    pub fn available_ids(&self) -> Vec<i32> {
        self.tp
            .iter()
            .filter_map(|(id, p)| p.broker(self.state).map(|_| id))
            .collect()
    }
}

impl<'a> fmt::Debug for Partitions<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "Partitions {{ ["));
        let mut ps = self.iter();
        if let Some(p) = ps.next() {
            try!(write!(f, "{:?}", p));
        }
        for p in ps {
            try!(write!(f, ", {:?}", p));
        }
        write!(f, "] }}")
    }
}

impl<'a> IntoIterator for &'a Partitions<'a> {
    type Item=Partition<'a>;
    type IntoIter=PartitionIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a> IntoIterator for Partitions<'a> {
    type Item=Partition<'a>;
    type IntoIter=PartitionIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        PartitionIter::new(self.state, self.tp)
    }
}

/// An interator over a topic's partitions.
pub struct PartitionIter<'a> {
    state: &'a ClientState,
    iter: TopicPartitionIter<'a>,
}

impl<'a> PartitionIter<'a> {
    fn new(state: &'a ClientState, tp: &'a TopicPartitions) -> Self {
        PartitionIter {
            state: state,
            iter: tp.iter(),
        }
    }
}

impl<'a> Iterator for PartitionIter<'a> {
    type Item=Partition<'a>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(id, p)| Partition::new(self.state, p, id))
    }
}

/// Metadata about a particular topic partition.
///
/// A partition can be seen as either available or not by
/// `kafka-rust`.  "Available" partitions are partitions with an
/// assigned leader broker and can be send messages to or fetched
/// messages from.  Non-available partitions are ignored by
/// `kafka-rust`.  Whether or not a partition is currently "available"
/// can be determined by testing for `partition.leader().is_some()` or
/// more directly through `partition.available()`.
pub struct Partition<'a> {
    state: &'a ClientState,
    partition: &'a TopicPartition,
    id: i32,
}

impl<'a> Partition<'a> {
    fn new(state: &'a ClientState, partition: &'a TopicPartition, id: i32) -> Partition<'a> {
        Partition {
            state: state,
            partition: partition,
            id: id,
        }
    }

    /// Retrieves the identifier of this topic partition.
    #[inline]
    pub fn id(&self) -> i32 {
        self.id
    }

    /// Retrieves the current leader broker of this partition - if
    /// any.  A partition with a leader is said to be "available".
    #[inline]
    pub fn leader(&self) -> Option<&Broker> {
        self.partition.broker(self.state)
    }

    /// Determines whether this partition is currently "available".
    /// See `Partition::leader()`.
    pub fn available(&self) -> bool {
        self.leader().is_some()
    }
}

impl<'a> fmt::Debug for Partition<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "Partition {{ id: {}, leader: {:?} }}",
               self.id(),
               self.leader())
    }
}
<|endoftext|>


<commit_before>/// Utilities for writing messages to the Janus log.
extern crate chrono;
extern crate colored;

use self::chrono::{DateTime, Local};
use self::colored::{Color, Colorize};
use super::ffi;
use std::fmt::Write;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
/// A Janus log level. Lower is more severe.
pub enum LogLevel {
    Fatal = 1,
    Err = 2,
    Warn = 3,
    Info = 4,
    Verb = 5,
    Huge = 6,
    Dbg = 7,
}

impl LogLevel {
    /// The color associated with each log level's label (if colors are enabled.)
    fn color(&self) -> Option<Color> {
        match *self {
            LogLevel::Fatal => Some(Color::Magenta),
            LogLevel::Err => Some(Color::Red),
            LogLevel::Warn => Some(Color::Yellow),
            _ => None,
        }
    }
}

#[derive(Debug, Clone)]
pub struct LogParameters {
    pub max_log_level: i32,
    pub log_timestamps: bool,
    pub log_colors: bool,
    pub clock: fn() -> DateTime<Local>,
}

impl Default for LogParameters {
    fn default() -> Self {
        unsafe {
            Self {
                max_log_level: ffi::janus_log_level,
                log_timestamps: ffi::janus_log_timestamps == 1,
                log_colors: ffi::janus_log_colors == 1,
                clock: Local::now,
            }
        }
    }
}

/// Writes a message at the given log level to the Janus log, using the provided parameters to control
/// how the log message is formatted.
pub fn write_log(level: LogLevel, message: &str, params: LogParameters) {
    if level as i32 <= params.max_log_level {
        let output = print_log(level, message, params);
        unsafe { ffi::janus_vprintf(output.as_ptr() as *const _) }
    }
}

/// Prints a message at the given log level into an owned string, using the provided parameters to control
/// how the log message is formatted.
pub fn print_log(level: LogLevel, message: &str, params: LogParameters) -> String {
    let mut output = String::with_capacity(message.len() + 40);
    if params.log_timestamps {
        write!(output, "{} ", (params.clock)().format("[%a %b %e %T %Y]")).unwrap();
    }
    if level <= LogLevel::Warn {
        let name = format!("[{:?}] ", level).to_uppercase();
        match (params.log_colors, level.color()) {
            (true, Some(c)) => output.push_str(&name.color(c)),
            _ => output.push_str(&name),
        }
    }
    output.push_str(message);
    output.push('\n');
    output
}

/// Writes a message at the given log level to the Janus log.
pub fn log(level: LogLevel, message: &str) {
    write_log(level, message, LogParameters::default());
}

#[cfg(test)]
mod tests {

    use super::*;
    use super::chrono::TimeZone;

    fn fixed_clock(year: i32, month: u32, day: u32, hour: u32, min: u32, sec: u32) -> DateTime<Local> {
        Local.ymd(year, month, day).and_hms(hour, min, sec)
    }

    #[test]
    fn log_format_correctness() {
        assert_eq!(
            "[Tue Oct 10 01:37:46 2017] [WARN] Test message.\n",
            print_log(
                LogLevel::Warn,
                "Test message.",
                LogParameters {
                    max_log_level: 6,
                    log_timestamps: true,
                    log_colors: false,
                    clock: || fixed_clock(2017, 10, 10, 1, 37, 46),
                }
            )
        )
    }
}
<commit_msg>Fix a bug in logging<commit_after>/// Utilities for writing messages to the Janus log.
extern crate chrono;
extern crate colored;

use self::chrono::{DateTime, Local};
use self::colored::{Color, Colorize};
use super::ffi;
use std::ffi::CString;
use std::fmt::Write;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
/// A Janus log level. Lower is more severe.
pub enum LogLevel {
    Fatal = 1,
    Err = 2,
    Warn = 3,
    Info = 4,
    Verb = 5,
    Huge = 6,
    Dbg = 7,
}

impl LogLevel {
    /// The color associated with each log level's label (if colors are enabled.)
    fn color(&self) -> Option<Color> {
        match *self {
            LogLevel::Fatal => Some(Color::Magenta),
            LogLevel::Err => Some(Color::Red),
            LogLevel::Warn => Some(Color::Yellow),
            _ => None,
        }
    }
}

#[derive(Debug, Clone)]
pub struct LogParameters {
    pub max_log_level: i32,
    pub log_timestamps: bool,
    pub log_colors: bool,
    pub clock: fn() -> DateTime<Local>,
}

impl Default for LogParameters {
    fn default() -> Self {
        unsafe {
            Self {
                max_log_level: ffi::janus_log_level,
                log_timestamps: ffi::janus_log_timestamps == 1,
                log_colors: ffi::janus_log_colors == 1,
                clock: Local::now,
            }
        }
    }
}

/// Writes a message at the given log level to the Janus log, using the provided parameters to control
/// how the log message is formatted.
pub fn write_log(level: LogLevel, message: &str, params: LogParameters) {
    if level as i32 <= params.max_log_level {
        let output = CString::new(print_log(level, message, params)).expect("Null character in log message :(");
        unsafe { ffi::janus_vprintf(output.as_ptr()) }
    }
}

/// Prints a message at the given log level into an owned string, using the provided parameters to control
/// how the log message is formatted.
pub fn print_log(level: LogLevel, message: &str, params: LogParameters) -> String {
    let mut output = String::with_capacity(message.len() + 40);
    if params.log_timestamps {
        write!(output, "{} ", (params.clock)().format("[%a %b %e %T %Y]")).unwrap();
    }
    if level <= LogLevel::Warn {
        let name = format!("[{:?}] ", level).to_uppercase();
        match (params.log_colors, level.color()) {
            (true, Some(c)) => output.push_str(&name.color(c)),
            _ => output.push_str(&name),
        }
    }
    output.push_str(message);
    output.push('\n');
    output
}

/// Writes a message at the given log level to the Janus log.
pub fn log(level: LogLevel, message: &str) {
    write_log(level, message, LogParameters::default());
}

#[cfg(test)]
mod tests {

    use super::*;
    use super::chrono::TimeZone;

    fn fixed_clock(year: i32, month: u32, day: u32, hour: u32, min: u32, sec: u32) -> DateTime<Local> {
        Local.ymd(year, month, day).and_hms(hour, min, sec)
    }

    #[test]
    fn log_format_correctness() {
        assert_eq!(
            "[Tue Oct 10 01:37:46 2017] [WARN] Test message.\n",
            print_log(
                LogLevel::Warn,
                "Test message.",
                LogParameters {
                    max_log_level: 6,
                    log_timestamps: true,
                    log_colors: false,
                    clock: || fixed_clock(2017, 10, 10, 1, 37, 46),
                }
            )
        )
    }
}
<|endoftext|>