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

use std::collections::BTreeMap;
use std::path::Path;

use chrono::{DateTime,Utc};

use store;
use AplibObject;
use AplibType;
use audit::{
    audit_get_str_value, audit_get_int_value, audit_get_bool_value,
    audit_get_date_value,
    Report, SkipReason
};
use plutils::{get_array_value, Plist};

#[derive(Debug, PartialEq, Clone)]
pub enum Subclass {
    Invalid,
    Implicit,
    Smart,
    User
}

impl Subclass {

    fn from(v: i64) -> Self {
        match v {
            0 => Subclass::Invalid,
            1 => Subclass::Implicit,
            2 => Subclass::Smart,
            3 => Subclass::User,
            _ => {
                println!("Unknown subclass value {}", v);
                Subclass::Invalid
            }
        }
    }

    fn from_option(o: Option<i64>) -> Option<Self> {
        if let Some(v) = o {
            Some(Self::from(v))
        } else {
            None
        }
    }

    pub fn to_int(v: &Self) -> i64 {
        match *v {
            Subclass::Invalid => 0,
            Subclass::Implicit => 1,
            Subclass::Smart => 2,
            Subclass::User => 3,
        }
    }
}

/// Album object.
#[derive(Debug)]
pub struct Album {
    /// uuid
    uuid: Option<String>,
    /// Folder uuid it represents.
    folder_uuid: Option<String>,
    model_id: Option<i64>,

    /// Subclass. See ``Subclass`` enum. (Normal, Smart)
    pub subclass: Option<Subclass>,
    /// ```Type```. Seems to always be 1
    pub album_type: Option<i64>,
    /// UUID of folder it is querying content of (smart only)
    pub query_folder_uuid: Option<String>,
    /// Version of db
    pub db_version: Option<i64>,
    /// Sort ascending
    pub sort_asc: Option<bool>,
    /// Date key for sort
    pub sort_key: Option<String>,
    /// Name of the album.
    pub name: Option<String>,
    pub custom_sort_available: Option<bool>,
    pub colour_label_index: Option<i64>,
    pub create_date: Option<DateTime<Utc>>,
    pub is_hidden: Option<bool>,
    pub is_magic: Option<bool>,
    pub is_favourite: Option<bool>,
    pub is_in_trash: Option<bool>,
    /// Content list
    pub content: Option<Vec<String>>,
}

impl AplibObject for Album {
    fn from_path(plist_path: &Path,
                 mut auditor: Option<&mut Report>) -> Option<Album> {

        use plutils::*;

        let plist = parse_plist(plist_path);
        match plist {
            Plist::Dictionary(ref dict) => {
                if let Some(info_dict) = get_dict_value(dict, "InfoDictionary") {
                    let subclass =
                        Subclass::from_option(
                            audit_get_int_value(&info_dict,
                                                "albumSubclass", &mut auditor));
                    let result = Some(Album {
                        uuid: audit_get_str_value(
                            &info_dict, "uuid", &mut auditor),
                        folder_uuid: audit_get_str_value(
                            &info_dict, "folderUuid", &mut auditor),
                        subclass: subclass.clone(),
                        album_type: audit_get_int_value(
                            &info_dict, "albumType", &mut auditor),
                        db_version: audit_get_int_value(
                            &info_dict, "version", &mut auditor),
                        model_id: audit_get_int_value(
                            &info_dict, "modelId", &mut auditor),
                        sort_asc: audit_get_bool_value(
                            &info_dict, "sortAscending", &mut auditor),
                        sort_key: audit_get_str_value(
                            &info_dict, "sortKeyPath", &mut auditor),
                        name: audit_get_str_value(
                            &info_dict, "name", &mut auditor),
                        query_folder_uuid: audit_get_str_value(
                            &info_dict, "queryFolderUuid", &mut auditor),
                        create_date: audit_get_date_value(&info_dict, "createDate", &mut auditor),
                        colour_label_index: audit_get_int_value(
                            &info_dict, "colorLabelIndex", &mut auditor),
                        custom_sort_available: audit_get_bool_value(
                            &info_dict, "customSortAvailable", &mut auditor),
                        is_hidden: audit_get_bool_value(&info_dict, "isHidden", &mut auditor),
                        is_magic: audit_get_bool_value(&info_dict, "isMagic", &mut auditor),
                        is_favourite: audit_get_bool_value(&info_dict, "isFavorite", &mut auditor),
                        is_in_trash: audit_get_bool_value(&info_dict, "isInTrash", &mut auditor),

                        content: Album::content_from(
                            &dict, &subclass, &mut auditor),
                    });
                    if auditor.is_some() {
                        let ref mut auditor = auditor.unwrap();
                        auditor.audit_ignored(&info_dict, None);
                    }
                    result
                } else {
                    None
                }
            },
            _ =>
                None
        }
    }
    fn obj_type(&self) -> AplibType {
        AplibType::Album
    }
    fn uuid(&self) -> &Option<String> {
        &self.uuid
    }
    fn parent(&self) -> &Option<String> {
        &self.folder_uuid
    }
    fn model_id(&self) -> i64 {
        self.model_id.unwrap_or(0)
    }
    fn is_valid(&self) -> bool {
        self.uuid.is_some()
    }
    fn wrap(obj: Album) -> store::Wrapper {
        store::Wrapper::Album(Box::new(obj))
    }
}

impl Album {
    fn content_from(dict: &BTreeMap<String, Plist>,
                    subclass: &Option<Subclass>,
                    auditor: &mut Option<&mut Report>) -> Option<Vec<String>> {
        if let Some(array) = get_array_value(&dict, "versionUuids") {
            if *subclass == Some(Subclass::User) {
                let content: Vec<String>;
                content = array.iter().filter_map(
                    |elem|
                    match *elem {
                        Plist::String(ref s) =>
                            Some(s.to_owned()),
                        _ =>
                            None
                    }
                ).collect();
                if let Some(ref mut report) = *auditor {
                    report.parsed("versionUuids");
                }
                Some(content)
            } else {
                if let Some(ref mut report) = *auditor {
                    report.skip("versionUuids", SkipReason::InvalidData);
                }
                None
            }
        } else {
            None
        }
    }
}

#[cfg(test)]
#[test]
fn test_album_parse() {
    use testutils;

    let album = Album::from_path(
        testutils::get_test_file_path("gOnttfpzQoOxcwLpFS9DQg.apalbum")
            .as_path(), None);
    assert!(album.is_some());
    let album = album.unwrap();

    assert_eq!(album.uuid.as_ref().unwrap(), "gOnttfpzQoOxcwLpFS9DQg");
    assert_eq!(album.folder_uuid.as_ref().unwrap(), "TopLevelAlbums");
    assert_eq!(album.model_id.unwrap(), 601);
    assert_eq!(*album.subclass.as_ref().unwrap(), Subclass::Implicit);
    assert_eq!(album.album_type.unwrap(), 1);
    assert!(album.query_folder_uuid.is_none());
    assert_eq!(album.db_version.unwrap(), 110);
    assert_eq!(album.sort_asc.unwrap(), true);
    assert_eq!(album.sort_key.as_ref().unwrap(), "exifProperties.ImageDate");
    assert!(album.name.is_none());

//    let report = album.audit();
    // XXX fix when have actual audit.
//    println!("report {:?}", report);
}

#[cfg(test)]
#[test]
fn test_album_content_parse() {
    use testutils;

    let album = Album::from_path(
        testutils::get_test_file_path("x6yNun58SB2sImfCarTJHA.apalbum")
            .as_path(), None);
    assert!(album.is_some());
    let album = album.unwrap();

    assert_eq!(album.uuid.as_ref().unwrap(), "x6yNun58SB2sImfCarTJHA");
    assert_eq!(album.folder_uuid.as_ref().unwrap(), "TopLevelAlbums");
    assert_eq!(album.model_id.unwrap(), 181);
    assert_eq!(*album.subclass.as_ref().unwrap(), Subclass::User);
    assert_eq!(album.album_type.unwrap(), 1);
    assert!(album.query_folder_uuid.is_none());
    assert_eq!(album.db_version.unwrap(), 110);
    assert_eq!(album.sort_asc.unwrap(), true);
    assert_eq!(album.sort_key.as_ref().unwrap(), "exifProperties.ImageDate");
    assert_eq!(album.name.as_ref().unwrap(), "Flickr");
    assert!(album.content.is_some());
    let content = &album.content.as_ref().unwrap();
    assert_eq!(content.len(), 1);
    assert_eq!(content[0], "BF6nuoBnTumzoXyexdmXlw");

//    let report = album.audit();
    // XXX fix when have actual audit.
//    println!("report {:?}", report);
}
<commit_msg>albums: handle selected_track_path_uuid<commit_after>/*
  This Source Code Form is subject to the terms of the Mozilla Public
  License, v. 2.0. If a copy of the MPL was not distributed with this
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

use std::collections::BTreeMap;
use std::path::Path;

use chrono::{DateTime,Utc};

use store;
use AplibObject;
use AplibType;
use audit::{
    audit_get_str_value, audit_get_int_value, audit_get_bool_value,
    audit_get_date_value,
    Report, SkipReason
};
use plutils::{get_array_value, Plist};

#[derive(Debug, PartialEq, Clone)]
pub enum Subclass {
    Invalid,
    Implicit,
    Smart,
    User
}

impl Subclass {

    fn from(v: i64) -> Self {
        match v {
            0 => Subclass::Invalid,
            1 => Subclass::Implicit,
            2 => Subclass::Smart,
            3 => Subclass::User,
            _ => {
                println!("Unknown subclass value {}", v);
                Subclass::Invalid
            }
        }
    }

    fn from_option(o: Option<i64>) -> Option<Self> {
        if let Some(v) = o {
            Some(Self::from(v))
        } else {
            None
        }
    }

    pub fn to_int(v: &Self) -> i64 {
        match *v {
            Subclass::Invalid => 0,
            Subclass::Implicit => 1,
            Subclass::Smart => 2,
            Subclass::User => 3,
        }
    }
}

/// Album object.
#[derive(Debug)]
pub struct Album {
    /// uuid
    uuid: Option<String>,
    /// Folder uuid it represents.
    folder_uuid: Option<String>,
    model_id: Option<i64>,

    /// Subclass. See ``Subclass`` enum. (Normal, Smart)
    pub subclass: Option<Subclass>,
    /// ```Type```. Seems to always be 1
    pub album_type: Option<i64>,
    /// UUID of folder it is querying content of (smart only)
    pub query_folder_uuid: Option<String>,
    /// Version of db
    pub db_version: Option<i64>,
    /// Sort ascending
    pub sort_asc: Option<bool>,
    /// Date key for sort
    pub sort_key: Option<String>,
    /// Name of the album.
    pub name: Option<String>,
    pub custom_sort_available: Option<bool>,
    pub colour_label_index: Option<i64>,
    pub create_date: Option<DateTime<Utc>>,
    pub is_hidden: Option<bool>,
    pub is_magic: Option<bool>,
    pub is_favourite: Option<bool>,
    pub is_in_trash: Option<bool>,
    pub selected_track_path_uuid: Option<String>,
    /// Content list
    pub content: Option<Vec<String>>,
}

impl AplibObject for Album {
    fn from_path(plist_path: &Path,
                 mut auditor: Option<&mut Report>) -> Option<Album> {

        use plutils::*;

        let plist = parse_plist(plist_path);
        match plist {
            Plist::Dictionary(ref dict) => {
                if let Some(info_dict) = get_dict_value(dict, "InfoDictionary") {
                    let subclass =
                        Subclass::from_option(
                            audit_get_int_value(&info_dict,
                                                "albumSubclass", &mut auditor));
                    let result = Some(Album {
                        uuid: audit_get_str_value(
                            &info_dict, "uuid", &mut auditor),
                        folder_uuid: audit_get_str_value(
                            &info_dict, "folderUuid", &mut auditor),
                        subclass: subclass.clone(),
                        album_type: audit_get_int_value(
                            &info_dict, "albumType", &mut auditor),
                        db_version: audit_get_int_value(
                            &info_dict, "version", &mut auditor),
                        model_id: audit_get_int_value(
                            &info_dict, "modelId", &mut auditor),
                        sort_asc: audit_get_bool_value(
                            &info_dict, "sortAscending", &mut auditor),
                        sort_key: audit_get_str_value(
                            &info_dict, "sortKeyPath", &mut auditor),
                        name: audit_get_str_value(
                            &info_dict, "name", &mut auditor),
                        query_folder_uuid: audit_get_str_value(
                            &info_dict, "queryFolderUuid", &mut auditor),
                        create_date: audit_get_date_value(&info_dict, "createDate", &mut auditor),
                        colour_label_index: audit_get_int_value(
                            &info_dict, "colorLabelIndex", &mut auditor),
                        custom_sort_available: audit_get_bool_value(
                            &info_dict, "customSortAvailable", &mut auditor),
                        is_hidden: audit_get_bool_value(&info_dict, "isHidden", &mut auditor),
                        is_magic: audit_get_bool_value(&info_dict, "isMagic", &mut auditor),
                        is_favourite: audit_get_bool_value(&info_dict, "isFavorite", &mut auditor),
                        is_in_trash: audit_get_bool_value(&info_dict, "isInTrash", &mut auditor),
                        selected_track_path_uuid: audit_get_str_value(
                            &info_dict, "selectedTrackPathUuid", &mut auditor),
                        content: Album::content_from(
                            &dict, &subclass, &mut auditor),
                    });
                    if auditor.is_some() {
                        let ref mut auditor = auditor.unwrap();
                        auditor.audit_ignored(&info_dict, None);
                    }
                    result
                } else {
                    None
                }
            },
            _ =>
                None
        }
    }
    fn obj_type(&self) -> AplibType {
        AplibType::Album
    }
    fn uuid(&self) -> &Option<String> {
        &self.uuid
    }
    fn parent(&self) -> &Option<String> {
        &self.folder_uuid
    }
    fn model_id(&self) -> i64 {
        self.model_id.unwrap_or(0)
    }
    fn is_valid(&self) -> bool {
        self.uuid.is_some()
    }
    fn wrap(obj: Album) -> store::Wrapper {
        store::Wrapper::Album(Box::new(obj))
    }
}

impl Album {
    fn content_from(dict: &BTreeMap<String, Plist>,
                    subclass: &Option<Subclass>,
                    auditor: &mut Option<&mut Report>) -> Option<Vec<String>> {
        if let Some(array) = get_array_value(&dict, "versionUuids") {
            if *subclass == Some(Subclass::User) {
                let content: Vec<String>;
                content = array.iter().filter_map(
                    |elem|
                    match *elem {
                        Plist::String(ref s) =>
                            Some(s.to_owned()),
                        _ =>
                            None
                    }
                ).collect();
                if let Some(ref mut report) = *auditor {
                    report.parsed("versionUuids");
                }
                Some(content)
            } else {
                if let Some(ref mut report) = *auditor {
                    report.skip("versionUuids", SkipReason::InvalidData);
                }
                None
            }
        } else {
            None
        }
    }
}

#[cfg(test)]
#[test]
fn test_album_parse() {
    use testutils;

    let album = Album::from_path(
        testutils::get_test_file_path("gOnttfpzQoOxcwLpFS9DQg.apalbum")
            .as_path(), None);
    assert!(album.is_some());
    let album = album.unwrap();

    assert_eq!(album.uuid.as_ref().unwrap(), "gOnttfpzQoOxcwLpFS9DQg");
    assert_eq!(album.folder_uuid.as_ref().unwrap(), "TopLevelAlbums");
    assert_eq!(album.model_id.unwrap(), 601);
    assert_eq!(*album.subclass.as_ref().unwrap(), Subclass::Implicit);
    assert_eq!(album.album_type.unwrap(), 1);
    assert!(album.query_folder_uuid.is_none());
    assert_eq!(album.db_version.unwrap(), 110);
    assert_eq!(album.sort_asc.unwrap(), true);
    assert_eq!(album.sort_key.as_ref().unwrap(), "exifProperties.ImageDate");
    assert!(album.name.is_none());

//    let report = album.audit();
    // XXX fix when have actual audit.
//    println!("report {:?}", report);
}

#[cfg(test)]
#[test]
fn test_album_content_parse() {
    use testutils;

    let album = Album::from_path(
        testutils::get_test_file_path("x6yNun58SB2sImfCarTJHA.apalbum")
            .as_path(), None);
    assert!(album.is_some());
    let album = album.unwrap();

    assert_eq!(album.uuid.as_ref().unwrap(), "x6yNun58SB2sImfCarTJHA");
    assert_eq!(album.folder_uuid.as_ref().unwrap(), "TopLevelAlbums");
    assert_eq!(album.model_id.unwrap(), 181);
    assert_eq!(*album.subclass.as_ref().unwrap(), Subclass::User);
    assert_eq!(album.album_type.unwrap(), 1);
    assert!(album.query_folder_uuid.is_none());
    assert_eq!(album.db_version.unwrap(), 110);
    assert_eq!(album.sort_asc.unwrap(), true);
    assert_eq!(album.sort_key.as_ref().unwrap(), "exifProperties.ImageDate");
    assert_eq!(album.name.as_ref().unwrap(), "Flickr");
    assert!(album.content.is_some());
    let content = &album.content.as_ref().unwrap();
    assert_eq!(content.len(), 1);
    assert_eq!(content[0], "BF6nuoBnTumzoXyexdmXlw");

//    let report = album.audit();
    // XXX fix when have actual audit.
//    println!("report {:?}", report);
}
<|endoftext|>


<commit_before>extern crate nalgebra;

use memoized_flat_time_steward as s;
use ::{TimeSteward, DeterministicRandomId, Column, ColumnId, RowId, PredictorId, Mutator,
TimeStewardStaticMethods, Accessor, MomentaryAccessor, PredictorAccessor};
use ::collision_detection::inefficient as collisions;

use ::time_functions::QuadraticTrajectory;
use std::rc::Rc;
use rand::Rng;
use nalgebra::{Vector2};

use std::io::Write;
macro_rules! printlnerr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

type Time = i64;
type SpaceCoordinate = i64;

const HOW_MANY_CIRCLES: i32 = 20;
const ARENA_SIZE: SpaceCoordinate = (1 << 20);
const TIME_SHIFT: i32 = 20;
const SECOND: Time = (1 << TIME_SHIFT);

#[derive(Clone)]
struct Basics;
impl ::Basics for Basics {
  type Time = Time;
  type Constants = ();
}
struct CollisionBasics {}
impl ::collision_detection::Basics for CollisionBasics {
  type StewardBasics = Basics;
  type DetectorId =();
  fn nearness_column_id() -> ColumnId {
    ColumnId(0x89ebc3ba9a24c286)
  }

}

type Nearness = ::collision_detection::Nearness<CollisionBasics> ;

#[derive(Clone)]
struct Circle {
position: QuadraticTrajectory,
radius: SpaceCoordinate,
}
impl Column for Circle {
  type FieldType = Self;
  fn column_id() -> ColumnId {
    ColumnId(0x6422505ce8c8ce8e)
  }
}
struct Intersection {
induced_acceleration: Vector2 <SpaceCoordinate>,
}
impl Column for Intersection {
  type FieldType = Self;
  fn column_id() -> ColumnId {
    ColumnId(0x9357f021339198a1)  }
}

 type Steward = s::Steward<Basics>;

fn get_circle_id(index: i32) -> RowId {
  DeterministicRandomId::new(&(0x86ccbeb2c140cc51u64, index))
}

fn collision_predictor <PA: PredictorAccessor <Basics, <s::Steward <Basics> as TimeStewardStaticMethods < Basics>>::EventFn >> (accessor: &mut PA, id: RowId) {
  printlnerr!("Planning {}", id);
let ids = Nearness::get_ids (accessor, id).0;
let time;
  {

let us = (accessor.data_and_last_change::<Circle>(ids [0]).unwrap(), accessor.data_and_last_change::<Circle>(ids [0]).unwrap());

let relationship = accessor.get::<Intersection> (id);
time =QuadraticTrajectory::approximately_when_distance_passes((us.0) .0.radius + (us.1) .0.radius, if relationship.is_none() {-1} else {1},
((us.0) .1.clone(), & (us.0) .0.position), ((us.1) .1.clone(), & (us.1) .0.position)) ;
  }
  if let Some (yes) = time { accessor.predict_at_time (& yes, Rc::new (move | mutator | {
let new_relationship;let mut new ;
    {let relationship = mutator.get::<Intersection> (id).clone();
    let us = (mutator.data_and_last_change::<Circle>(ids [0]).unwrap(), mutator.data_and_last_change::<Circle>(ids [0]).unwrap());
    new = ((us.0).0.clone(), (us.1).0.clone());
    new.0.position.update_by (mutator.now() - (us.0).1);
    new.1.position.update_by (mutator.now() - (us. 1) .1);
    if let Some (intersection) = relationship {
new.0.position.add_acceleration (- intersection.induced_acceleration);
new.1 .position.add_acceleration (intersection.induced_acceleration);
new_relationship = None;
    }
    else {
    let acceleration = Vector2::new (ARENA_SIZE,ARENA_SIZE);
    new.0.position.add_acceleration (acceleration);
    new.1.position.add_acceleration (- acceleration);
        new_relationship = Some (Intersection {induced_acceleration: acceleration});

    }}
    mutator.set::<Intersection> (id, new_relationship);
    mutator.set::<Circle> (ids [0], Some (new.0));
    mutator.set::<Circle> (ids [1], Some (new. 1));
  }));}
}

pub fn testfunc() {

  let mut stew: Steward = ::TimeStewardStaticMethods::new_empty((),
                                                   vec![s::Predictor {
                                                          predictor_id: PredictorId(0x5375592f4da8682c),
                                                          column_id: Nearness::column_id(),
                                                          function: Rc::new(| accessor, id | collision_predictor (accessor, id)),}]); /*{
      printlnerr!("Planning {}", id);
      let me = pa.get::<Circle>(id).unwrap().clone();
      pa.predict_at_time(&me.time_when_next_initiates_handshake,
                         Rc::new(move |m| {
        let now = *m.now();
        let friend_id = get_philosopher_id(m.rng().gen_range(0, HOW_MANY_PHILOSOPHERS));
        let awaken_time_1 = now + m.rng().gen_range(-1, 4);
        let awaken_time_2 = now + m.rng().gen_range(-1, 7);
        printlnerr!("SHAKE!!! @{}. {}={}; {}={}", now, whodunnit, awaken_time_2, friend_id, awaken_time_1);
        // IF YOU SHAKE YOUR OWN HAND YOU RECOVER
        // IN THE SECOND TIME APPARENTLY
        m.set::<Philosopher>(friend_id,
                             Some(Philosopher {
                               time_when_next_initiates_handshake: awaken_time_1,
                             }));
        m.set::<Philosopher>(whodunnit,
                             Some(Philosopher {
                               time_when_next_initiates_handshake: awaken_time_2,
                             }));
      }));
    }),
                                                        }]);*/

  stew.insert_fiat_event(0,
                         DeterministicRandomId::new(& 0),
                         Rc::new(| mutator | {
    for i in 0..HOW_MANY_CIRCLES {
let thingy =ARENA_SIZE/20;
let radius = mutator.rng().gen_range(ARENA_SIZE/30, ARENA_SIZE/15);
let id =get_circle_id(i);

let position = QuadraticTrajectory::new (
TIME_SHIFT,
[mutator.rng().gen_range(0, ARENA_SIZE), mutator.rng().gen_range(0, ARENA_SIZE),
mutator.rng().gen_range(- thingy, thingy), mutator.rng().gen_range(- thingy, thingy),
0, 0]
);
      mutator.set::<Circle>(id,
                           Some(Circle {
position: position, radius: radius
                           }));
collisions::insert::<CollisionBasics,_> (mutator, id,());
    }
  }));

  let mut snapshots = Vec:: new();
  for increment in 1..21 {
    snapshots.push (stew.snapshot_before(& (increment*100i64)));
  }
  for snapshot in snapshots.iter_mut().map (| option | option.as_mut().expect ("all these snapshots should have been valid")) {
    printlnerr!("snapshot for {}", snapshot.now());
    for index in 0..HOW_MANY_CIRCLES {
      //printlnerr!("{}", snapshot.get::<Circle> (get_circle_id (index)).expect("missing circle").position);
    }
  }
  // panic!("anyway")
}

#[test]
fn actuallytest() {
  testfunc();
}
<commit_msg>Better failure messages<commit_after>extern crate nalgebra;

use memoized_flat_time_steward as s;
use ::{TimeSteward, DeterministicRandomId, Column, ColumnId, RowId, PredictorId, Mutator,
TimeStewardStaticMethods, Accessor, MomentaryAccessor, PredictorAccessor};
use ::collision_detection::inefficient as collisions;

use ::time_functions::QuadraticTrajectory;
use std::rc::Rc;
use rand::Rng;
use nalgebra::{Vector2};

use std::io::Write;
macro_rules! printlnerr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

type Time = i64;
type SpaceCoordinate = i64;

const HOW_MANY_CIRCLES: i32 = 20;
const ARENA_SIZE: SpaceCoordinate = (1 << 20);
const TIME_SHIFT: i32 = 20;
const SECOND: Time = (1 << TIME_SHIFT);

#[derive(Clone)]
struct Basics;
impl ::Basics for Basics {
  type Time = Time;
  type Constants = ();
}
struct CollisionBasics {}
impl ::collision_detection::Basics for CollisionBasics {
  type StewardBasics = Basics;
  type DetectorId =();
  fn nearness_column_id() -> ColumnId {
    ColumnId(0x89ebc3ba9a24c286)
  }

}

type Nearness = ::collision_detection::Nearness<CollisionBasics> ;

#[derive(Clone)]
struct Circle {
position: QuadraticTrajectory,
radius: SpaceCoordinate,
}
impl Column for Circle {
  type FieldType = Self;
  fn column_id() -> ColumnId {
    ColumnId(0x6422505ce8c8ce8e)
  }
}
struct Intersection {
induced_acceleration: Vector2 <SpaceCoordinate>,
}
impl Column for Intersection {
  type FieldType = Self;
  fn column_id() -> ColumnId {
    ColumnId(0x9357f021339198a1)  }
}

 type Steward = s::Steward<Basics>;

fn get_circle_id(index: i32) -> RowId {
  DeterministicRandomId::new(&(0x86ccbeb2c140cc51u64, index))
}

fn collision_predictor <PA: PredictorAccessor <Basics, <s::Steward <Basics> as TimeStewardStaticMethods < Basics>>::EventFn >> (accessor: &mut PA, id: RowId) {
  printlnerr!("Planning {}", id);
let ids = Nearness::get_ids (accessor, id).0;
let time;
  {

let us = (accessor.data_and_last_change::<Circle>(ids [0]).expect("a nearness exists for a circle that doesn't"), accessor.data_and_last_change::<Circle>(ids [0]).expect("a nearness exists for a circle that doesn't"));

let relationship = accessor.get::<Intersection> (id);
time =QuadraticTrajectory::approximately_when_distance_passes((us.0) .0.radius + (us.1) .0.radius, if relationship.is_none() {-1} else {1},
((us.0) .1.clone(), & (us.0) .0.position), ((us.1) .1.clone(), & (us.1) .0.position)) ;
  }
  if let Some (yes) = time { accessor.predict_at_time (& yes, Rc::new (move | mutator | {
let new_relationship;let mut new ;
    {let relationship = mutator.get::<Intersection> (id).clone();
    let us = (mutator.data_and_last_change::<Circle>(ids [0]).expect("a nearness exists for a circle that doesn't (event)"),mutator.data_and_last_change::<Circle>(ids [0]).expect("a nearness exists for a circle that doesn't (event)"));
    new = ((us.0).0.clone(), (us.1).0.clone());
    new.0.position.update_by (mutator.now() - (us.0).1);
    new.1.position.update_by (mutator.now() - (us. 1) .1);
    if let Some (intersection) = relationship {
new.0.position.add_acceleration (- intersection.induced_acceleration);
new.1 .position.add_acceleration (intersection.induced_acceleration);
new_relationship = None;
    }
    else {
    let acceleration = Vector2::new (ARENA_SIZE,ARENA_SIZE);
    new.0.position.add_acceleration (acceleration);
    new.1.position.add_acceleration (- acceleration);
        new_relationship = Some (Intersection {induced_acceleration: acceleration});

    }}
    mutator.set::<Intersection> (id, new_relationship);
    mutator.set::<Circle> (ids [0], Some (new.0));
    mutator.set::<Circle> (ids [1], Some (new. 1));
  }));}
}

pub fn testfunc() {

  let mut stew: Steward = ::TimeStewardStaticMethods::new_empty((),
                                                   vec![s::Predictor {
                                                          predictor_id: PredictorId(0x5375592f4da8682c),
                                                          column_id: Nearness::column_id(),
                                                          function: Rc::new(| accessor, id | collision_predictor (accessor, id)),}]); /*{
      printlnerr!("Planning {}", id);
      let me = pa.get::<Circle>(id).unwrap().clone();
      pa.predict_at_time(&me.time_when_next_initiates_handshake,
                         Rc::new(move |m| {
        let now = *m.now();
        let friend_id = get_philosopher_id(m.rng().gen_range(0, HOW_MANY_PHILOSOPHERS));
        let awaken_time_1 = now + m.rng().gen_range(-1, 4);
        let awaken_time_2 = now + m.rng().gen_range(-1, 7);
        printlnerr!("SHAKE!!! @{}. {}={}; {}={}", now, whodunnit, awaken_time_2, friend_id, awaken_time_1);
        // IF YOU SHAKE YOUR OWN HAND YOU RECOVER
        // IN THE SECOND TIME APPARENTLY
        m.set::<Philosopher>(friend_id,
                             Some(Philosopher {
                               time_when_next_initiates_handshake: awaken_time_1,
                             }));
        m.set::<Philosopher>(whodunnit,
                             Some(Philosopher {
                               time_when_next_initiates_handshake: awaken_time_2,
                             }));
      }));
    }),
                                                        }]);*/

  stew.insert_fiat_event(0,
                         DeterministicRandomId::new(& 0),
                         Rc::new(| mutator | {
    for i in 0..HOW_MANY_CIRCLES {
let thingy =ARENA_SIZE/20;
let radius = mutator.rng().gen_range(ARENA_SIZE/30, ARENA_SIZE/15);
let id =get_circle_id(i);

let position = QuadraticTrajectory::new (
TIME_SHIFT,
[mutator.rng().gen_range(0, ARENA_SIZE), mutator.rng().gen_range(0, ARENA_SIZE),
mutator.rng().gen_range(- thingy, thingy), mutator.rng().gen_range(- thingy, thingy),
0, 0]
);
      mutator.set::<Circle>(id,
                           Some(Circle {
position: position, radius: radius
                           }));
collisions::insert::<CollisionBasics,_> (mutator, id,());
    }
  }));

  let mut snapshots = Vec:: new();
  for increment in 1..21 {
    snapshots.push (stew.snapshot_before(& (increment*100i64)));
  }
  for snapshot in snapshots.iter_mut().map (| option | option.as_mut().expect ("all these snapshots should have been valid")) {
    printlnerr!("snapshot for {}", snapshot.now());
    for index in 0..HOW_MANY_CIRCLES {
      //printlnerr!("{}", snapshot.get::<Circle> (get_circle_id (index)).expect("missing circle").position);
    }
  }
  // panic!("anyway")
}

#[test]
fn actuallytest() {
  testfunc();
}
<|endoftext|>


<commit_before>use crate::{
    exporter::{ExportResult, Exporter},
    texture::Texture,
};
use image::{DynamicImage, ImageBuffer, Rgba};
use std::marker::PhantomData;

#[derive(Copy, Clone)]
pub struct ImageExporter<T>(PhantomData<T>);

impl<T: Texture<Pixel = Rgba<u8>>> ImageExporter<T> {
    pub fn export(texture: &T) -> ExportResult<DynamicImage> {
        <Self as Exporter<T>>::export(texture)
    }
}

impl<T: Texture<Pixel = Rgba<u8>>> Exporter<T> for ImageExporter<T> {
    type Output = DynamicImage;

    fn export(texture: &T) -> ExportResult<DynamicImage> {
        let width = texture.width();
        let height = texture.height();

        if width == 0 || height == 0 {
            return Err("Width or height of this texture is zero".to_string());
        }

        let mut pixels = Vec::new();

        for row in 0..height {
            for col in 0..width {
                if let Some(pixel) = texture.get(col, row) {
                    pixels.push(pixel[0]);
                    pixels.push(pixel[1]);
                    pixels.push(pixel[2]);
                    pixels.push(pixel[3]);
                } else {
                    pixels.push(0);
                    pixels.push(0);
                    pixels.push(0);
                    pixels.push(0);
                }
            }
        }

        if let Some(image_buffer) =
            ImageBuffer::<Rgba<u8>, Vec<u8>>::from_raw(width, height, pixels)
        {
            Ok(DynamicImage::ImageRgba8(image_buffer))
        } else {
            Err("Can't export texture".to_string())
        }
    }
}
<commit_msg>docs: Document image_exporter module contents<commit_after>use crate::{
    exporter::{ExportResult, Exporter},
    texture::Texture,
};
use image::{DynamicImage, ImageBuffer, Rgba};
use std::marker::PhantomData;

/// Exporter type for images.
#[derive(Copy, Clone)]
pub struct ImageExporter<T>(PhantomData<T>);

impl<T: Texture<Pixel = Rgba<u8>>> ImageExporter<T> {
    /// Export a texture to an image type.
    pub fn export(texture: &T) -> ExportResult<DynamicImage> {
        <Self as Exporter<T>>::export(texture)
    }
}

impl<T: Texture<Pixel = Rgba<u8>>> Exporter<T> for ImageExporter<T> {
    type Output = DynamicImage;

    fn export(texture: &T) -> ExportResult<DynamicImage> {
        let width = texture.width();
        let height = texture.height();

        if width == 0 || height == 0 {
            return Err("Width or height of this texture is zero".to_string());
        }

        let mut pixels = Vec::new();

        for row in 0..height {
            for col in 0..width {
                if let Some(pixel) = texture.get(col, row) {
                    pixels.push(pixel[0]);
                    pixels.push(pixel[1]);
                    pixels.push(pixel[2]);
                    pixels.push(pixel[3]);
                } else {
                    pixels.push(0);
                    pixels.push(0);
                    pixels.push(0);
                    pixels.push(0);
                }
            }
        }

        if let Some(image_buffer) =
            ImageBuffer::<Rgba<u8>, Vec<u8>>::from_raw(width, height, pixels)
        {
            Ok(DynamicImage::ImageRgba8(image_buffer))
        } else {
            Err("Can't export texture".to_string())
        }
    }
}
<|endoftext|>


<commit_before>#[allow(dead_code)];
#[allow(unused_imports)];

use rand::{Rng, task_rng};
use stdtest::BenchHarness;

use super::heap;
use super::merge;
use super::quick;

static SIZE_SORTED: uint = 1000;
static SIZE_SAME: uint = 1000;
static SIZE_MICRO: uint = 10;
static SIZE_SMALL: uint = 100;
static SIZE_MEDIUM: uint = 10000;
static SIZE_LARGE: uint = 100000;

macro_rules! defbench(
    ($name:ident, $sorter:expr, $gen:ident) => (
        #[bench]
        #[cfg($gen)]
        fn $name(b: &mut BenchHarness) {
            let xs = $gen();
            b.iter(|| $sorter(xs.clone()))
        }
    );
)

fn std_sort(xs: &mut [int]) { xs.sort() }
fn micro() -> ~[int] { task_rng().gen_vec(SIZE_MICRO) }
fn small() -> ~[int] { task_rng().gen_vec(SIZE_SMALL) }
fn medium() -> ~[int] { task_rng().gen_vec(SIZE_MEDIUM) }
fn large() -> ~[int] { task_rng().gen_vec(SIZE_LARGE) }
fn sorted() -> ~[int] {
    let mut xs = task_rng().gen_vec(SIZE_SORTED);
    xs.sort();
    return xs
}
fn same() -> ~[int] {
    let x: int = task_rng().gen();
    ::std::iter::Repeat::new(x).take(SIZE_SAME).collect()
}

defbench!(sorted_std, std_sort, sorted)
defbench!(sorted_bogo, bogo, sorted)
defbench!(sorted_insertion, insertion, sorted)
defbench!(sorted_bubble, bubble, sorted)
defbench!(sorted_selection, selection, sorted)
defbench!(sorted_mergesort, merge::sort, sorted)
defbench!(sorted_mergesort_insertion, merge::insertion, sorted)
defbench!(sorted_heapsort_up, heap::up, sorted)
defbench!(sorted_heapsort_down, heap::down, sorted)
defbench!(sorted_quicksort_dumb, quick::dumb, sorted)
defbench!(sorted_quicksort_smart, quick::smart, sorted)
defbench!(sorted_quicksort_insertion, quick::insertion, sorted)

defbench!(same_std, std_sort, same)
defbench!(same_bogo, bogo, same)
defbench!(same_insertion, insertion, same)
defbench!(same_bubble, bubble, same)
defbench!(same_selection, selection, same)
defbench!(same_mergesort, merge::sort, same)
defbench!(same_mergesort_insertion, merge::insertion, same)
defbench!(same_heapsort_up, heap::up, same)
defbench!(same_heapsort_down, heap::down, same)
defbench!(same_quicksort_dumb, quick::dumb, same)
defbench!(same_quicksort_smart, quick::smart, same)
defbench!(same_quicksort_insertion, quick::insertion, same)

defbench!(micro_std, std_sort, micro)
defbench!(micro_insertion, insertion, micro)
defbench!(micro_bubble, bubble, micro)
defbench!(micro_selection, selection, micro)
defbench!(micro_mergesort, merge::sort, micro)
defbench!(micro_mergesort_insertion, merge::insertion, micro)
defbench!(micro_heapsort_up, heap::up, micro)
defbench!(micro_heapsort_down, heap::down, micro)
defbench!(micro_quicksort_dumb, quick::dumb, micro)
defbench!(micro_quicksort_smart, quick::smart, micro)
defbench!(micro_quicksort_insertion, quick::insertion, micro)

defbench!(small_std, std_sort, small)
defbench!(small_insertion, insertion, small)
defbench!(small_bubble, bubble, small)
defbench!(small_selection, selection, small)
defbench!(small_mergesort, merge::sort, small)
defbench!(small_mergesort_insertion, merge::insertion, small)
defbench!(small_heapsort_up, heap::up, small)
defbench!(small_heapsort_down, heap::down, small)
defbench!(small_quicksort_dumb, quick::dumb, small)
defbench!(small_quicksort_smart, quick::smart, small)
defbench!(small_quicksort_insertion, quick::insertion, small)

// We stop benchmarking O(n^2) (and greater) sorting algorithms here. They
// are just too slow.

defbench!(medium_std, std_sort, medium)
defbench!(medium_mergesort, merge::sort, medium)
defbench!(medium_mergesort_insertion, merge::insertion, medium)
defbench!(medium_heapsort_up, heap::up, medium)
defbench!(medium_heapsort_down, heap::down, medium)
defbench!(medium_quicksort_dumb, quick::dumb, medium)
defbench!(medium_quicksort_smart, quick::smart, medium)
defbench!(medium_quicksort_insertion, quick::insertion, medium)

defbench!(large_std, std_sort, large)
defbench!(large_mergesort, merge::sort, large)
defbench!(large_mergesort_insertion, merge::insertion, large)
defbench!(large_heapsort_up, heap::up, large)
defbench!(large_heapsort_down, heap::down, large)
defbench!(large_quicksort_dumb, quick::dumb, large)
defbench!(large_quicksort_smart, quick::smart, large)
defbench!(large_quicksort_insertion, quick::insertion, large)

<commit_msg>Explicitly import sorting algorithms.<commit_after>#[allow(dead_code)];
#[allow(unused_imports)];

use rand::{Rng, task_rng};
use stdtest::BenchHarness;

use super::heap;
use super::merge;
use super::quick;
use super::{bogo, insertion, bubble, selection};

static SIZE_SORTED: uint = 1000;
static SIZE_SAME: uint = 1000;
static SIZE_MICRO: uint = 10;
static SIZE_SMALL: uint = 100;
static SIZE_MEDIUM: uint = 10000;
static SIZE_LARGE: uint = 100000;

macro_rules! defbench(
    ($name:ident, $sorter:expr, $gen:ident) => (
        #[bench]
        #[cfg($gen)]
        fn $name(b: &mut BenchHarness) {
            let xs = $gen();
            b.iter(|| $sorter(xs.clone()))
        }
    );
)

fn std_sort(xs: &mut [int]) { xs.sort() }
fn micro() -> ~[int] { task_rng().gen_vec(SIZE_MICRO) }
fn small() -> ~[int] { task_rng().gen_vec(SIZE_SMALL) }
fn medium() -> ~[int] { task_rng().gen_vec(SIZE_MEDIUM) }
fn large() -> ~[int] { task_rng().gen_vec(SIZE_LARGE) }
fn sorted() -> ~[int] {
    let mut xs = task_rng().gen_vec(SIZE_SORTED);
    xs.sort();
    return xs
}
fn same() -> ~[int] {
    let x: int = task_rng().gen();
    ::std::iter::Repeat::new(x).take(SIZE_SAME).collect()
}

defbench!(sorted_std, std_sort, sorted)
defbench!(sorted_bogo, bogo, sorted)
defbench!(sorted_insertion, insertion, sorted)
defbench!(sorted_bubble, bubble, sorted)
defbench!(sorted_selection, selection, sorted)
defbench!(sorted_mergesort, merge::sort, sorted)
defbench!(sorted_mergesort_insertion, merge::insertion, sorted)
defbench!(sorted_heapsort_up, heap::up, sorted)
defbench!(sorted_heapsort_down, heap::down, sorted)
defbench!(sorted_quicksort_dumb, quick::dumb, sorted)
defbench!(sorted_quicksort_smart, quick::smart, sorted)
defbench!(sorted_quicksort_insertion, quick::insertion, sorted)

defbench!(same_std, std_sort, same)
defbench!(same_bogo, bogo, same)
defbench!(same_insertion, insertion, same)
defbench!(same_bubble, bubble, same)
defbench!(same_selection, selection, same)
defbench!(same_mergesort, merge::sort, same)
defbench!(same_mergesort_insertion, merge::insertion, same)
defbench!(same_heapsort_up, heap::up, same)
defbench!(same_heapsort_down, heap::down, same)
defbench!(same_quicksort_dumb, quick::dumb, same)
defbench!(same_quicksort_smart, quick::smart, same)
defbench!(same_quicksort_insertion, quick::insertion, same)

defbench!(micro_std, std_sort, micro)
defbench!(micro_insertion, insertion, micro)
defbench!(micro_bubble, bubble, micro)
defbench!(micro_selection, selection, micro)
defbench!(micro_mergesort, merge::sort, micro)
defbench!(micro_mergesort_insertion, merge::insertion, micro)
defbench!(micro_heapsort_up, heap::up, micro)
defbench!(micro_heapsort_down, heap::down, micro)
defbench!(micro_quicksort_dumb, quick::dumb, micro)
defbench!(micro_quicksort_smart, quick::smart, micro)
defbench!(micro_quicksort_insertion, quick::insertion, micro)

defbench!(small_std, std_sort, small)
defbench!(small_insertion, insertion, small)
defbench!(small_bubble, bubble, small)
defbench!(small_selection, selection, small)
defbench!(small_mergesort, merge::sort, small)
defbench!(small_mergesort_insertion, merge::insertion, small)
defbench!(small_heapsort_up, heap::up, small)
defbench!(small_heapsort_down, heap::down, small)
defbench!(small_quicksort_dumb, quick::dumb, small)
defbench!(small_quicksort_smart, quick::smart, small)
defbench!(small_quicksort_insertion, quick::insertion, small)

// We stop benchmarking O(n^2) (and greater) sorting algorithms here. They
// are just too slow.

defbench!(medium_std, std_sort, medium)
defbench!(medium_mergesort, merge::sort, medium)
defbench!(medium_mergesort_insertion, merge::insertion, medium)
defbench!(medium_heapsort_up, heap::up, medium)
defbench!(medium_heapsort_down, heap::down, medium)
defbench!(medium_quicksort_dumb, quick::dumb, medium)
defbench!(medium_quicksort_smart, quick::smart, medium)
defbench!(medium_quicksort_insertion, quick::insertion, medium)

defbench!(large_std, std_sort, large)
defbench!(large_mergesort, merge::sort, large)
defbench!(large_mergesort_insertion, merge::insertion, large)
defbench!(large_heapsort_up, heap::up, large)
defbench!(large_heapsort_down, heap::down, large)
defbench!(large_quicksort_dumb, quick::dumb, large)
defbench!(large_quicksort_smart, quick::smart, large)
defbench!(large_quicksort_insertion, quick::insertion, large)

<|endoftext|>


<commit_before>use std::fmt;
use std::marker::PhantomData;
use std::mem;
use translate::*;

/// Wrapper implementations for Boxed types. See `glib_wrapper!`.
#[macro_export]
macro_rules! glib_boxed_wrapper {
    ([$($attr:meta)*] $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr,
     @free $free_arg:ident $free_expr:expr) => {
        $(#[$attr])*
        #[derive(Clone, Debug)]
        pub struct $name($crate::boxed::Boxed<$ffi_name, MemoryManager>);

        #[doc(hidden)]
        pub struct MemoryManager;

        impl $crate::boxed::BoxedMemoryManager<$ffi_name> for MemoryManager {
            #[inline]
            unsafe fn copy($copy_arg: *const $ffi_name) -> *mut $ffi_name {
                $copy_expr
            }

            #[inline]
            unsafe fn free($free_arg: *mut $ffi_name) {
                $free_expr
            }
        }

        impl $crate::translate::Uninitialized for $name {
            #[inline]
            unsafe fn uninitialized() -> Self {
                $name($crate::boxed::Boxed::uninitialized())
            }
        }

        impl $crate::translate::GlibPtrDefault for $name {
            type GlibType = *mut $ffi_name;
        }

        impl<'a> $crate::translate::ToGlibPtr<'a, *const $ffi_name> for $name {
            type Storage = &'a $crate::boxed::Boxed<$ffi_name, MemoryManager>;

            #[inline]
            fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *const $ffi_name, Self> {
                let stash = self.0.to_glib_none();
                $crate::translate::Stash(stash.0, stash.1)
            }
        }

        impl<'a> $crate::translate::ToGlibPtrMut<'a, *mut $ffi_name> for $name {
            type Storage = &'a mut $crate::boxed::Boxed<$ffi_name, MemoryManager>;

            #[inline]
            fn to_glib_none_mut(&'a mut self) -> $crate::translate::StashMut<'a, *mut $ffi_name, Self> {
                let stash = self.0.to_glib_none_mut();
                $crate::translate::StashMut(stash.0, stash.1)
            }
        }

        impl $crate::translate::FromGlibPtr<*mut $ffi_name> for $name {
            #[inline]
            unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self {
                $name($crate::translate::from_glib_none(ptr))
            }

            #[inline]
            unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self {
                $name($crate::translate::from_glib_full(ptr))
            }

            #[inline]
            unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> Self {
                $name($crate::translate::from_glib_borrow(ptr))
            }
        }
    }
}

enum AnyBox<T> {
    Native(Box<T>),
    ForeignOwned(*mut T),
    ForeignBorrowed(*mut T),
}

impl<T> fmt::Debug for AnyBox<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::AnyBox::*;
        match *self {
            Native(ref b) => write!(f, "AnyBox::Native({:?})", &**b as *const T),
            ForeignOwned(ptr) => write!(f, "AnyBox::ForeignOwned({:?})", ptr),
            ForeignBorrowed(ptr) => write!(f, "AnyBox::ForeignBorrowed({:?})", ptr),
        }
    }
}

/// Memory management functions for a boxed type.
pub trait BoxedMemoryManager<T>: 'static {
    /// Makes a copy.
    unsafe fn copy(ptr: *const T) -> *mut T;
    /// Frees the object.
    unsafe fn free(ptr: *mut T);
}

/// Encapsulates memory management logic for boxed types.
pub struct Boxed<T: 'static, MM: BoxedMemoryManager<T>> {
    inner: AnyBox<T>,
    _dummy: PhantomData<MM>,
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Boxed<T, MM> {
    #[inline]
    pub unsafe fn uninitialized() -> Self {
        Boxed {
            inner: AnyBox::Native(Box::new(mem::uninitialized())),
            _dummy: PhantomData,
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Uninitialized for Boxed<T, MM> {
    #[inline]
    unsafe fn uninitialized() -> Self {
        Boxed {
            inner: AnyBox::Native(Box::new(mem::uninitialized())),
            _dummy: PhantomData,
        }
    }
}

impl<'a, T: 'static, MM: BoxedMemoryManager<T>> ToGlibPtr<'a, *const T> for Boxed<T, MM> {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *const T, Self> {
        use self::AnyBox::*;
        let ptr = match self.inner {
            Native(ref b) => &**b as *const T,
            ForeignOwned(p) | ForeignBorrowed(p) => p as *const T,
        };
        Stash(ptr, self)
    }
}

impl<'a, T: 'static, MM: BoxedMemoryManager<T>> ToGlibPtrMut<'a, *mut T> for Boxed<T, MM> {
    type Storage = &'a mut Self;

    #[inline]
    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut T, Self> {
        use self::AnyBox::*;
        let ptr = match self.inner {
            Native(ref mut b) => &mut **b as *mut T,
            ForeignOwned(p) | ForeignBorrowed(p) => p,
        };
        StashMut(ptr, self)
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> FromGlibPtr<*mut T> for Boxed<T, MM> {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut T) -> Self {
        assert!(!ptr.is_null());
        let ptr = MM::copy(ptr);
        from_glib_full(ptr)
    }

    #[inline]
    unsafe fn from_glib_full(ptr: *mut T) -> Self {
        assert!(!ptr.is_null());
        Boxed {
            inner: AnyBox::ForeignOwned(ptr),
            _dummy: PhantomData,
        }
    }

    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut T) -> Self {
        assert!(!ptr.is_null());
        Boxed {
            inner: AnyBox::ForeignBorrowed(ptr),
            _dummy: PhantomData,
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Drop for Boxed<T, MM> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            if let AnyBox::ForeignOwned(ptr) = self.inner {
                MM::free(ptr);
            }
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> fmt::Debug for Boxed<T, MM> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Boxed {{ inner: {:?} }}", self.inner)
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Clone for Boxed<T, MM> {
    #[inline]
    fn clone(&self) -> Self {
        unsafe {
            from_glib_none(self.to_glib_none().0 as *mut T)
        }
    }
}
<commit_msg>Adjust `Debug` impl slightly<commit_after>use std::fmt;
use std::marker::PhantomData;
use std::mem;
use translate::*;

/// Wrapper implementations for Boxed types. See `glib_wrapper!`.
#[macro_export]
macro_rules! glib_boxed_wrapper {
    ([$($attr:meta)*] $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr,
     @free $free_arg:ident $free_expr:expr) => {
        $(#[$attr])*
        #[derive(Clone, Debug)]
        pub struct $name($crate::boxed::Boxed<$ffi_name, MemoryManager>);

        #[doc(hidden)]
        pub struct MemoryManager;

        impl $crate::boxed::BoxedMemoryManager<$ffi_name> for MemoryManager {
            #[inline]
            unsafe fn copy($copy_arg: *const $ffi_name) -> *mut $ffi_name {
                $copy_expr
            }

            #[inline]
            unsafe fn free($free_arg: *mut $ffi_name) {
                $free_expr
            }
        }

        impl $crate::translate::Uninitialized for $name {
            #[inline]
            unsafe fn uninitialized() -> Self {
                $name($crate::boxed::Boxed::uninitialized())
            }
        }

        impl $crate::translate::GlibPtrDefault for $name {
            type GlibType = *mut $ffi_name;
        }

        impl<'a> $crate::translate::ToGlibPtr<'a, *const $ffi_name> for $name {
            type Storage = &'a $crate::boxed::Boxed<$ffi_name, MemoryManager>;

            #[inline]
            fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *const $ffi_name, Self> {
                let stash = self.0.to_glib_none();
                $crate::translate::Stash(stash.0, stash.1)
            }
        }

        impl<'a> $crate::translate::ToGlibPtrMut<'a, *mut $ffi_name> for $name {
            type Storage = &'a mut $crate::boxed::Boxed<$ffi_name, MemoryManager>;

            #[inline]
            fn to_glib_none_mut(&'a mut self) -> $crate::translate::StashMut<'a, *mut $ffi_name, Self> {
                let stash = self.0.to_glib_none_mut();
                $crate::translate::StashMut(stash.0, stash.1)
            }
        }

        impl $crate::translate::FromGlibPtr<*mut $ffi_name> for $name {
            #[inline]
            unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self {
                $name($crate::translate::from_glib_none(ptr))
            }

            #[inline]
            unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self {
                $name($crate::translate::from_glib_full(ptr))
            }

            #[inline]
            unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> Self {
                $name($crate::translate::from_glib_borrow(ptr))
            }
        }
    }
}

enum AnyBox<T> {
    Native(Box<T>),
    ForeignOwned(*mut T),
    ForeignBorrowed(*mut T),
}

impl<T> fmt::Debug for AnyBox<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::AnyBox::*;
        match *self {
            Native(ref b) => write!(f, "Native({:?})", &**b as *const T),
            ForeignOwned(ptr) => write!(f, "ForeignOwned({:?})", ptr),
            ForeignBorrowed(ptr) => write!(f, "ForeignBorrowed({:?})", ptr),
        }
    }
}

/// Memory management functions for a boxed type.
pub trait BoxedMemoryManager<T>: 'static {
    /// Makes a copy.
    unsafe fn copy(ptr: *const T) -> *mut T;
    /// Frees the object.
    unsafe fn free(ptr: *mut T);
}

/// Encapsulates memory management logic for boxed types.
pub struct Boxed<T: 'static, MM: BoxedMemoryManager<T>> {
    inner: AnyBox<T>,
    _dummy: PhantomData<MM>,
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Boxed<T, MM> {
    #[inline]
    pub unsafe fn uninitialized() -> Self {
        Boxed {
            inner: AnyBox::Native(Box::new(mem::uninitialized())),
            _dummy: PhantomData,
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Uninitialized for Boxed<T, MM> {
    #[inline]
    unsafe fn uninitialized() -> Self {
        Boxed {
            inner: AnyBox::Native(Box::new(mem::uninitialized())),
            _dummy: PhantomData,
        }
    }
}

impl<'a, T: 'static, MM: BoxedMemoryManager<T>> ToGlibPtr<'a, *const T> for Boxed<T, MM> {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *const T, Self> {
        use self::AnyBox::*;
        let ptr = match self.inner {
            Native(ref b) => &**b as *const T,
            ForeignOwned(p) | ForeignBorrowed(p) => p as *const T,
        };
        Stash(ptr, self)
    }
}

impl<'a, T: 'static, MM: BoxedMemoryManager<T>> ToGlibPtrMut<'a, *mut T> for Boxed<T, MM> {
    type Storage = &'a mut Self;

    #[inline]
    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut T, Self> {
        use self::AnyBox::*;
        let ptr = match self.inner {
            Native(ref mut b) => &mut **b as *mut T,
            ForeignOwned(p) | ForeignBorrowed(p) => p,
        };
        StashMut(ptr, self)
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> FromGlibPtr<*mut T> for Boxed<T, MM> {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut T) -> Self {
        assert!(!ptr.is_null());
        let ptr = MM::copy(ptr);
        from_glib_full(ptr)
    }

    #[inline]
    unsafe fn from_glib_full(ptr: *mut T) -> Self {
        assert!(!ptr.is_null());
        Boxed {
            inner: AnyBox::ForeignOwned(ptr),
            _dummy: PhantomData,
        }
    }

    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut T) -> Self {
        assert!(!ptr.is_null());
        Boxed {
            inner: AnyBox::ForeignBorrowed(ptr),
            _dummy: PhantomData,
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Drop for Boxed<T, MM> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            if let AnyBox::ForeignOwned(ptr) = self.inner {
                MM::free(ptr);
            }
        }
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> fmt::Debug for Boxed<T, MM> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Boxed {{ inner: {:?} }}", self.inner)
    }
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Clone for Boxed<T, MM> {
    #[inline]
    fn clone(&self) -> Self {
        unsafe {
            from_glib_none(self.to_glib_none().0 as *mut T)
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::io::Read;
use std::path::PathBuf;

#[cfg(unix)]
use std::os::unix::fs::MetadataExt;

use reqwest;
use flate2::read::GzDecoder;
use tar::Archive;
use time;
use walkdir::{DirEntry, WalkDir};
use xdg::BaseDirectories;

use error::TealdeerError::{self, CacheError, UpdateError};
use types::OsType;

#[derive(Debug)]
pub struct Cache {
    url: String,
    os: OsType,
}

impl Cache {
    pub fn new<S>(url: S, os: OsType) -> Cache
    where
        S: Into<String>,
    {
        Cache {
            url: url.into(),
            os: os,
        }
    }

    /// Return the path to the cache directory.
    fn get_cache_dir(&self) -> Result<PathBuf, TealdeerError> {
        // Allow overriding the cache directory by setting the
        // $TEALDEER_CACHE_DIR env variable.
        if let Ok(value) = env::var("TEALDEER_CACHE_DIR") {
            let path = PathBuf::from(value);

            if path.exists() && path.is_dir() {
                return Ok(path);
            } else {
                return Err(CacheError(
                    "Path specified by $TEALDEER_CACHE_DIR \
                     does not exist or is not a directory."
                        .into(),
                ));
            }
        };

        // Otherwise, fall back to $XDG_CACHE_HOME/tealdeer.
        let xdg_dirs = match BaseDirectories::with_prefix(::NAME) {
            Ok(dirs) => dirs,
            Err(_) => return Err(CacheError("Could not determine XDG base directory.".into())),
        };
        Ok(xdg_dirs.get_cache_home())
    }

    /// Download the archive
    fn download(&self) -> Result<Vec<u8>, TealdeerError> {
        let mut resp = reqwest::get(&self.url)?;
        let mut buf: Vec<u8> = vec![];
        let bytes_downloaded = resp.copy_to(&mut buf)?;
        debug!("{} bytes downloaded", bytes_downloaded);
        Ok(buf)
    }

    /// Decompress and open the archive
    fn decompress<R: Read>(&self, reader: R) -> Archive<GzDecoder<R>> {
        Archive::new(GzDecoder::new(reader))
    }

    /// Update the pages cache.
    pub fn update(&self) -> Result<(), TealdeerError> {
        // First, download the compressed data
        let bytes: Vec<u8> = try!(self.download());

        // Decompress the response body into an `Archive`
        let mut archive = self.decompress(&bytes[..]);

        // Determine paths
        let cache_dir = try!(self.get_cache_dir());

        // Make sure that cache directory exists
        debug!("Ensure cache directory {:?} exists", &cache_dir);
        try!(
            fs::create_dir_all(&cache_dir)
                .map_err(|e| UpdateError(format!("Could not create cache directory: {}", e)))
        );

        // Clear cache directory
        // Note: This is not the best solution. Ideally we would download the
        // archive to a temporary directory and then swap the two directories.
        // But renaming a directory doesn't work across filesystems and Rust
        // does not yet offer a recursive directory copying function. So for
        // now, we'll use this approach.
        try!(self.clear());

        // Extract archive
        try!(
            archive
                .unpack(&cache_dir)
                .map_err(|e| UpdateError(format!("Could not unpack compressed data: {}", e)))
        );

        Ok(())
    }

    #[cfg(unix)]
    /// Return the number of seconds since the cache directory was last modified.
    pub fn last_update(&self) -> Option<i64> {
        if let Ok(cache_dir) = self.get_cache_dir() {
            if let Ok(metadata) = fs::metadata(cache_dir.join("tldr-master")) {
                let mtime = metadata.mtime();
                let now = time::now_utc().to_timespec();
                return Some(now.sec - mtime);
            };
        };
        None
    }

    /// Return the platform directory.
    fn get_platform_dir(&self) -> Option<&'static str> {
        match self.os {
            OsType::Linux => Some("linux"),
            OsType::OsX => Some("osx"),
            OsType::SunOs => None, // TODO: Does Rust support SunOS?
            OsType::Other => None,
        }
    }

    /// Search for a page and return the path to it.
    pub fn find_page(&self, name: &str) -> Option<PathBuf> {
        // Build page file name
        let page_filename = format!("{}.md", name);

        // Get platform dir
        let platforms_dir = match self.get_cache_dir() {
            Ok(cache_dir) => cache_dir.join("tldr-master").join("pages"),
            _ => return None,
        };

        // Determine platform
        let platform = self.get_platform_dir();

        // Search for the page in the platform specific directory
        if let Some(pf) = platform {
            let path = platforms_dir.join(&pf).join(&page_filename);
            if path.exists() && path.is_file() {
                return Some(path);
            }
        }

        // If platform is not supported or if platform specific page does not exist,
        // look up the page in the "common" directory.
        let path = platforms_dir.join("common").join(&page_filename);

        // Return it if it exists, otherwise give up and return `None`
        if path.exists() && path.is_file() {
            Some(path)
        } else {
            None
        }
    }

    /// Return the available pages.
    pub fn list_pages(&self) -> Result<Vec<String>, TealdeerError> {
        // Determine platforms directory and platform
        let cache_dir = try!(self.get_cache_dir());
        let platforms_dir = cache_dir.join("tldr-master").join("pages");
        let platform_dir = self.get_platform_dir();

        // Closure that allows the WalkDir instance to traverse platform
        // specific and common page directories, but not others.
        let should_walk = |entry: &DirEntry| -> bool {
            let file_type = entry.file_type();
            let file_name = match entry.file_name().to_str() {
                Some(name) => name,
                None => return false,
            };
            if file_type.is_dir() {
                if file_name == "common" {
                    return true;
                }
                if let Some(platform) = platform_dir {
                    return file_name == platform;
                }
            } else if file_type.is_file() {
                return true;
            }
            false
        };

        // Recursively walk through common and (if applicable) platform specific directory
        let mut pages = WalkDir::new(platforms_dir)
            .min_depth(1) // Skip root directory
            .into_iter()
            .filter_entry(|e| should_walk(e)) // Filter out pages for other architectures
            .filter_map(|e| e.ok()) // Convert results to options, filter out errors
            .filter_map(|e| {
                let path = e.path();
                let extension = &path.extension().and_then(|s| s.to_str()).unwrap_or("");
                if e.file_type().is_file() && extension == &"md" {
                    path.file_stem()
                        .and_then(|stem| stem.to_str().map(|s| s.into()))
                } else {
                    None
                }
            })
            .collect::<Vec<String>>();
        pages.sort();
        pages.dedup();
        Ok(pages)
    }

    /// Delete the cache directory.
    pub fn clear(&self) -> Result<(), TealdeerError> {
        let path = try!(self.get_cache_dir());
        if path.exists() && path.is_dir() {
            try!(fs::remove_dir_all(&path).map_err(|_| CacheError(format!(
                "Could not remove cache directory ({}).",
                path.display()
            ))));
        } else if path.exists() {
            return Err(CacheError(format!(
                "Cache path ({}) is not a directory.",
                path.display()
            )));
        } else {
            return Err(CacheError(format!(
                "Cache path ({}) does not exist.",
                path.display()
            )));
        };
        Ok(())
    }
}
<commit_msg>Add (back) support for proxies (#68)<commit_after>use std::env;
use std::fs;
use std::io::Read;
use std::path::PathBuf;

#[cfg(unix)]
use std::os::unix::fs::MetadataExt;

use reqwest::{Client, Proxy};
use flate2::read::GzDecoder;
use tar::Archive;
use time;
use walkdir::{DirEntry, WalkDir};
use xdg::BaseDirectories;

use error::TealdeerError::{self, CacheError, UpdateError};
use types::OsType;

#[derive(Debug)]
pub struct Cache {
    url: String,
    os: OsType,
}

impl Cache {
    pub fn new<S>(url: S, os: OsType) -> Cache
    where
        S: Into<String>,
    {
        Cache {
            url: url.into(),
            os: os,
        }
    }

    /// Return the path to the cache directory.
    fn get_cache_dir(&self) -> Result<PathBuf, TealdeerError> {
        // Allow overriding the cache directory by setting the
        // $TEALDEER_CACHE_DIR env variable.
        if let Ok(value) = env::var("TEALDEER_CACHE_DIR") {
            let path = PathBuf::from(value);

            if path.exists() && path.is_dir() {
                return Ok(path);
            } else {
                return Err(CacheError(
                    "Path specified by $TEALDEER_CACHE_DIR \
                     does not exist or is not a directory."
                        .into(),
                ));
            }
        };

        // Otherwise, fall back to $XDG_CACHE_HOME/tealdeer.
        let xdg_dirs = match BaseDirectories::with_prefix(::NAME) {
            Ok(dirs) => dirs,
            Err(_) => return Err(CacheError("Could not determine XDG base directory.".into())),
        };
        Ok(xdg_dirs.get_cache_home())
    }

    /// Download the archive
    fn download(&self) -> Result<Vec<u8>, TealdeerError> {
        let mut builder = Client::builder();
        if let Ok(ref host) = env::var("HTTP_PROXY") {
            if let Ok(proxy) = Proxy::http(host) {
                builder = builder.proxy(proxy);
            }
        }
        if let Ok(ref host) = env::var("HTTPS_PROXY") {
            if let Ok(proxy) = Proxy::https(host) {
                builder = builder.proxy(proxy);
            }
        }
        let client = builder.build().unwrap_or_else(|_| Client::new());
        let mut resp = client.get(&self.url).send()?;
        let mut buf: Vec<u8> = vec![];
        let bytes_downloaded = resp.copy_to(&mut buf)?;
        debug!("{} bytes downloaded", bytes_downloaded);
        Ok(buf)
    }

    /// Decompress and open the archive
    fn decompress<R: Read>(&self, reader: R) -> Archive<GzDecoder<R>> {
        Archive::new(GzDecoder::new(reader))
    }

    /// Update the pages cache.
    pub fn update(&self) -> Result<(), TealdeerError> {
        // First, download the compressed data
        let bytes: Vec<u8> = try!(self.download());

        // Decompress the response body into an `Archive`
        let mut archive = self.decompress(&bytes[..]);

        // Determine paths
        let cache_dir = try!(self.get_cache_dir());

        // Make sure that cache directory exists
        debug!("Ensure cache directory {:?} exists", &cache_dir);
        try!(
            fs::create_dir_all(&cache_dir)
                .map_err(|e| UpdateError(format!("Could not create cache directory: {}", e)))
        );

        // Clear cache directory
        // Note: This is not the best solution. Ideally we would download the
        // archive to a temporary directory and then swap the two directories.
        // But renaming a directory doesn't work across filesystems and Rust
        // does not yet offer a recursive directory copying function. So for
        // now, we'll use this approach.
        try!(self.clear());

        // Extract archive
        try!(
            archive
                .unpack(&cache_dir)
                .map_err(|e| UpdateError(format!("Could not unpack compressed data: {}", e)))
        );

        Ok(())
    }

    #[cfg(unix)]
    /// Return the number of seconds since the cache directory was last modified.
    pub fn last_update(&self) -> Option<i64> {
        if let Ok(cache_dir) = self.get_cache_dir() {
            if let Ok(metadata) = fs::metadata(cache_dir.join("tldr-master")) {
                let mtime = metadata.mtime();
                let now = time::now_utc().to_timespec();
                return Some(now.sec - mtime);
            };
        };
        None
    }

    /// Return the platform directory.
    fn get_platform_dir(&self) -> Option<&'static str> {
        match self.os {
            OsType::Linux => Some("linux"),
            OsType::OsX => Some("osx"),
            OsType::SunOs => None, // TODO: Does Rust support SunOS?
            OsType::Other => None,
        }
    }

    /// Search for a page and return the path to it.
    pub fn find_page(&self, name: &str) -> Option<PathBuf> {
        // Build page file name
        let page_filename = format!("{}.md", name);

        // Get platform dir
        let platforms_dir = match self.get_cache_dir() {
            Ok(cache_dir) => cache_dir.join("tldr-master").join("pages"),
            _ => return None,
        };

        // Determine platform
        let platform = self.get_platform_dir();

        // Search for the page in the platform specific directory
        if let Some(pf) = platform {
            let path = platforms_dir.join(&pf).join(&page_filename);
            if path.exists() && path.is_file() {
                return Some(path);
            }
        }

        // If platform is not supported or if platform specific page does not exist,
        // look up the page in the "common" directory.
        let path = platforms_dir.join("common").join(&page_filename);

        // Return it if it exists, otherwise give up and return `None`
        if path.exists() && path.is_file() {
            Some(path)
        } else {
            None
        }
    }

    /// Return the available pages.
    pub fn list_pages(&self) -> Result<Vec<String>, TealdeerError> {
        // Determine platforms directory and platform
        let cache_dir = try!(self.get_cache_dir());
        let platforms_dir = cache_dir.join("tldr-master").join("pages");
        let platform_dir = self.get_platform_dir();

        // Closure that allows the WalkDir instance to traverse platform
        // specific and common page directories, but not others.
        let should_walk = |entry: &DirEntry| -> bool {
            let file_type = entry.file_type();
            let file_name = match entry.file_name().to_str() {
                Some(name) => name,
                None => return false,
            };
            if file_type.is_dir() {
                if file_name == "common" {
                    return true;
                }
                if let Some(platform) = platform_dir {
                    return file_name == platform;
                }
            } else if file_type.is_file() {
                return true;
            }
            false
        };

        // Recursively walk through common and (if applicable) platform specific directory
        let mut pages = WalkDir::new(platforms_dir)
            .min_depth(1) // Skip root directory
            .into_iter()
            .filter_entry(|e| should_walk(e)) // Filter out pages for other architectures
            .filter_map(|e| e.ok()) // Convert results to options, filter out errors
            .filter_map(|e| {
                let path = e.path();
                let extension = &path.extension().and_then(|s| s.to_str()).unwrap_or("");
                if e.file_type().is_file() && extension == &"md" {
                    path.file_stem()
                        .and_then(|stem| stem.to_str().map(|s| s.into()))
                } else {
                    None
                }
            })
            .collect::<Vec<String>>();
        pages.sort();
        pages.dedup();
        Ok(pages)
    }

    /// Delete the cache directory.
    pub fn clear(&self) -> Result<(), TealdeerError> {
        let path = try!(self.get_cache_dir());
        if path.exists() && path.is_dir() {
            try!(fs::remove_dir_all(&path).map_err(|_| CacheError(format!(
                "Could not remove cache directory ({}).",
                path.display()
            ))));
        } else if path.exists() {
            return Err(CacheError(format!(
                "Cache path ({}) is not a directory.",
                path.display()
            )));
        } else {
            return Err(CacheError(format!(
                "Cache path ({}) does not exist.",
                path.display()
            )));
        };
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Prepared statements cache for faster execution.

use std::cell::RefCell;
use std::ops::{Deref, DerefMut};
use lru_cache::LruCache;
use {Result, Connection, Statement};
use raw_statement::RawStatement;

impl Connection {
    /// Prepare a SQL statement for execution, returning a previously prepared (but
    /// not currently in-use) statement if one is available. The returned statement
    /// will be cached for reuse by future calls to `prepare_cached` once it is
    /// dropped.
    ///
    /// ```rust,no_run
    /// # use rusqlite::{Connection, Result};
    /// fn insert_new_people(conn: &Connection) -> Result<()> {
    ///     {
    ///         let mut stmt = try!(conn.prepare_cached("INSERT INTO People (name) VALUES (?)"));
    ///         try!(stmt.execute(&[&"Joe Smith"]));
    ///     }
    ///     {
    ///         // This will return the same underlying SQLite statement handle without
    ///         // having to prepare it again.
    ///         let mut stmt = try!(conn.prepare_cached("INSERT INTO People (name) VALUES (?)"));
    ///         try!(stmt.execute(&[&"Bob Jones"]));
    ///     }
    ///     Ok(())
    /// }
    /// ```
    ///
    /// # Failure
    ///
    /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
    /// underlying SQLite call fails.
    pub fn prepare_cached<'a>(&'a self, sql: &str) -> Result<CachedStatement<'a>> {
        self.cache.get(&self, sql)
    }

    /// Set the maximum number of cached prepared statements this connection will hold.
    /// By default, a connection will hold a relatively small number of cached statements.
    /// If you need more, or know that you will not use cached statements, you can set
    /// the capacity manually using this method.
    pub fn set_prepared_statement_cache_capacity(&self, capacity: usize) {
        self.cache.set_capacity(capacity)
    }
}

/// Prepared statements LRU cache.
#[derive(Debug)]
pub struct StatementCache(RefCell<LruCache<String, RawStatement>>);

/// Cacheable statement.
///
/// Statement will return automatically to the cache by default.
/// If you want the statement to be discarded, call `discard()` on it.
pub struct CachedStatement<'conn> {
    stmt: Option<Statement<'conn>>,
    cache: &'conn StatementCache,
}

impl<'conn> Deref for CachedStatement<'conn> {
    type Target = Statement<'conn>;

    fn deref(&self) -> &Statement<'conn> {
        self.stmt.as_ref().unwrap()
    }
}

impl<'conn> DerefMut for CachedStatement<'conn> {
    fn deref_mut(&mut self) -> &mut Statement<'conn> {
        self.stmt.as_mut().unwrap()
    }
}

impl<'conn> Drop for CachedStatement<'conn> {
    #[allow(unused_must_use)]
    fn drop(&mut self) {
        if let Some(stmt) = self.stmt.take() {
            self.cache.cache_stmt(stmt.into());
        }
    }
}

impl<'conn> CachedStatement<'conn> {
    fn new(stmt: Statement<'conn>, cache: &'conn StatementCache) -> CachedStatement<'conn> {
        CachedStatement {
            stmt: Some(stmt),
            cache: cache,
        }
    }

    pub fn discard(mut self) {
        self.stmt = None;
    }
}

impl StatementCache {
    /// Create a statement cache.
    pub fn with_capacity(capacity: usize) -> StatementCache {
        StatementCache(RefCell::new(LruCache::new(capacity)))
    }

    fn set_capacity(&self, capacity: usize) {
        self.0.borrow_mut().set_capacity(capacity)
    }

    // Search the cache for a prepared-statement object that implements `sql`.
    // If no such prepared-statement can be found, allocate and prepare a new one.
    //
    // # Failure
    //
    // Will return `Err` if no cached statement can be found and the underlying SQLite prepare
    // call fails.
    fn get<'conn>(&'conn self,
                  conn: &'conn Connection,
                  sql: &str)
                  -> Result<CachedStatement<'conn>> {
        let mut cache = self.0.borrow_mut();
        let stmt = match cache.remove(sql) {
            Some(raw_stmt) => Ok(Statement::new(conn, raw_stmt)),
            None => conn.prepare(sql),
        };
        stmt.map(|stmt| CachedStatement::new(stmt, self))
    }

    // Return a statement to the cache.
    fn cache_stmt(&self, stmt: RawStatement) {
        let mut cache = self.0.borrow_mut();
        stmt.clear_bindings();
        let sql = String::from_utf8_lossy(stmt.sql().to_bytes()).to_string();
        cache.insert(sql, stmt);
    }
}

#[cfg(test)]
mod test {
    use Connection;
    use super::StatementCache;

    impl StatementCache {
        fn clear(&self) {
            self.0.borrow_mut().clear();
        }

        fn len(&self) -> usize {
            self.0.borrow().len()
        }

        fn capacity(&self) -> usize {
            self.0.borrow().capacity()
        }
    }

    #[test]
    fn test_cache() {
        let db = Connection::open_in_memory().unwrap();
        let cache = &db.cache;
        let initial_capacity = cache.capacity();
        assert_eq!(0, cache.len());
        assert!(initial_capacity > 0);

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
        }
        assert_eq!(1, cache.len());

        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
        }
        assert_eq!(1, cache.len());

        cache.clear();
        assert_eq!(0, cache.len());
        assert_eq!(initial_capacity, cache.capacity());
    }

    #[test]
    fn test_set_capacity() {
        let db = Connection::open_in_memory().unwrap();
        let cache = &db.cache;

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
        }
        assert_eq!(1, cache.len());

        db.set_prepared_statement_cache_capacity(0);
        assert_eq!(0, cache.len());

        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
        }
        assert_eq!(0, cache.len());

        db.set_prepared_statement_cache_capacity(8);
        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
        }
        assert_eq!(1, cache.len());
    }

    #[test]
    fn test_discard() {
        let db = Connection::open_in_memory().unwrap();
        let cache = &db.cache;

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
            stmt.discard();
        }
        assert_eq!(0, cache.len());
    }

    #[test]
    fn test_ddl() {
        let db = Connection::open_in_memory().unwrap();
        db.execute_batch(r#"
            CREATE TABLE foo (x INT);
            INSERT INTO foo VALUES (1);
        "#)
            .unwrap();

        let sql = "SELECT * FROM foo";

        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(1i32,
                       stmt.query_map(&[], |r| r.get(0)).unwrap().next().unwrap().unwrap());
        }

        db.execute_batch(r#"
            ALTER TABLE foo ADD COLUMN y INT;
            UPDATE foo SET y = 2;
        "#)
            .unwrap();

        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!((1i32, 2i32),
                       stmt.query_map(&[], |r| (r.get(0), r.get(1)))
                           .unwrap()
                           .next()
                           .unwrap()
                           .unwrap());
        }
    }
}
<commit_msg>Fix clippy needless_borrow warning<commit_after>//! Prepared statements cache for faster execution.

use std::cell::RefCell;
use std::ops::{Deref, DerefMut};
use lru_cache::LruCache;
use {Result, Connection, Statement};
use raw_statement::RawStatement;

impl Connection {
    /// Prepare a SQL statement for execution, returning a previously prepared (but
    /// not currently in-use) statement if one is available. The returned statement
    /// will be cached for reuse by future calls to `prepare_cached` once it is
    /// dropped.
    ///
    /// ```rust,no_run
    /// # use rusqlite::{Connection, Result};
    /// fn insert_new_people(conn: &Connection) -> Result<()> {
    ///     {
    ///         let mut stmt = try!(conn.prepare_cached("INSERT INTO People (name) VALUES (?)"));
    ///         try!(stmt.execute(&[&"Joe Smith"]));
    ///     }
    ///     {
    ///         // This will return the same underlying SQLite statement handle without
    ///         // having to prepare it again.
    ///         let mut stmt = try!(conn.prepare_cached("INSERT INTO People (name) VALUES (?)"));
    ///         try!(stmt.execute(&[&"Bob Jones"]));
    ///     }
    ///     Ok(())
    /// }
    /// ```
    ///
    /// # Failure
    ///
    /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
    /// underlying SQLite call fails.
    pub fn prepare_cached<'a>(&'a self, sql: &str) -> Result<CachedStatement<'a>> {
        self.cache.get(self, sql)
    }

    /// Set the maximum number of cached prepared statements this connection will hold.
    /// By default, a connection will hold a relatively small number of cached statements.
    /// If you need more, or know that you will not use cached statements, you can set
    /// the capacity manually using this method.
    pub fn set_prepared_statement_cache_capacity(&self, capacity: usize) {
        self.cache.set_capacity(capacity)
    }
}

/// Prepared statements LRU cache.
#[derive(Debug)]
pub struct StatementCache(RefCell<LruCache<String, RawStatement>>);

/// Cacheable statement.
///
/// Statement will return automatically to the cache by default.
/// If you want the statement to be discarded, call `discard()` on it.
pub struct CachedStatement<'conn> {
    stmt: Option<Statement<'conn>>,
    cache: &'conn StatementCache,
}

impl<'conn> Deref for CachedStatement<'conn> {
    type Target = Statement<'conn>;

    fn deref(&self) -> &Statement<'conn> {
        self.stmt.as_ref().unwrap()
    }
}

impl<'conn> DerefMut for CachedStatement<'conn> {
    fn deref_mut(&mut self) -> &mut Statement<'conn> {
        self.stmt.as_mut().unwrap()
    }
}

impl<'conn> Drop for CachedStatement<'conn> {
    #[allow(unused_must_use)]
    fn drop(&mut self) {
        if let Some(stmt) = self.stmt.take() {
            self.cache.cache_stmt(stmt.into());
        }
    }
}

impl<'conn> CachedStatement<'conn> {
    fn new(stmt: Statement<'conn>, cache: &'conn StatementCache) -> CachedStatement<'conn> {
        CachedStatement {
            stmt: Some(stmt),
            cache: cache,
        }
    }

    pub fn discard(mut self) {
        self.stmt = None;
    }
}

impl StatementCache {
    /// Create a statement cache.
    pub fn with_capacity(capacity: usize) -> StatementCache {
        StatementCache(RefCell::new(LruCache::new(capacity)))
    }

    fn set_capacity(&self, capacity: usize) {
        self.0.borrow_mut().set_capacity(capacity)
    }

    // Search the cache for a prepared-statement object that implements `sql`.
    // If no such prepared-statement can be found, allocate and prepare a new one.
    //
    // # Failure
    //
    // Will return `Err` if no cached statement can be found and the underlying SQLite prepare
    // call fails.
    fn get<'conn>(&'conn self,
                  conn: &'conn Connection,
                  sql: &str)
                  -> Result<CachedStatement<'conn>> {
        let mut cache = self.0.borrow_mut();
        let stmt = match cache.remove(sql) {
            Some(raw_stmt) => Ok(Statement::new(conn, raw_stmt)),
            None => conn.prepare(sql),
        };
        stmt.map(|stmt| CachedStatement::new(stmt, self))
    }

    // Return a statement to the cache.
    fn cache_stmt(&self, stmt: RawStatement) {
        let mut cache = self.0.borrow_mut();
        stmt.clear_bindings();
        let sql = String::from_utf8_lossy(stmt.sql().to_bytes()).to_string();
        cache.insert(sql, stmt);
    }
}

#[cfg(test)]
mod test {
    use Connection;
    use super::StatementCache;

    impl StatementCache {
        fn clear(&self) {
            self.0.borrow_mut().clear();
        }

        fn len(&self) -> usize {
            self.0.borrow().len()
        }

        fn capacity(&self) -> usize {
            self.0.borrow().capacity()
        }
    }

    #[test]
    fn test_cache() {
        let db = Connection::open_in_memory().unwrap();
        let cache = &db.cache;
        let initial_capacity = cache.capacity();
        assert_eq!(0, cache.len());
        assert!(initial_capacity > 0);

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
        }
        assert_eq!(1, cache.len());

        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
        }
        assert_eq!(1, cache.len());

        cache.clear();
        assert_eq!(0, cache.len());
        assert_eq!(initial_capacity, cache.capacity());
    }

    #[test]
    fn test_set_capacity() {
        let db = Connection::open_in_memory().unwrap();
        let cache = &db.cache;

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
        }
        assert_eq!(1, cache.len());

        db.set_prepared_statement_cache_capacity(0);
        assert_eq!(0, cache.len());

        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
        }
        assert_eq!(0, cache.len());

        db.set_prepared_statement_cache_capacity(8);
        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
        }
        assert_eq!(1, cache.len());
    }

    #[test]
    fn test_discard() {
        let db = Connection::open_in_memory().unwrap();
        let cache = &db.cache;

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
            stmt.discard();
        }
        assert_eq!(0, cache.len());
    }

    #[test]
    fn test_ddl() {
        let db = Connection::open_in_memory().unwrap();
        db.execute_batch(r#"
            CREATE TABLE foo (x INT);
            INSERT INTO foo VALUES (1);
        "#)
            .unwrap();

        let sql = "SELECT * FROM foo";

        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(1i32,
                       stmt.query_map(&[], |r| r.get(0)).unwrap().next().unwrap().unwrap());
        }

        db.execute_batch(r#"
            ALTER TABLE foo ADD COLUMN y INT;
            UPDATE foo SET y = 2;
        "#)
            .unwrap();

        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!((1i32, 2i32),
                       stmt.query_map(&[], |r| (r.get(0), r.get(1)))
                           .unwrap()
                           .next()
                           .unwrap()
                           .unwrap());
        }
    }
}
<|endoftext|>


<commit_before>extern crate nanomsg;

use nanomsg::{Socket, Protocol};
use std::io::{Read, Write};

const ADDRESS: &'static str = "ipc:///tmp/a.ipc";

fn main() {
    let mut socket = Socket::new(Protocol::Rep).unwrap();
    println!("Connecting to address '{}'", ADDRESS);
    let mut endpoint = socket.bind(ADDRESS).unwrap();

    let mut request = String::new();
    loop {
        println!("Waiting for a message");
        assert!(socket.read_to_string(&mut request).is_ok());
        println!("Received {}", request);

        match request.as_ref() {
            "PING" => {
                reply(&mut socket, "PONG");
            }
            "STOP" => {
                reply(&mut socket, "OK");
                println!("Shutting down");
                break;
            },
            _ => reply(&mut socket, "UNKNOWN REQUEST")
        }

        request.clear();
    }

    assert!(endpoint.shutdown().is_ok());
}

fn reply(socket: &mut Socket, reply: &str) {
    assert!(socket.write_all(reply.as_bytes()).is_ok());
    println!("Replied with '{}'", reply)
}

<commit_msg>Rust: refactor code.<commit_after>extern crate nanomsg;

use nanomsg::{Socket, Protocol};
use std::io::{Read, Write};

const ADDRESS: &'static str = "ipc:///tmp/a.ipc";

fn main() {
    let mut socket = Socket::new(Protocol::Rep).unwrap();
    println!("Connecting to address '{}'", ADDRESS);
    let mut endpoint = socket.bind(ADDRESS).unwrap();

    let mut request = String::new();
    loop {
        println!("Waiting for a message");
        socket.read_to_string(&mut request).unwrap();
        println!("Received '{}'", request);

        match request.as_ref() {
            "PING" => {
                reply(&mut socket, "PONG");
            }
            "STOP" => {
                reply(&mut socket, "OK");
                println!("Shutting down");
                break;
            },
            _ => reply(&mut socket, "UNKNOWN REQUEST")
        }

        request.clear();
    }

    endpoint.shutdown().unwrap();
}

fn reply(socket: &mut Socket, reply: &str) {
    socket.write_all(reply.as_bytes()).unwrap();
    println!("Replied with '{}'", reply)
}

<|endoftext|>