<commit_before>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! A library for 2D graphics that works with multiple back-ends.

extern crate core;
extern crate std;

pub use AddBevel
    = add_bevel::AddBevel;
pub use AddBevelBorder
    = add_bevel_border::AddBevelBorder;
pub use AddBorder
    = add_border::AddBorder;
pub use AddColor
    = add_color::AddColor;
pub use AddEllipse
    = add_ellipse::AddEllipse;
pub use AddImage
    = add_image::AddImage;
pub use AddLine
    = add_line::AddLine;
pub use AddPolygon
    = add_polygon::AddPolygon;
pub use AddPolygons
    = add_polygons::AddPolygons;
pub use AddRectangle
    = add_rectangle::AddRectangle;
pub use AddRound
    = add_round::AddRound;
pub use AddRoundBorder
    = add_round_border::AddRoundBorder;
pub use AddSquareBorder
    = add_square_border::AddSquareBorder;
pub use AddTween
    = add_tween::AddTween;
pub use BackEnd
    = back_end::BackEnd;
pub use BevelBorderLineColorContext
    = bevel_border_line_color_context::BevelBorderLineColorContext;
pub use BevelBorderLineContext
    = bevel_border_line_context::BevelBorderLineContext;
pub use BevelRectangleBorderColorContext
    = bevel_rectangle_border_color_context::BevelRectangleBorderColorContext;
pub use BevelRectangleBorderContext
    = bevel_rectangle_border_context::BevelRectangleBorderContext;
pub use BevelRectangleColorContext
    = bevel_rectangle_color_context::BevelRectangleColorContext;
pub use BevelRectangleContext
    = bevel_rectangle_context::BevelRectangleContext;
pub use ColorContext
    = color_context::ColorContext;
pub use Context
    = context::Context;
pub use Draw
    = draw::Draw;
pub use EllipseContext
    = ellipse_context::EllipseContext;
pub use EllipseBorderContext
    = ellipse_border_context::EllipseBorderContext;
pub use EllipseColorContext
    = ellipse_color_context::EllipseColorContext;
pub use EllipseBorderColorContext
    = ellipse_border_color_context::EllipseBorderColorContext;
pub use ImageSize
    = image_size::ImageSize;
pub use ImageContext
    = image_context::ImageContext;
pub use ImageColorContext
    = image_color_context::ImageColorContext;
pub use ImageRectangleContext
    = image_rectangle_context::ImageRectangleContext;
pub use ImageRectangleColorContext
    = image_rectangle_color_context::ImageRectangleColorContext;
pub use LerpTweenContext
    = lerp_tween_context::LerpTweenContext;
pub use LerpTweenColorContext
    = lerp_tween_color_context::LerpTweenColorContext;
pub use LerpTweenPolygonsContext
    = lerp_tween_polygons_context::LerpTweenPolygonsContext;
pub use LerpTweenPolygonsColorContext
    = lerp_tween_polygons_color_context::LerpTweenPolygonsColorContext;
pub use LineContext
    = line_context::LineContext;
pub use LineColorContext
    = line_color_context::LineColorContext;
pub use PolygonContext
    = polygon_context::PolygonContext;
pub use PolygonColorContext
    = polygon_color_context::PolygonColorContext;
pub use RectangleBorderContext
    = rectangle_border_context::RectangleBorderContext;
pub use RectangleBorderColorContext
    = rectangle_border_color_context::RectangleBorderColorContext;
pub use RectangleContext
    = rectangle_context::RectangleContext;
pub use RectangleColorContext
    = rectangle_color_context::RectangleColorContext;
pub use RelativeColor
    = relative_color::RelativeColor;
pub use RelativeRectangle
    = relative_rectangle::RelativeRectangle;
pub use RelativeSourceRectangle
    = relative_source_rectangle::RelativeSourceRectangle;
pub use RelativeTransform2d
    = relative_transform2d::RelativeTransform2d;
pub use RoundBorderLineContext
    = round_border_line_context::RoundBorderLineContext;
pub use RoundBorderLineColorContext
    = round_border_line_color_context::RoundBorderLineColorContext;
pub use RoundRectangleBorderColorContext
    = round_rectangle_border_color_context::RoundRectangleBorderColorContext;
pub use RoundRectangleBorderContext
    = round_rectangle_border_context::RoundRectangleBorderContext;
pub use RoundRectangleColorContext
    = round_rectangle_color_context::RoundRectangleColorContext;
pub use RoundRectangleContext
    = round_rectangle_context::RoundRectangleContext;
pub use SquareBorderLineColorContext
    = square_border_line_color_context::SquareBorderLineColorContext;
pub use SquareBorderLineContext
    = square_border_line_context::SquareBorderLineContext;
pub use View
    = view::View;

mod add_bevel;
mod add_bevel_border;
mod add_border;
mod add_color;
mod add_ellipse;
mod add_image;
mod add_line;
mod add_polygon;
mod add_polygons;
mod add_rectangle;
mod add_round;
mod add_round_border;
mod add_square_border;
mod add_tween;
mod back_end;
mod bevel_border_line_color_context;
mod bevel_border_line_context;
mod bevel_rectangle_border_color_context;
mod bevel_rectangle_border_context;
mod bevel_rectangle_color_context;
mod bevel_rectangle_context;
mod color_context;
mod context;
mod draw;
mod ellipse_border_context;
mod ellipse_border_color_context;
mod ellipse_color_context;
mod ellipse_context;
mod image_size;
mod image_context;
mod image_color_context;
mod image_rectangle_color_context;
mod image_rectangle_context;
mod line_color_context;
mod line_context;
mod polygon_color_context;
mod polygon_context;
mod rectangle_border_context;
mod rectangle_border_color_context;
mod rectangle_color_context;
mod rectangle_context;
mod relative_color;
mod relative_rectangle;
mod relative_source_rectangle;
mod relative_transform2d;
mod round_border_line_color_context;
mod round_border_line_context;
mod round_rectangle_border_color_context;
mod round_rectangle_border_context;
mod round_rectangle_color_context;
mod round_rectangle_context;
mod square_border_line_color_context;
mod square_border_line_context;
mod lerp_tween_color_context;
mod lerp_tween_context;
mod lerp_tween_polygons_color_context;
mod lerp_tween_polygons_context;
mod view;

pub mod internal;
pub mod interpolation;
pub mod modular_index;
pub mod triangulation;
pub mod vecmath;

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<T> {
    /// Contains a value.
    Value(T),
}

impl<T: Copy> Field<T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&self) -> T {
        match *self {
            Value(val) => val,
        }
    }
}

/* Uncomment when lifetime traits problem is solved.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(val) => val,
        }
    }
}
*/

<commit_msg>Remove unused import of crates<commit_after>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! A library for 2D graphics that works with multiple back-ends.

pub use AddBevel
    = add_bevel::AddBevel;
pub use AddBevelBorder
    = add_bevel_border::AddBevelBorder;
pub use AddBorder
    = add_border::AddBorder;
pub use AddColor
    = add_color::AddColor;
pub use AddEllipse
    = add_ellipse::AddEllipse;
pub use AddImage
    = add_image::AddImage;
pub use AddLine
    = add_line::AddLine;
pub use AddPolygon
    = add_polygon::AddPolygon;
pub use AddPolygons
    = add_polygons::AddPolygons;
pub use AddRectangle
    = add_rectangle::AddRectangle;
pub use AddRound
    = add_round::AddRound;
pub use AddRoundBorder
    = add_round_border::AddRoundBorder;
pub use AddSquareBorder
    = add_square_border::AddSquareBorder;
pub use AddTween
    = add_tween::AddTween;
pub use BackEnd
    = back_end::BackEnd;
pub use BevelBorderLineColorContext
    = bevel_border_line_color_context::BevelBorderLineColorContext;
pub use BevelBorderLineContext
    = bevel_border_line_context::BevelBorderLineContext;
pub use BevelRectangleBorderColorContext
    = bevel_rectangle_border_color_context::BevelRectangleBorderColorContext;
pub use BevelRectangleBorderContext
    = bevel_rectangle_border_context::BevelRectangleBorderContext;
pub use BevelRectangleColorContext
    = bevel_rectangle_color_context::BevelRectangleColorContext;
pub use BevelRectangleContext
    = bevel_rectangle_context::BevelRectangleContext;
pub use ColorContext
    = color_context::ColorContext;
pub use Context
    = context::Context;
pub use Draw
    = draw::Draw;
pub use EllipseContext
    = ellipse_context::EllipseContext;
pub use EllipseBorderContext
    = ellipse_border_context::EllipseBorderContext;
pub use EllipseColorContext
    = ellipse_color_context::EllipseColorContext;
pub use EllipseBorderColorContext
    = ellipse_border_color_context::EllipseBorderColorContext;
pub use ImageSize
    = image_size::ImageSize;
pub use ImageContext
    = image_context::ImageContext;
pub use ImageColorContext
    = image_color_context::ImageColorContext;
pub use ImageRectangleContext
    = image_rectangle_context::ImageRectangleContext;
pub use ImageRectangleColorContext
    = image_rectangle_color_context::ImageRectangleColorContext;
pub use LerpTweenContext
    = lerp_tween_context::LerpTweenContext;
pub use LerpTweenColorContext
    = lerp_tween_color_context::LerpTweenColorContext;
pub use LerpTweenPolygonsContext
    = lerp_tween_polygons_context::LerpTweenPolygonsContext;
pub use LerpTweenPolygonsColorContext
    = lerp_tween_polygons_color_context::LerpTweenPolygonsColorContext;
pub use LineContext
    = line_context::LineContext;
pub use LineColorContext
    = line_color_context::LineColorContext;
pub use PolygonContext
    = polygon_context::PolygonContext;
pub use PolygonColorContext
    = polygon_color_context::PolygonColorContext;
pub use RectangleBorderContext
    = rectangle_border_context::RectangleBorderContext;
pub use RectangleBorderColorContext
    = rectangle_border_color_context::RectangleBorderColorContext;
pub use RectangleContext
    = rectangle_context::RectangleContext;
pub use RectangleColorContext
    = rectangle_color_context::RectangleColorContext;
pub use RelativeColor
    = relative_color::RelativeColor;
pub use RelativeRectangle
    = relative_rectangle::RelativeRectangle;
pub use RelativeSourceRectangle
    = relative_source_rectangle::RelativeSourceRectangle;
pub use RelativeTransform2d
    = relative_transform2d::RelativeTransform2d;
pub use RoundBorderLineContext
    = round_border_line_context::RoundBorderLineContext;
pub use RoundBorderLineColorContext
    = round_border_line_color_context::RoundBorderLineColorContext;
pub use RoundRectangleBorderColorContext
    = round_rectangle_border_color_context::RoundRectangleBorderColorContext;
pub use RoundRectangleBorderContext
    = round_rectangle_border_context::RoundRectangleBorderContext;
pub use RoundRectangleColorContext
    = round_rectangle_color_context::RoundRectangleColorContext;
pub use RoundRectangleContext
    = round_rectangle_context::RoundRectangleContext;
pub use SquareBorderLineColorContext
    = square_border_line_color_context::SquareBorderLineColorContext;
pub use SquareBorderLineContext
    = square_border_line_context::SquareBorderLineContext;
pub use View
    = view::View;

mod add_bevel;
mod add_bevel_border;
mod add_border;
mod add_color;
mod add_ellipse;
mod add_image;
mod add_line;
mod add_polygon;
mod add_polygons;
mod add_rectangle;
mod add_round;
mod add_round_border;
mod add_square_border;
mod add_tween;
mod back_end;
mod bevel_border_line_color_context;
mod bevel_border_line_context;
mod bevel_rectangle_border_color_context;
mod bevel_rectangle_border_context;
mod bevel_rectangle_color_context;
mod bevel_rectangle_context;
mod color_context;
mod context;
mod draw;
mod ellipse_border_context;
mod ellipse_border_color_context;
mod ellipse_color_context;
mod ellipse_context;
mod image_size;
mod image_context;
mod image_color_context;
mod image_rectangle_color_context;
mod image_rectangle_context;
mod line_color_context;
mod line_context;
mod polygon_color_context;
mod polygon_context;
mod rectangle_border_context;
mod rectangle_border_color_context;
mod rectangle_color_context;
mod rectangle_context;
mod relative_color;
mod relative_rectangle;
mod relative_source_rectangle;
mod relative_transform2d;
mod round_border_line_color_context;
mod round_border_line_context;
mod round_rectangle_border_color_context;
mod round_rectangle_border_context;
mod round_rectangle_color_context;
mod round_rectangle_context;
mod square_border_line_color_context;
mod square_border_line_context;
mod lerp_tween_color_context;
mod lerp_tween_context;
mod lerp_tween_polygons_color_context;
mod lerp_tween_polygons_context;
mod view;

pub mod internal;
pub mod interpolation;
pub mod modular_index;
pub mod triangulation;
pub mod vecmath;

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<T> {
    /// Contains a value.
    Value(T),
}

impl<T: Copy> Field<T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&self) -> T {
        match *self {
            Value(val) => val,
        }
    }
}

/* Uncomment when lifetime traits problem is solved.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(val) => val,
        }
    }
}
*/

<|endoftext|>


<commit_before>#![allow(clippy::non_ascii_literal)]

#[macro_use]
extern crate seed;

use seed::prelude::*;

pub mod pages;

#[derive(Copy, Clone)]
pub enum Page {
    ContactUs,
    Downloads,
    Faq,
    Home,
    Status,
    FermatArchive,
    FibonacciArchive,
    MersenneArchive,
    PerfectArchive,
    /*
    NumberCruncher,
    PrimalityChecker,
    PrimeNumbersArchive,
    MersennePrimeArchive,
    */
    //Article(article::slug::Slug),
}

// Model
struct Model {
    page: Page,
    slug: std::string::String,
}

// Setup a default here, for initialization later.
impl Default for Model {
    fn default() -> Self {
        Self {
            page: Page::Home,
            slug: "".to_owned(),
        }
    }
}

// Update
#[derive(Clone)]
pub enum Msg {
    ChangePage(Page, std::string::String),
}

/// The sole source of updating the model
fn update(msg: Msg, model: &mut Model, _: &mut Orders<Msg>) {
    match msg {
        Msg::ChangePage(page, slug) => {model.page = page; model.slug = slug}
    }
}

/// The top-level component we pass to the virtual dom. Must accept the model as its
/// only argument, and output has to implement trait `ElContainer`.
fn view(model: &Model) -> impl View<Msg> {
    match model.page {
        Page::ContactUs => pages::contact::render(),
        Page::Downloads => pages::downloads::render(),
        Page::Faq => pages::faq::render(),
        Page::FermatArchive => pages::archive::fermat::render(),
        Page::FibonacciArchive => pages::archive::fibonacci::render(model.slug.to_owned()),
        Page::Home => pages::home::render(),
        Page::MersenneArchive => pages::archive::mersenne::render(),
        Page::PerfectArchive => pages::archive::perfect::render(),
        Page::Status => pages::status::render(),
    }
}

impl ToString for Page {
    fn to_string(&self) -> String {
        // Eg for url routing
        match self {
            Page::ContactUs => "contactus".into(),
            Page::Downloads => "downloads".into(),
            Page::Faq => "faq".into(),
            Page::FermatArchive => "fermat".into(),
            Page::FibonacciArchive => "fibonacci".into(),//TODO: check this is right, might need the archive/ prefix!
            Page::Home => "home".into(),
            Page::Status => "status".into(),
            Page::MersenneArchive => "mersenne".into(),
            Page::PerfectArchive => "perfect".into(),
        }
    }
}

fn routes(url: seed::Url) -> Msg {

    let empty_string = "".to_owned();

    if url.path.is_empty() {
        return Msg::ChangePage(Page::Home, empty_string)
    }

    match url.path[0].as_ref() {
        "archive" => {
            // Determine if we are at the archive page, or a subpage
            match url.path[1].as_ref() {
                "fermat" => Msg::ChangePage(Page::FermatArchive, empty_string),
                "fibonacci" => {
                    match url.path.get(2).as_ref() {
                        Some(_slug) => Msg::ChangePage(Page::FibonacciArchive, url.path[2].to_owned()),
                        None => Msg::ChangePage(Page::FibonacciArchive, "1".to_owned()),
                    }
                },
                "mersenne" => Msg::ChangePage(Page::MersenneArchive, empty_string),
                "perfect" => Msg::ChangePage(Page::PerfectArchive, empty_string),
                _ => Msg::ChangePage(Page::Home, empty_string)//TODO: add archive page
            }
        },
        "contactus" => Msg::ChangePage(Page::ContactUs, empty_string),
        "downloads" => Msg::ChangePage(Page::Downloads, empty_string),
        "faq" => Msg::ChangePage(Page::Faq, empty_string),
        "status" => Msg::ChangePage(Page::Status, empty_string),
        _ => Msg::ChangePage(Page::Home, empty_string)
    }
}

#[wasm_bindgen(start)]
pub fn render() {
    seed::App::build(Model::default(), update, view)
        .mount("app")
        .routes(routes)
        //.window_events(window_events)
        .finish()
        .run();
}<commit_msg>Removed old page reminders<commit_after>#![allow(clippy::non_ascii_literal)]

#[macro_use]
extern crate seed;

use seed::prelude::*;

pub mod pages;

#[derive(Copy, Clone)]
pub enum Page {
    ContactUs,
    Downloads,
    Faq,
    Home,
    Status,
    FermatArchive,
    FibonacciArchive,
    MersenneArchive,
    PerfectArchive,
    /*
    NumberCruncher,
    PrimalityChecker,
    PrimeNumbersArchive,
    */
}

// Model
struct Model {
    page: Page,
    slug: std::string::String,
}

// Setup a default here, for initialization later.
impl Default for Model {
    fn default() -> Self {
        Self {
            page: Page::Home,
            slug: "".to_owned(),
        }
    }
}

// Update
#[derive(Clone)]
pub enum Msg {
    ChangePage(Page, std::string::String),
}

/// The sole source of updating the model
fn update(msg: Msg, model: &mut Model, _: &mut Orders<Msg>) {
    match msg {
        Msg::ChangePage(page, slug) => {model.page = page; model.slug = slug}
    }
}

/// The top-level component we pass to the virtual dom. Must accept the model as its
/// only argument, and output has to implement trait `ElContainer`.
fn view(model: &Model) -> impl View<Msg> {
    match model.page {
        Page::ContactUs => pages::contact::render(),
        Page::Downloads => pages::downloads::render(),
        Page::Faq => pages::faq::render(),
        Page::FermatArchive => pages::archive::fermat::render(),
        Page::FibonacciArchive => pages::archive::fibonacci::render(model.slug.to_owned()),
        Page::Home => pages::home::render(),
        Page::MersenneArchive => pages::archive::mersenne::render(),
        Page::PerfectArchive => pages::archive::perfect::render(),
        Page::Status => pages::status::render(),
    }
}

impl ToString for Page {
    fn to_string(&self) -> String {
        // Eg for url routing
        match self {
            Page::ContactUs => "contactus".into(),
            Page::Downloads => "downloads".into(),
            Page::Faq => "faq".into(),
            Page::FermatArchive => "fermat".into(),
            Page::FibonacciArchive => "fibonacci".into(),//TODO: check this is right, might need the archive/ prefix!
            Page::Home => "home".into(),
            Page::Status => "status".into(),
            Page::MersenneArchive => "mersenne".into(),
            Page::PerfectArchive => "perfect".into(),
        }
    }
}

fn routes(url: seed::Url) -> Msg {

    let empty_string = "".to_owned();

    if url.path.is_empty() {
        return Msg::ChangePage(Page::Home, empty_string)
    }

    match url.path[0].as_ref() {
        "archive" => {
            // Determine if we are at the archive page, or a subpage
            match url.path[1].as_ref() {
                "fermat" => Msg::ChangePage(Page::FermatArchive, empty_string),
                "fibonacci" => {
                    match url.path.get(2).as_ref() {
                        Some(_slug) => Msg::ChangePage(Page::FibonacciArchive, url.path[2].to_owned()),
                        None => Msg::ChangePage(Page::FibonacciArchive, "1".to_owned()),
                    }
                },
                "mersenne" => Msg::ChangePage(Page::MersenneArchive, empty_string),
                "perfect" => Msg::ChangePage(Page::PerfectArchive, empty_string),
                _ => Msg::ChangePage(Page::Home, empty_string)//TODO: add archive page
            }
        },
        "contactus" => Msg::ChangePage(Page::ContactUs, empty_string),
        "downloads" => Msg::ChangePage(Page::Downloads, empty_string),
        "faq" => Msg::ChangePage(Page::Faq, empty_string),
        "status" => Msg::ChangePage(Page::Status, empty_string),
        _ => Msg::ChangePage(Page::Home, empty_string)
    }
}

#[wasm_bindgen(start)]
pub fn render() {
    seed::App::build(Model::default(), update, view)
        .mount("app")
        .routes(routes)
        //.window_events(window_events)
        .finish()
        .run();
}<|endoftext|>


<commit_before>#![doc(html_root_url = "https://urschrei.github.io/polyline-ffi/")]
//! This module exposes functions for accessing the Polyline encoding and decoding functions via FFI
extern crate polyline;
use polyline::{encode_coordinates, decode_polyline};
use std::mem;
use std::slice;
use std::f64;
use std::ffi::{CStr, CString};

extern crate libc;
use self::libc::{c_char, c_void, uint32_t, size_t};

#[repr(C)]
pub struct Array {
    pub data: *const c_void,
    pub len: size_t,
}

// Build an Array from &[[f64; 2]], so it can be leaked across the FFI boundary
impl<'a> From<&'a [[f64; 2]]> for Array {
    fn from(sl: &'a [[f64; 2]]) -> Self {
        let array = Array {
            data: sl.as_ptr() as *const c_void,
            len: sl.len() as size_t,
        };
        mem::forget(sl);
        array
    }
}

// Build &[[f64; 2]] from an Array, so it can be dropped
impl<'a> From<Array> for &'a [[f64; 2]] {
    fn from(arr: Array) -> Self {
        unsafe { slice::from_raw_parts(arr.data as *const [f64; 2], arr.len) }
    }
}

// Decode a Polyline into an Array
fn arr_from_string(incoming: String, precision: uint32_t) -> Array {
    let result: Array = match decode_polyline(incoming, precision) {
        Ok(res) => res.as_slice().into(),
        // should be easy to check for
        Err(_) => vec![[f64::NAN, f64::NAN]].as_slice().into(),
    };
    result.into()
}

// Decode an Array into a Polyline
fn string_from_arr(incoming: Array, precision: uint32_t) -> String {
    match encode_coordinates(incoming.into(), precision) {
        Ok(res) => res,
        // we don't need to adapt the error
        Err(res) => res,
    }
}

/// Convert a Polyline into an array of coordinates
///
/// Callers must pass two arguments:
///
/// - a pointer to `NUL`-terminated characters (`char*`)
/// - an unsigned 32-bit `int` for precision (5 for Google Polylines, 6 for
/// OSRM and Valhalla Polylines)
///
/// # Examples
///
/// ```
/// use std::ffi::CString;
/// use std::slice;
/// let input = CString::new("_ibE_seK_seK_seK").unwrap().as_ptr();
/// let result: Array = decode_polyline_ffi(input, 5);
/// let slice = unsafe { slice::from_raw_parts(result.data as *const [f64; 2], result.len) };
/// assert_eq!(slice, [[1.0, 2.0], [3.0, 4.0]]);
/// drop_float_array(result);
/// ```
///
/// A decoding failure will always return an array: `[[NaN, NaN]]`
///
/// Implementations calling this function **must** call [`drop_float_array`](fn.drop_float_array.html)
/// with the returned [Array](struct.Array.html), in order to free the memory it allocates.
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn decode_polyline_ffi(pl: *const c_char, precision: uint32_t) -> Array {
    let s: String = unsafe { CStr::from_ptr(pl).to_string_lossy().into_owned() };
    arr_from_string(s, precision)
}

/// Convert an array of coordinates into a Polyline
///
/// Callers must pass two arguments:
///
/// - a [Struct](struct.Array.html) with two fields:
///     - `data`, a void pointer to an array of floating-point lat, lon coordinates: `[[1.0, 2.0]]`
///     - `len`, the length of the array being passed. Its type must be `size_t`: `1`
/// - an unsigned 32-bit `int` for precision (5 for Google Polylines, 6 for
/// OSRM and Valhalla Polylines)
///
/// # Examples
///
/// ```
/// extern crate libc;
/// use libc::{c_void, size_t};
/// use std::ffi::CStr;
/// use std::slice;
/// let input = vec![[1.0, 2.0], [3.0, 4.0]].as_slice();
/// let array = Array { data: input.as_ptr() as *const c_void, len: input.len() as size_t };
/// let output = "_ibE_seK_seK_seK".to_string();
/// let pl = encode_coordinates_ffi(array, 5);
/// let result = unsafe { CStr::from_ptr(pl).to_str().unwrap() };
/// assert_eq!(result, output);
/// drop_cstring(pl);
/// ```
///
/// A decoding failure will always return a string: "Couldn't decode Polyline"
///
/// Implementations calling this function **must** call [`drop_cstring`](fn.drop_cstring.html)
/// with the returned `c_char` pointer, in order to free the memory it allocates.
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn encode_coordinates_ffi(coords: Array, precision: uint32_t) -> *mut c_char {
    let s: String = string_from_arr(coords, precision);
    match CString::new(s) {
        Ok(res) => res.into_raw(),
        // It's arguably better to fail noisily, but this is robust
        Err(_) => CString::new("Couldn't decode Polyline".to_string()).unwrap().into_raw(),
    }
}

/// Free Array memory which Rust has allocated across the FFI boundary
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn drop_float_array(arr: Array) {
    if arr.data.is_null() {
        return;
    }
    let _: &[[f64; 2]] = arr.into();
}

/// Free `CString` memory which Rust has allocated across the FFI boundary
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn drop_cstring(p: *mut c_char) {
    let _ = unsafe { CString::from_raw(p) };
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::ptr;
    use std::ffi::{CString, CStr};

    #[test]
    fn test_array_conversion() {
        let original = vec![[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]];
        // move into an Array, and leak it
        let arr: Array = original.as_slice().into();
        // move back into an slice -- leaked value still needs to be dropped
        let converted: &[[f64; 2]] = arr.into();
        assert_eq!(converted, &[[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]);
        // drop it
        drop_float_array(converted.into());
    }

    #[test]
    fn test_drop_empty_float_array() {
        let original = vec![[1.0, 2.0], [3.0, 4.0]];
        // move into an Array, and leak it
        let mut arr: Array = original.as_slice().into();
        // zero Array contents
        arr.data = ptr::null();
        drop_float_array(arr);
    }

    #[test]
    fn test_coordinate_conversion() {
        let input = vec![[1.0, 2.0], [3.0, 4.0]];
        let output = "_ibE_seK_seK_seK";
        let input_arr: Array = input.as_slice().into();
        let transformed: String = super::string_from_arr(input_arr, 5);
        assert_eq!(transformed, output);
    }

    #[test]
    fn test_string_conversion() {
        let input = "_ibE_seK_seK_seK".to_string();
        let output = [[1.0, 2.0], [3.0, 4.0]];
        // String to Array
        let transformed: Array = super::arr_from_string(input, 5);
        // Array to Vec
        let transformed_arr: &[[f64; 2]] = transformed.into();
        assert_eq!(transformed_arr, output);
    }

    #[test]
    #[should_panic]
    fn test_bad_string_conversion() {
        let input = "_p~iF~ps|U_u🗑lLnnqC_mqNvxq`@".to_string();
        let output = vec![[1.0, 2.0], [3.0, 4.0]];
        // String to Array
        let transformed: Array = super::arr_from_string(input, 5);
        // Array to Vec
        let transformed_arr: &[[f64; 2]] = transformed.into();
        // this will fail, bc transformed_arr is [[NaN, NaN]]
        assert_eq!(transformed_arr, output.as_slice());
    }

    #[test]
    fn test_ffi_polyline_decoding() {
        let input = CString::new("_ibE_seK_seK_seK").unwrap().as_ptr();
        let result: &[[f64; 2]] = decode_polyline_ffi(input, 5).into();
        assert_eq!(result, [[1.0, 2.0], [3.0, 4.0]]);
        drop_float_array(result.into());
    }

    #[test]
    fn test_ffi_coordinate_encoding() {
        let input: Array = vec![[1.0, 2.0], [3.0, 4.0]].as_slice().into();
        let output = "_ibE_seK_seK_seK".to_string();
        let pl = encode_coordinates_ffi(input, 5);
        // Allocate a new String
        let result = unsafe { CStr::from_ptr(pl).to_str().unwrap() };
        assert_eq!(result, output);
        // Drop received FFI data
        drop_cstring(pl);
    }

    #[test]
    fn test_long_running() {
        let input = CString::new("_ibE_seK_seK_seK").unwrap().as_ptr();
        for _ in 0..100 {
            let result: &[[f64; 2]] = decode_polyline_ffi(input, 5).into();
            assert_eq!(result, [[1.0, 2.0], [3.0, 4.0]]);
            drop_float_array(result.into());
        }

    }
}
<commit_msg>Remove nonsense test for now<commit_after>#![doc(html_root_url = "https://urschrei.github.io/polyline-ffi/")]
//! This module exposes functions for accessing the Polyline encoding and decoding functions via FFI
extern crate polyline;
use polyline::{encode_coordinates, decode_polyline};
use std::mem;
use std::slice;
use std::f64;
use std::ffi::{CStr, CString};

extern crate libc;
use self::libc::{c_char, c_void, uint32_t, size_t};

#[repr(C)]
pub struct Array {
    pub data: *const c_void,
    pub len: size_t,
}

// Build an Array from &[[f64; 2]], so it can be leaked across the FFI boundary
impl<'a> From<&'a [[f64; 2]]> for Array {
    fn from(sl: &'a [[f64; 2]]) -> Self {
        let array = Array {
            data: sl.as_ptr() as *const c_void,
            len: sl.len() as size_t,
        };
        mem::forget(sl);
        array
    }
}

// Build &[[f64; 2]] from an Array, so it can be dropped
impl<'a> From<Array> for &'a [[f64; 2]] {
    fn from(arr: Array) -> Self {
        unsafe { slice::from_raw_parts(arr.data as *const [f64; 2], arr.len) }
    }
}

// Decode a Polyline into an Array
fn arr_from_string(incoming: String, precision: uint32_t) -> Array {
    let result: Array = match decode_polyline(incoming, precision) {
        Ok(res) => res.as_slice().into(),
        // should be easy to check for
        Err(_) => vec![[f64::NAN, f64::NAN]].as_slice().into(),
    };
    result.into()
}

// Decode an Array into a Polyline
fn string_from_arr(incoming: Array, precision: uint32_t) -> String {
    match encode_coordinates(incoming.into(), precision) {
        Ok(res) => res,
        // we don't need to adapt the error
        Err(res) => res,
    }
}

/// Convert a Polyline into an array of coordinates
///
/// Callers must pass two arguments:
///
/// - a pointer to `NUL`-terminated characters (`char*`)
/// - an unsigned 32-bit `int` for precision (5 for Google Polylines, 6 for
/// OSRM and Valhalla Polylines)
///
/// # Examples
///
/// ```
/// use std::ffi::CString;
/// use std::slice;
/// let input = CString::new("_ibE_seK_seK_seK").unwrap().as_ptr();
/// let result: Array = decode_polyline_ffi(input, 5);
/// let slice = unsafe { slice::from_raw_parts(result.data as *const [f64; 2], result.len) };
/// assert_eq!(slice, [[1.0, 2.0], [3.0, 4.0]]);
/// drop_float_array(result);
/// ```
///
/// A decoding failure will always return an array: `[[NaN, NaN]]`
///
/// Implementations calling this function **must** call [`drop_float_array`](fn.drop_float_array.html)
/// with the returned [Array](struct.Array.html), in order to free the memory it allocates.
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn decode_polyline_ffi(pl: *const c_char, precision: uint32_t) -> Array {
    let s: String = unsafe { CStr::from_ptr(pl).to_string_lossy().into_owned() };
    arr_from_string(s, precision)
}

/// Convert an array of coordinates into a Polyline
///
/// Callers must pass two arguments:
///
/// - a [Struct](struct.Array.html) with two fields:
///     - `data`, a void pointer to an array of floating-point lat, lon coordinates: `[[1.0, 2.0]]`
///     - `len`, the length of the array being passed. Its type must be `size_t`: `1`
/// - an unsigned 32-bit `int` for precision (5 for Google Polylines, 6 for
/// OSRM and Valhalla Polylines)
///
/// # Examples
///
/// ```
/// extern crate libc;
/// use libc::{c_void, size_t};
/// use std::ffi::CStr;
/// use std::slice;
/// let input = vec![[1.0, 2.0], [3.0, 4.0]].as_slice();
/// let array = Array { data: input.as_ptr() as *const c_void, len: input.len() as size_t };
/// let output = "_ibE_seK_seK_seK".to_string();
/// let pl = encode_coordinates_ffi(array, 5);
/// let result = unsafe { CStr::from_ptr(pl).to_str().unwrap() };
/// assert_eq!(result, output);
/// drop_cstring(pl);
/// ```
///
/// A decoding failure will always return a string: "Couldn't decode Polyline"
///
/// Implementations calling this function **must** call [`drop_cstring`](fn.drop_cstring.html)
/// with the returned `c_char` pointer, in order to free the memory it allocates.
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn encode_coordinates_ffi(coords: Array, precision: uint32_t) -> *mut c_char {
    let s: String = string_from_arr(coords, precision);
    match CString::new(s) {
        Ok(res) => res.into_raw(),
        // It's arguably better to fail noisily, but this is robust
        Err(_) => CString::new("Couldn't decode Polyline".to_string()).unwrap().into_raw(),
    }
}

/// Free Array memory which Rust has allocated across the FFI boundary
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn drop_float_array(arr: Array) {
    if arr.data.is_null() {
        return;
    }
    let _: &[[f64; 2]] = arr.into();
}

/// Free `CString` memory which Rust has allocated across the FFI boundary
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn drop_cstring(p: *mut c_char) {
    let _ = unsafe { CString::from_raw(p) };
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::ptr;
    use std::ffi::{CString, CStr};

    #[test]
    fn test_array_conversion() {
        let original = vec![[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]];
        // move into an Array, and leak it
        let arr: Array = original.as_slice().into();
        // move back into an slice -- leaked value still needs to be dropped
        let converted: &[[f64; 2]] = arr.into();
        assert_eq!(converted, &[[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]);
        // drop it
        drop_float_array(converted.into());
    }

    #[test]
    fn test_drop_empty_float_array() {
        let original = vec![[1.0, 2.0], [3.0, 4.0]];
        // move into an Array, and leak it
        let mut arr: Array = original.as_slice().into();
        // zero Array contents
        arr.data = ptr::null();
        drop_float_array(arr);
    }

    #[test]
    fn test_coordinate_conversion() {
        let input = vec![[1.0, 2.0], [3.0, 4.0]];
        let output = "_ibE_seK_seK_seK";
        let input_arr: Array = input.as_slice().into();
        let transformed: String = super::string_from_arr(input_arr, 5);
        assert_eq!(transformed, output);
    }

    #[test]
    fn test_string_conversion() {
        let input = "_ibE_seK_seK_seK".to_string();
        let output = [[1.0, 2.0], [3.0, 4.0]];
        // String to Array
        let transformed: Array = super::arr_from_string(input, 5);
        // Array to Vec
        let transformed_arr: &[[f64; 2]] = transformed.into();
        assert_eq!(transformed_arr, output);
    }

    #[test]
    #[should_panic]
    fn test_bad_string_conversion() {
        let input = "_p~iF~ps|U_u🗑lLnnqC_mqNvxq`@".to_string();
        let output = vec![[1.0, 2.0], [3.0, 4.0]];
        // String to Array
        let transformed: Array = super::arr_from_string(input, 5);
        // Array to Vec
        let transformed_arr: &[[f64; 2]] = transformed.into();
        // this will fail, bc transformed_arr is [[NaN, NaN]]
        assert_eq!(transformed_arr, output.as_slice());
    }

    #[test]
    fn test_ffi_polyline_decoding() {
        let input = CString::new("_ibE_seK_seK_seK").unwrap().as_ptr();
        let result: &[[f64; 2]] = decode_polyline_ffi(input, 5).into();
        assert_eq!(result, [[1.0, 2.0], [3.0, 4.0]]);
        drop_float_array(result.into());
    }

    #[test]
    fn test_ffi_coordinate_encoding() {
        let input: Array = vec![[1.0, 2.0], [3.0, 4.0]].as_slice().into();
        let output = "_ibE_seK_seK_seK".to_string();
        let pl = encode_coordinates_ffi(input, 5);
        // Allocate a new String
        let result = unsafe { CStr::from_ptr(pl).to_str().unwrap() };
        assert_eq!(result, output);
        // Drop received FFI data
        drop_cstring(pl);
    }

    // #[test]
    // fn test_long_running() {
    //     let input: Array = vec![[1.0, 2.0], [3.0, 4.0]].as_slice().into();
    //     for _ in 0..100 {
    //         let result: &[[f64; 2]] = decode_polyline_ffi(input, 5).into();
    //         assert_eq!(result, [[1.0, 2.0], [3.0, 4.0]]);
    //         drop_float_array(result.into());
    //     }

    // }
}
<|endoftext|>


<commit_before>//! Struct and methods for union-find operation.

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

use std::mem;

#[deriving(Clone)]
enum UFNode {
    Key(uint),
    Size(uint)
}

/// Struct for union-find operation.
pub struct UnionFind {
    data: Vec<UFNode>
}

impl UnionFind {
    /// Creates empty `UnionFind` struct.
    #[inline]
    pub fn new(len: uint) -> UnionFind { UnionFind { data: Vec::from_elem(len, UFNode::Size(1)) } }

    /// Join two sets that contains given keys (Union operation).
    ///
    /// Returns `true` if these keys are belonged to different sets.
    pub fn union(&mut self, key1: uint, key2: uint) -> bool {
        let (key1, size1) = self.get_key_size(key1);
        let (key2, size2) = self.get_key_size(key2);
        if key1 == key2 { return false; }

        let mut key1 = key1; let mut size1 = size1;
        let mut key2 = key2; let mut size2 = size2;

        if size1 < size2 {
            mem::swap(&mut key1, &mut key2);
            mem::swap(&mut size1, &mut size2);
        }

        self.data[key1] = UFNode::Size(size1 + size2);
        self.data[key2] = UFNode::Key(key1);

        return true;
    }

    /// Returns `true` if two keys contained by the same set (find operation).
    #[inline]
    pub fn find(&mut self, key1: uint, key2: uint) -> bool {
        return self.get_key(key1) == self.get_key(key2);
    }

    /// Returns the number of the elements that belongs to the same set with key.
    #[inline]
    pub fn get_size(&mut self, key: uint) -> uint {
        self.get_key_size(key).1
    }

    fn get_key(&mut self, key: uint) -> uint {
        self.get_key_size(key).0
    }

    fn get_key_size(&mut self, key: uint) -> (uint, uint) {
        let (root_key, size) = match self.data[key] {
            UFNode::Size(size) => { return (key, size); }
            UFNode::Key(key) => self.get_key_size(key)
        };
        self.data[key] = UFNode::Key(root_key);
        return (root_key, size);
    }
}

#[test]
fn test_union_find() {
    let mut uf = UnionFind::new(100);
    assert_eq!(uf.get_size(0), 1);
    assert_eq!(uf.get_size(1), 1);
    assert!(!uf.find(0, 1));
    assert!(!uf.find(1, 2));
    assert!(uf.union(0, 1));
    assert!(uf.find(0, 1));
    assert_eq!(uf.get_size(0), 2);
    assert_eq!(uf.get_size(1), 2);
    assert_eq!(uf.get_size(2), 1);
    assert!(!uf.union(0, 1));
    assert_eq!(uf.get_size(0), 2);
    assert_eq!(uf.get_size(1), 2);
    assert_eq!(uf.get_size(2), 1);
    assert!(uf.union(1, 2));
    assert_eq!(uf.get_size(0), 3);
    assert_eq!(uf.get_size(1), 3);
    assert_eq!(uf.get_size(2), 3);
    assert!(uf.find(0, 1));
    assert!(uf.find(2, 1));
}
<commit_msg>fix deprecation warnings<commit_after>//! Struct and methods for union-find operation.

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

use std::{iter, mem};

#[deriving(Clone)]
enum UFNode {
    Key(uint),
    Size(uint)
}

/// Struct for union-find operation.
pub struct UnionFind {
    data: Vec<UFNode>
}

impl UnionFind {
    /// Creates empty `UnionFind` struct.
    #[inline]
    pub fn new(len: uint) -> UnionFind {
        UnionFind { data: iter::repeat(UFNode::Size(1)).take(len).collect() }
    }

    /// Join two sets that contains given keys (Union operation).
    ///
    /// Returns `true` if these keys are belonged to different sets.
    pub fn union(&mut self, key1: uint, key2: uint) -> bool {
        let (key1, size1) = self.get_key_size(key1);
        let (key2, size2) = self.get_key_size(key2);
        if key1 == key2 { return false; }

        let mut key1 = key1; let mut size1 = size1;
        let mut key2 = key2; let mut size2 = size2;

        if size1 < size2 {
            mem::swap(&mut key1, &mut key2);
            mem::swap(&mut size1, &mut size2);
        }

        self.data[key1] = UFNode::Size(size1 + size2);
        self.data[key2] = UFNode::Key(key1);

        return true;
    }

    /// Returns `true` if two keys contained by the same set (find operation).
    #[inline]
    pub fn find(&mut self, key1: uint, key2: uint) -> bool {
        return self.get_key(key1) == self.get_key(key2);
    }

    /// Returns the number of the elements that belongs to the same set with key.
    #[inline]
    pub fn get_size(&mut self, key: uint) -> uint {
        self.get_key_size(key).1
    }

    fn get_key(&mut self, key: uint) -> uint {
        self.get_key_size(key).0
    }

    fn get_key_size(&mut self, key: uint) -> (uint, uint) {
        let (root_key, size) = match self.data[key] {
            UFNode::Size(size) => { return (key, size); }
            UFNode::Key(key) => self.get_key_size(key)
        };
        self.data[key] = UFNode::Key(root_key);
        return (root_key, size);
    }
}

#[test]
fn test_union_find() {
    let mut uf = UnionFind::new(100);
    assert_eq!(uf.get_size(0), 1);
    assert_eq!(uf.get_size(1), 1);
    assert!(!uf.find(0, 1));
    assert!(!uf.find(1, 2));
    assert!(uf.union(0, 1));
    assert!(uf.find(0, 1));
    assert_eq!(uf.get_size(0), 2);
    assert_eq!(uf.get_size(1), 2);
    assert_eq!(uf.get_size(2), 1);
    assert!(!uf.union(0, 1));
    assert_eq!(uf.get_size(0), 2);
    assert_eq!(uf.get_size(1), 2);
    assert_eq!(uf.get_size(2), 1);
    assert!(uf.union(1, 2));
    assert_eq!(uf.get_size(0), 3);
    assert_eq!(uf.get_size(1), 3);
    assert_eq!(uf.get_size(2), 3);
    assert!(uf.find(0, 1));
    assert!(uf.find(2, 1));
}
<|endoftext|>


<commit_before>//! redis-rs is a rust implementation of a Redis client library.  It exposes
//! a general purpose interface to Redis and also provides specific helpers for
//! commonly used functionality.
//!
//! The crate is called `redis` and you can depend on it via cargo:
//!
//! ```ini
//! [dependencies.redis]
//! version = "*"
//! ```
//!
//! If you want to use the git version:
//!
//! ```ini
//! [dependencies.redis]
//! git = "https://github.com/mitsuhiko/redis-rs.git"
//! ```
//!
//! # Basic Operation
//!
//! redis-rs exposes to API levels: a low- and a high-level part.  The high-level
//! part does not expose all the functionality of redis and might take some
//! liberties in how it speaks the protocol.  The low-level part of the API
//! allows you to express any request on the redis level.  You can fluently
//! switch between both API levels at any point.
//!
//! ## Connection Handling
//!
//! For connecting to redis you can use a client object which then can produce
//! actual connections.  Connections and clients as well as results of
//! connections and clients are considered `ConnectionLike` objects and
//! can be used anywhere a request is made.
//!
//! The full canonical way to get a connection is to create a client and
//! to ask for a connection from it:
//!
//! ```rust,no_run
//! extern crate redis;
//!
//! fn do_something() -> redis::RedisResult<()> {
//!     let client = try!(redis::Client::open("redis://127.0.0.1/"));
//!     let con = try!(client.get_connection());
//!
//!     /* do something here */
//!
//!     Ok(())
//! }
//! # fn main() {}
//! ```
//!
//! ## Optional Features
//!
//! There are currently two features defined that can enable additional
//! functionality if so desired.
//!
//! `with-unix-sockets`:
//!   By default this library does not support unix sockets on older versions
//!   of Rust but you can optionally compile it with unix sockets enabled by
//!   enabling the `with-unix-sockets` feature flag.  On rust 1.10 or later
//!   this is not needed.
//!
//! `with-rustc-json`:
//!   This feature flag enables the `rustc_serialize` JSON support.
//!
//! ## Connection Parameters
//!
//! redis-rs knows different ways to define where a connection should
//! go.  The parameter to `Client::open` needs to implement the
//! `IntoConnectionInfo` trait of which there are three implementations:
//!
//! * string slices in `redis://` URL format.
//! * URL objects from the redis-url crate.
//! * `ConnectionInfo` objects.
//!
//! The URL format is `redis://[:<passwd>@]<hostname>[:port][/<db>]`
//!
//! In case the create is compiled with Unix socket support you can also
//! use a unix URL in this format:
//!
//! `redis+unix:///[:<passwd>@]<path>[?db=<db>]`
//!
//! For compatibility with some other redis libraries, the "unix" scheme
//! is also supported:
//!
//! `unix:///[:<passwd>@]<path>[?db=<db>]`
//!
//! ## Executing Low-Level Commands
//!
//! To execute low-level commands you can use the `cmd` function which allows
//! you to build redis requests.  Once you have configured a command object
//! to your liking you can send a query into any `ConnectionLike` object:
//!
//! ```rust,no_run
//! fn do_something(con: &redis::Connection) -> redis::RedisResult<()> {
//!     let _ : () = try!(redis::cmd("SET").arg("my_key").arg(42).query(con));
//!     Ok(())
//! }
//! ```
//!
//! Upon querying the return value is a result object.  If you do not care
//! about the actual return value (other than that it is not a failure)
//! you can always type annotate it to the unit type `()`.
//!
//! ## Executing High-Level Commands
//!
//! The high-level interface is similar.  For it to become available you
//! need to use the `Commands` trait in which case all `ConnectionLike`
//! objects the library provides will also have high-level methods which
//! make working with the protocol easier:
//!
//! ```rust,no_run
//! extern crate redis;
//! use redis::Commands;
//!
//! fn do_something(con: &redis::Connection) -> redis::RedisResult<()> {
//!     let _ : () = try!(con.set("my_key", 42));
//!     Ok(())
//! }
//! # fn main() {}
//! ```
//!
//! Note that high-level commands are work in progress and many are still
//! missing!
//!
//! ## Type Conversions
//!
//! Because redis inherently is mostly type-less and the protocol is not
//! exactly friendly to developers, this library provides flexible support
//! for casting values to the intended results.  This is driven through the
//! `FromRedisValue` and `ToRedisArgs` traits.
//!
//! The `arg` method of the command will accept a wide range of types through
//! the `ToRedisArgs` trait and the `query` method of a command can convert the
//! value to what you expect the function to return through the `FromRedisValue`
//! trait.  This is quite flexible and allows vectors, tuples, hashsets, hashmaps
//! as well as optional values:
//!
//! ```rust,no_run
//! # use redis::Commands;
//! # use std::collections::{HashMap, HashSet};
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let count : i32 = try!(con.get("my_counter"));
//! let count = con.get("my_counter").unwrap_or(0i32);
//! let k : Option<String> = try!(con.get("missing_key"));
//! let name : String = try!(con.get("my_name"));
//! let bin : Vec<u8> = try!(con.get("my_binary"));
//! let map : HashMap<String, i32> = try!(con.hgetall("my_hash"));
//! let keys : Vec<String> = try!(con.hkeys("my_hash"));
//! let mems : HashSet<i32> = try!(con.smembers("my_set"));
//! let (k1, k2) : (String, String) = try!(con.get(&["k1", "k2"]));
//! # Ok(())
//! # }
//! ```
//!
//! # Iteration Protocol
//!
//! In addition to sending a single query you iterators are also supported.  When
//! used with regular bulk responses they don't give you much over querying and
//! converting into a vector (both use a vector internally) but they can also
//! be used with `SCAN` like commands in which case iteration will send more
//! queries until the cursor is exhausted:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let mut iter : redis::Iter<isize> = try!(redis::cmd("SSCAN").arg("my_set")
//!     .cursor_arg(0).iter(&con));
//! for x in iter {
//!     // do something with the item
//! }
//! # Ok(()) }
//! ```
//!
//! As you can see the cursor argument needs to be defined with `cursor_arg`
//! instead of `arg` so that the library knows which argument needs updating
//! as the query is run for more items.
//!
//! # Pipelining
//!
//! In addition to simple queries you can also send command pipelines.  This
//! is provided through the `pipe` function.  It works very similar to sending
//! individual commands but you can send more than one in one go.  This also
//! allows you to ignore individual results so that matching on the end result
//! is easier:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = try!(redis::pipe()
//!     .cmd("SET").arg("key_1").arg(42).ignore()
//!     .cmd("SET").arg("key_2").arg(43).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con));
//! # Ok(()) }
//! ```
//!
//! If you want the pipeline to be wrapped in a `MULTI`/`EXEC` block you can
//! easily do that by switching the pipeline into `atomic` mode.  From the
//! caller's point of view nothing changes, the pipeline itself will take
//! care of the rest for you:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = try!(redis::pipe()
//!     .atomic()
//!     .cmd("SET").arg("key_1").arg(42).ignore()
//!     .cmd("SET").arg("key_2").arg(43).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con));
//! # Ok(()) }
//! ```
//!
//! You can also use high-level commands on pipelines through the
//! `PipelineCommands` trait:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! use redis::PipelineCommands;
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = try!(redis::pipe()
//!     .atomic()
//!     .set("key_1", 42).ignore()
//!     .set("key_2", 43).ignore()
//!     .get("key_1")
//!     .get("key_2").query(&con));
//! # Ok(()) }
//! ```
//!
//! # Transactions
//!
//! Transactions are available through atomic pipelines.  In order to use
//! them in a more simple way you can use the `transaction` function of a
//! connection:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! use redis::{Commands, PipelineCommands};
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let key = "the_key";
//! let (new_val,) : (isize,) = try!(redis::transaction(&con, &[key], |pipe| {
//!     let old_val : isize = try!(con.get(key));
//!     pipe
//!         .set(key, old_val + 1).ignore()
//!         .get(key).query(&con)
//! }));
//! println!("The incremented number is: {}", new_val);
//! # Ok(()) }
//! ```
//!
//! For more information see the `transaction` function.
//!
//! # PubSub
//!
//! Pubsub is currently work in progress but provided through the `PubSub`
//! connection object.  Due to the fact that Rust does not have support
//! for async IO in libnative yet, the API does not provide a way to
//! read messages with any form of timeout yet.
//!
//! Example usage:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! let client = try!(redis::Client::open("redis://127.0.0.1/"));
//! let mut pubsub = try!(client.get_pubsub());
//! try!(pubsub.subscribe("channel_1"));
//! try!(pubsub.subscribe("channel_2"));
//!
//! loop {
//!     let msg = try!(pubsub.get_message());
//!     let payload : String = try!(msg.get_payload());
//!     println!("channel '{}': {}", msg.get_channel_name(), payload);
//! }
//! # }
//! ```
//!
//! # Scripts
//!
//! Lua scripts are supported through the `Script` type in a convenient
//! way (it does not support pipelining currently).  It will automatically
//! load the script if it does not exist and invoke it.
//!
//! Example:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let script = redis::Script::new(r"
//!     return tonumber(ARGV[1]) + tonumber(ARGV[2]);
//! ");
//! let result : isize = try!(script.arg(1).arg(2).invoke(&con));
//! assert_eq!(result, 3);
//! # Ok(()) }
//! ```
//!
//! ## Breaking Changes
//!
//! In Rust 0.5.0 the semi-internal `ConnectionInfo` struct had to be
//! changed because of the unix socket support.  You are generally
//! heavily encouraged to use the URL based configuration format which
//! is a lot more stable than the structs.

#![deny(non_camel_case_types)]

extern crate url;
extern crate sha1;

#[cfg(feature="with-rustc-json")]
pub extern crate rustc_serialize as serialize;
#[cfg(feature="with-unix-sockets")]
extern crate unix_socket;

#[doc(hidden)]
#[cfg(feature="with-rustc-json")]
pub use serialize::json::Json;

// public api
pub use parser::{parse_redis_value, Parser};
pub use client::Client;
pub use script::{Script, ScriptInvocation};
pub use connection::{Connection, ConnectionLike, ConnectionInfo, ConnectionAddr,
                     IntoConnectionInfo, PubSub, Msg, transaction, parse_redis_url};
pub use cmd::{cmd, Cmd, pipe, Pipeline, Iter, pack_command};
pub use commands::{Commands, PipelineCommands};

pub use types::{
    /* low level values */
    Value,

    /* error and result types */
    RedisError,
    RedisResult,

    /* error kinds */
    ErrorKind,

    /* utility types */
    InfoDict,
    NumericBehavior,

    /* conversion traits */
    FromRedisValue,
    ToRedisArgs,

    /* utility functions */
    from_redis_value,
};

mod macros;

mod parser;
mod client;
mod connection;
mod types;
mod script;
mod cmd;
mod commands;
<commit_msg>Fixed spelling<commit_after>//! redis-rs is a rust implementation of a Redis client library.  It exposes
//! a general purpose interface to Redis and also provides specific helpers for
//! commonly used functionality.
//!
//! The crate is called `redis` and you can depend on it via cargo:
//!
//! ```ini
//! [dependencies.redis]
//! version = "*"
//! ```
//!
//! If you want to use the git version:
//!
//! ```ini
//! [dependencies.redis]
//! git = "https://github.com/mitsuhiko/redis-rs.git"
//! ```
//!
//! # Basic Operation
//!
//! redis-rs exposes two API levels: a low- and a high-level part.
//! The high-level part does not expose all the functionality of redis and
//! might take some liberties in how it speaks the protocol.  The low-level
//! part of the API allows you to express any request on the redis level.
//! You can fluently switch between both API levels at any point.
//!
//! ## Connection Handling
//!
//! For connecting to redis you can use a client object which then can produce
//! actual connections.  Connections and clients as well as results of
//! connections and clients are considered `ConnectionLike` objects and
//! can be used anywhere a request is made.
//!
//! The full canonical way to get a connection is to create a client and
//! to ask for a connection from it:
//!
//! ```rust,no_run
//! extern crate redis;
//!
//! fn do_something() -> redis::RedisResult<()> {
//!     let client = try!(redis::Client::open("redis://127.0.0.1/"));
//!     let con = try!(client.get_connection());
//!
//!     /* do something here */
//!
//!     Ok(())
//! }
//! # fn main() {}
//! ```
//!
//! ## Optional Features
//!
//! There are currently two features defined that can enable additional
//! functionality if so desired.
//!
//! `with-unix-sockets`:
//!   By default this library does not support unix sockets on older versions
//!   of Rust but you can optionally compile it with unix sockets enabled by
//!   enabling the `with-unix-sockets` feature flag.  On rust 1.10 or later
//!   this is not needed.
//!
//! `with-rustc-json`:
//!   This feature flag enables the `rustc_serialize` JSON support.
//!
//! ## Connection Parameters
//!
//! redis-rs knows different ways to define where a connection should
//! go.  The parameter to `Client::open` needs to implement the
//! `IntoConnectionInfo` trait of which there are three implementations:
//!
//! * string slices in `redis://` URL format.
//! * URL objects from the redis-url crate.
//! * `ConnectionInfo` objects.
//!
//! The URL format is `redis://[:<passwd>@]<hostname>[:port][/<db>]`
//!
//! In case the create is compiled with Unix socket support you can also
//! use a unix URL in this format:
//!
//! `redis+unix:///[:<passwd>@]<path>[?db=<db>]`
//!
//! For compatibility with some other redis libraries, the "unix" scheme
//! is also supported:
//!
//! `unix:///[:<passwd>@]<path>[?db=<db>]`
//!
//! ## Executing Low-Level Commands
//!
//! To execute low-level commands you can use the `cmd` function which allows
//! you to build redis requests.  Once you have configured a command object
//! to your liking you can send a query into any `ConnectionLike` object:
//!
//! ```rust,no_run
//! fn do_something(con: &redis::Connection) -> redis::RedisResult<()> {
//!     let _ : () = try!(redis::cmd("SET").arg("my_key").arg(42).query(con));
//!     Ok(())
//! }
//! ```
//!
//! Upon querying the return value is a result object.  If you do not care
//! about the actual return value (other than that it is not a failure)
//! you can always type annotate it to the unit type `()`.
//!
//! ## Executing High-Level Commands
//!
//! The high-level interface is similar.  For it to become available you
//! need to use the `Commands` trait in which case all `ConnectionLike`
//! objects the library provides will also have high-level methods which
//! make working with the protocol easier:
//!
//! ```rust,no_run
//! extern crate redis;
//! use redis::Commands;
//!
//! fn do_something(con: &redis::Connection) -> redis::RedisResult<()> {
//!     let _ : () = try!(con.set("my_key", 42));
//!     Ok(())
//! }
//! # fn main() {}
//! ```
//!
//! Note that high-level commands are work in progress and many are still
//! missing!
//!
//! ## Type Conversions
//!
//! Because redis inherently is mostly type-less and the protocol is not
//! exactly friendly to developers, this library provides flexible support
//! for casting values to the intended results.  This is driven through the
//! `FromRedisValue` and `ToRedisArgs` traits.
//!
//! The `arg` method of the command will accept a wide range of types through
//! the `ToRedisArgs` trait and the `query` method of a command can convert the
//! value to what you expect the function to return through the `FromRedisValue`
//! trait.  This is quite flexible and allows vectors, tuples, hashsets, hashmaps
//! as well as optional values:
//!
//! ```rust,no_run
//! # use redis::Commands;
//! # use std::collections::{HashMap, HashSet};
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let count : i32 = try!(con.get("my_counter"));
//! let count = con.get("my_counter").unwrap_or(0i32);
//! let k : Option<String> = try!(con.get("missing_key"));
//! let name : String = try!(con.get("my_name"));
//! let bin : Vec<u8> = try!(con.get("my_binary"));
//! let map : HashMap<String, i32> = try!(con.hgetall("my_hash"));
//! let keys : Vec<String> = try!(con.hkeys("my_hash"));
//! let mems : HashSet<i32> = try!(con.smembers("my_set"));
//! let (k1, k2) : (String, String) = try!(con.get(&["k1", "k2"]));
//! # Ok(())
//! # }
//! ```
//!
//! # Iteration Protocol
//!
//! In addition to sending a single query you iterators are also supported.  When
//! used with regular bulk responses they don't give you much over querying and
//! converting into a vector (both use a vector internally) but they can also
//! be used with `SCAN` like commands in which case iteration will send more
//! queries until the cursor is exhausted:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let mut iter : redis::Iter<isize> = try!(redis::cmd("SSCAN").arg("my_set")
//!     .cursor_arg(0).iter(&con));
//! for x in iter {
//!     // do something with the item
//! }
//! # Ok(()) }
//! ```
//!
//! As you can see the cursor argument needs to be defined with `cursor_arg`
//! instead of `arg` so that the library knows which argument needs updating
//! as the query is run for more items.
//!
//! # Pipelining
//!
//! In addition to simple queries you can also send command pipelines.  This
//! is provided through the `pipe` function.  It works very similar to sending
//! individual commands but you can send more than one in one go.  This also
//! allows you to ignore individual results so that matching on the end result
//! is easier:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = try!(redis::pipe()
//!     .cmd("SET").arg("key_1").arg(42).ignore()
//!     .cmd("SET").arg("key_2").arg(43).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con));
//! # Ok(()) }
//! ```
//!
//! If you want the pipeline to be wrapped in a `MULTI`/`EXEC` block you can
//! easily do that by switching the pipeline into `atomic` mode.  From the
//! caller's point of view nothing changes, the pipeline itself will take
//! care of the rest for you:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = try!(redis::pipe()
//!     .atomic()
//!     .cmd("SET").arg("key_1").arg(42).ignore()
//!     .cmd("SET").arg("key_2").arg(43).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con));
//! # Ok(()) }
//! ```
//!
//! You can also use high-level commands on pipelines through the
//! `PipelineCommands` trait:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! use redis::PipelineCommands;
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = try!(redis::pipe()
//!     .atomic()
//!     .set("key_1", 42).ignore()
//!     .set("key_2", 43).ignore()
//!     .get("key_1")
//!     .get("key_2").query(&con));
//! # Ok(()) }
//! ```
//!
//! # Transactions
//!
//! Transactions are available through atomic pipelines.  In order to use
//! them in a more simple way you can use the `transaction` function of a
//! connection:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! use redis::{Commands, PipelineCommands};
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let key = "the_key";
//! let (new_val,) : (isize,) = try!(redis::transaction(&con, &[key], |pipe| {
//!     let old_val : isize = try!(con.get(key));
//!     pipe
//!         .set(key, old_val + 1).ignore()
//!         .get(key).query(&con)
//! }));
//! println!("The incremented number is: {}", new_val);
//! # Ok(()) }
//! ```
//!
//! For more information see the `transaction` function.
//!
//! # PubSub
//!
//! Pubsub is currently work in progress but provided through the `PubSub`
//! connection object.  Due to the fact that Rust does not have support
//! for async IO in libnative yet, the API does not provide a way to
//! read messages with any form of timeout yet.
//!
//! Example usage:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! let client = try!(redis::Client::open("redis://127.0.0.1/"));
//! let mut pubsub = try!(client.get_pubsub());
//! try!(pubsub.subscribe("channel_1"));
//! try!(pubsub.subscribe("channel_2"));
//!
//! loop {
//!     let msg = try!(pubsub.get_message());
//!     let payload : String = try!(msg.get_payload());
//!     println!("channel '{}': {}", msg.get_channel_name(), payload);
//! }
//! # }
//! ```
//!
//! # Scripts
//!
//! Lua scripts are supported through the `Script` type in a convenient
//! way (it does not support pipelining currently).  It will automatically
//! load the script if it does not exist and invoke it.
//!
//! Example:
//!
//! ```rust,no_run
//! # fn do_something() -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let script = redis::Script::new(r"
//!     return tonumber(ARGV[1]) + tonumber(ARGV[2]);
//! ");
//! let result : isize = try!(script.arg(1).arg(2).invoke(&con));
//! assert_eq!(result, 3);
//! # Ok(()) }
//! ```
//!
//! ## Breaking Changes
//!
//! In Rust 0.5.0 the semi-internal `ConnectionInfo` struct had to be
//! changed because of the unix socket support.  You are generally
//! heavily encouraged to use the URL based configuration format which
//! is a lot more stable than the structs.

#![deny(non_camel_case_types)]

extern crate url;
extern crate sha1;

#[cfg(feature="with-rustc-json")]
pub extern crate rustc_serialize as serialize;
#[cfg(feature="with-unix-sockets")]
extern crate unix_socket;

#[doc(hidden)]
#[cfg(feature="with-rustc-json")]
pub use serialize::json::Json;

// public api
pub use parser::{parse_redis_value, Parser};
pub use client::Client;
pub use script::{Script, ScriptInvocation};
pub use connection::{Connection, ConnectionLike, ConnectionInfo, ConnectionAddr,
                     IntoConnectionInfo, PubSub, Msg, transaction, parse_redis_url};
pub use cmd::{cmd, Cmd, pipe, Pipeline, Iter, pack_command};
pub use commands::{Commands, PipelineCommands};

pub use types::{
    /* low level values */
    Value,

    /* error and result types */
    RedisError,
    RedisResult,

    /* error kinds */
    ErrorKind,

    /* utility types */
    InfoDict,
    NumericBehavior,

    /* conversion traits */
    FromRedisValue,
    ToRedisArgs,

    /* utility functions */
    from_redis_value,
};

mod macros;

mod parser;
mod client;
mod connection;
mod types;
mod script;
mod cmd;
mod commands;
<|endoftext|>


<commit_before>//! Rustic bindings to [libnotify](https://developer.gnome.org/libnotify/)
//!
//! ```rust
//! extern crate libnotify;
//!
//! fn main() {
//!     let notify = libnotify::Context::new("hello").unwrap_or_else(|e| {
//!         panic!("{}", e);
//!     });
//!     let body_text = Some("This is the optional body text.");
//!     let n = notify.new_notification("This is the summary.",
//!                                     body_text,
//!                                     None).unwrap_or_else(|e| {
//!         panic!("{}", e);
//!     });
//!     n.show().ok().expect("Failed to show notification");
//! }
//! ```

extern crate libnotify_sys as sys;
extern crate glib_2_0_sys as glib;
extern crate gtypes;

use std::ffi::{CStr, CString};
use std::marker::PhantomData;
use std::fmt;
use std::error::Error;

use gtypes::{TRUE, FALSE};

/// Error that can happen on context creation
#[derive(Debug)]
pub enum ContextCreationError {
    /// Context already exists
    AlreadyExists,
    InitFailure,
    NulError,
}

impl fmt::Display for ContextCreationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use ContextCreationError::*;
        match *self {
            AlreadyExists => write!(f, "A Libnotify context already exists."),
            InitFailure => write!(f, "Failed to initialize libnotify."),
            NulError => write!(f, "Argument contains a nul character."),
        }
    }
}

#[derive(Debug)]
pub enum NotificationCreationError {
    NulError,
    Unknown,
}

impl fmt::Display for NotificationCreationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use NotificationCreationError::*;
        match *self {
            NulError => write!(f, "Argument contains a nul character."),
            Unknown => write!(f, "Unknown error"),
        }
    }
}

/// The context which within libnotify operates.
///
/// Only one context can exist at a time.
pub struct Context;

impl Context {
    /// Create a new context
    ///
    /// Arguments:
    ///
    /// - app_name: The name of the application using the context
    pub fn new(app_name: &str) -> Result<Context, ContextCreationError> {
        unsafe {
            if sys::notify_is_initted() == TRUE {
                return Err(ContextCreationError::AlreadyExists);
            }
            let app_name = match CString::new(app_name) {
                Ok(name) => name,
                Err(_) => return Err(ContextCreationError::NulError),
            };
            if sys::notify_init(app_name.as_ptr()) == FALSE {
                return Err(ContextCreationError::InitFailure);
            }
        }
        Ok(Context)
    }
    /// Creates a new Notification.
    ///
    /// Arguments:
    ///
    /// - summary: Required summary text
    /// - body: Optional body text
    /// - icon: Optional icon theme icon name or filename
    pub fn new_notification(&self,
                            summary: &str,
                            body: Option<&str>,
                            icon: Option<&str>)
                            -> Result<Notification, NotificationCreationError> {
        let summary = match CString::new(summary) {
            Ok(cstr) => cstr,
            Err(_) => return Err(NotificationCreationError::NulError),
        };
        let body = match body {
            Some(body) => match CString::new(body) {
                Ok(cstr) => Some(cstr),
                Err(_) => return Err(NotificationCreationError::NulError),
            },
            None => None,
        };
        let body_ptr = match body {
            Some(body) => body.as_ptr(),
            None => std::ptr::null(),
        };
        let icon = match icon {
            Some(icon) => match CString::new(icon) {
                Ok(cstr) => Some(cstr),
                Err(_) => return Err(NotificationCreationError::NulError),
            },
            None => None,
        };
        let icon_ptr = match icon {
            Some(icon) => icon.as_ptr(),
            None => std::ptr::null(),
        };
        unsafe {
            let n = sys::notify_notification_new(summary.as_ptr(), body_ptr, icon_ptr);
            if n.is_null() {
                return Err(NotificationCreationError::Unknown);
            }

            Ok(Notification {
                handle: n,
                _phantom: PhantomData,
            })
        }
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            sys::notify_uninit();
        }
    }
}

/// A passive pop-up notification
pub struct Notification<'a> {
    handle: *mut sys::NotifyNotification,
    _phantom: PhantomData<&'a Context>,
}

impl<'a> Notification<'a> {
    /// Tells the notification server to display the notification
    /// on the screen.
    pub fn show(&'a self) -> Result<(), NotificationShowError> {
        unsafe {
            let mut err: *mut glib::GError = std::ptr::null_mut();
            sys::notify_notification_show(self.handle, &mut err);
            if !err.is_null() {
                let result = Err(NotificationShowError {
                    message: CStr::from_ptr((*err).message).to_string_lossy().into_owned(),
                });
                glib::g_error_free(err);
                return result;
            }
            return Ok(());
        }
    }
}

#[derive(Debug)]
pub struct NotificationShowError {
    message: String,
}

impl fmt::Display for NotificationShowError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error showing notification: {}", self.message)
    }
}

impl Error for NotificationShowError {
    fn description(&self) -> &str {
        "Notification show error"
    }
}
<commit_msg>Update doc example<commit_after>//! Rustic bindings to [libnotify](https://developer.gnome.org/libnotify/)
//!
//! ```rust
//!extern crate libnotify;
//!
//!fn main() {
//!    let notify = libnotify::Context::new("hello").unwrap_or_else(|e| {
//!        panic!("{}", e);
//!    });
//!    let body_text = Some("This is the optional body text.");
//!    let n = notify.new_notification("This is the summary.", body_text, None)
//!                  .unwrap_or_else(|e| panic!("{}", e));
//!    n.show().unwrap_or_else(|e| panic!("{}", e));
//!}
//!
//! ```

extern crate libnotify_sys as sys;
extern crate glib_2_0_sys as glib;
extern crate gtypes;

use std::ffi::{CStr, CString};
use std::marker::PhantomData;
use std::fmt;
use std::error::Error;

use gtypes::{TRUE, FALSE};

/// Error that can happen on context creation
#[derive(Debug)]
pub enum ContextCreationError {
    /// Context already exists
    AlreadyExists,
    InitFailure,
    NulError,
}

impl fmt::Display for ContextCreationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use ContextCreationError::*;
        match *self {
            AlreadyExists => write!(f, "A Libnotify context already exists."),
            InitFailure => write!(f, "Failed to initialize libnotify."),
            NulError => write!(f, "Argument contains a nul character."),
        }
    }
}

#[derive(Debug)]
pub enum NotificationCreationError {
    NulError,
    Unknown,
}

impl fmt::Display for NotificationCreationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use NotificationCreationError::*;
        match *self {
            NulError => write!(f, "Argument contains a nul character."),
            Unknown => write!(f, "Unknown error"),
        }
    }
}

/// The context which within libnotify operates.
///
/// Only one context can exist at a time.
pub struct Context;

impl Context {
    /// Create a new context
    ///
    /// Arguments:
    ///
    /// - app_name: The name of the application using the context
    pub fn new(app_name: &str) -> Result<Context, ContextCreationError> {
        unsafe {
            if sys::notify_is_initted() == TRUE {
                return Err(ContextCreationError::AlreadyExists);
            }
            let app_name = match CString::new(app_name) {
                Ok(name) => name,
                Err(_) => return Err(ContextCreationError::NulError),
            };
            if sys::notify_init(app_name.as_ptr()) == FALSE {
                return Err(ContextCreationError::InitFailure);
            }
        }
        Ok(Context)
    }
    /// Creates a new Notification.
    ///
    /// Arguments:
    ///
    /// - summary: Required summary text
    /// - body: Optional body text
    /// - icon: Optional icon theme icon name or filename
    pub fn new_notification(&self,
                            summary: &str,
                            body: Option<&str>,
                            icon: Option<&str>)
                            -> Result<Notification, NotificationCreationError> {
        let summary = match CString::new(summary) {
            Ok(cstr) => cstr,
            Err(_) => return Err(NotificationCreationError::NulError),
        };
        let body = match body {
            Some(body) => match CString::new(body) {
                Ok(cstr) => Some(cstr),
                Err(_) => return Err(NotificationCreationError::NulError),
            },
            None => None,
        };
        let body_ptr = match body {
            Some(body) => body.as_ptr(),
            None => std::ptr::null(),
        };
        let icon = match icon {
            Some(icon) => match CString::new(icon) {
                Ok(cstr) => Some(cstr),
                Err(_) => return Err(NotificationCreationError::NulError),
            },
            None => None,
        };
        let icon_ptr = match icon {
            Some(icon) => icon.as_ptr(),
            None => std::ptr::null(),
        };
        unsafe {
            let n = sys::notify_notification_new(summary.as_ptr(), body_ptr, icon_ptr);
            if n.is_null() {
                return Err(NotificationCreationError::Unknown);
            }

            Ok(Notification {
                handle: n,
                _phantom: PhantomData,
            })
        }
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            sys::notify_uninit();
        }
    }
}

/// A passive pop-up notification
pub struct Notification<'a> {
    handle: *mut sys::NotifyNotification,
    _phantom: PhantomData<&'a Context>,
}

impl<'a> Notification<'a> {
    /// Tells the notification server to display the notification
    /// on the screen.
    pub fn show(&'a self) -> Result<(), NotificationShowError> {
        unsafe {
            let mut err: *mut glib::GError = std::ptr::null_mut();
            sys::notify_notification_show(self.handle, &mut err);
            if !err.is_null() {
                let result = Err(NotificationShowError {
                    message: CStr::from_ptr((*err).message).to_string_lossy().into_owned(),
                });
                glib::g_error_free(err);
                return result;
            }
            return Ok(());
        }
    }
}

#[derive(Debug)]
pub struct NotificationShowError {
    message: String,
}

impl fmt::Display for NotificationShowError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error showing notification: {}", self.message)
    }
}

impl Error for NotificationShowError {
    fn description(&self) -> &str {
        "Notification show error"
    }
}
<|endoftext|>