<commit_before>extern crate csv;
extern crate rustc_serialize;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

//////////////////////////////DISTANCES////////////////////////////////
fn manhattan_dist(x: &Vec<f32>, y: &Vec<f32>) -> f32 {
    if x.len() != y.len() {
        panic!("Should compare vectors of same size");
    }

    let mut distance = 0.0;
    for i in 0..x.len() {
        distance += (x[i] - y[i]).abs();
    }

    distance
}

fn euclidian_dist(x: &Vec<f32>, y: &Vec<f32>) -> f32 {
    if x.len() != y.len() {
        panic!("Should compare vectors of same size");
    }
    let mut distance = 0.0;

    for i in 0..x.len() {
        distance += (x[i] - y[i]).powf(2.0);
    }

    distance.sqrt()
}
///////////////////////////////////////////////////////////////////////

struct IndexedDB(HashMap<String, HashMap<String, f32>>, HashMap<String, HashMap<String, f32>>);

fn load_db(path: &str) -> IndexedDB {
    let mut rdr = csv::Reader::from_file(path).unwrap().has_headers(false);
    let mut ratings: HashMap<String, HashMap<String, f32>> = HashMap::new();
    let mut features: HashMap<String, HashMap<String, f32>> = HashMap::new();

    for record in rdr.decode() {
        let (user_id, feat_id, rating): (String, String, f32) = record.unwrap();
        let (user_id2, feat_id2, rating2) = (user_id.clone(), feat_id.clone(), rating);

        match ratings.entry(user_id) {
            Vacant(entry) => {
                let mut user_ratings = HashMap::new();
                user_ratings.insert(feat_id, rating);
                entry.insert(user_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(feat_id, rating);
            }
        }

        match features.entry(feat_id2) {
            Vacant(entry) => {
                let mut movie_ratings = HashMap::new();
                movie_ratings.insert(user_id2, rating2);
                entry.insert(movie_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(user_id2, rating2);
            }
        }
    }

    IndexedDB(ratings, features)
}

fn median(vec: &Vec<f32>) -> f32 {
    let mut vec_cpy = vec.clone();
    vec_cpy.sort_by(|a, b| a.partial_cmp(b).unwrap());
    let length = vec_cpy.len();
    let mid = length / 2;
    let mut ret = vec_cpy[mid];
    if length % 2 == 0 {
        ret += vec_cpy[mid - 1];
        ret /= 2.0;
    }

    ret
}

fn abs_standard_deviation(vec: &Vec<f32>) -> (f32, f32) {
    let median = median(vec);
    let mut asd = 0.0;

    for x in vec.iter() {
        asd += (x - median).abs();
    }

    (asd / vec.len() as f32, median)
}

// fn mod_standard_score(vec: &Vec<f32>) -> Vec<f32> {
//     let (asd, median) = abs_standard_deviation(vec);
//     let mut stnzd_vec = Vec::new();

//     for val in vec.iter() {
//         stnzd_vec.push((val - median) / asd);
//     }

//     stnzd_vec
// }

fn users_rating_vectors(db: &IndexedDB, id1: &str, id2: &str) -> (Vec<f32>, Vec<f32>) {
    let mut usr1_vec: Vec<f32> = Vec::new();
    let mut usr2_vec: Vec<f32> = Vec::new();

    if let Some(ref ratings1) = db.0.get(&String::from(id1)) {
        for (feat1_id, &rating1) in ratings1.iter() {
            usr1_vec.push(rating1);
            if let Some(ref ratings2) = db.0.get(&String::from(id2)) {
                if let Some(rating2) = ratings2.get(feat1_id) {
                    usr2_vec.push(*rating2);
                } else {
                    usr2_vec.push(0.0);
                }
            } else {
                panic!("user2 is not found!");
            }
        }
    } else {
        panic!("user1 not found!");
    }

    if let Some(ref ratings2) = db.0.get(&String::from(id2)) {
        for (feat2_id, &rating2) in ratings2.iter() {
            if let Some(ref ratings1) = db.0.get(&String::from(id1)) {
                if let Some(_) = ratings1.get(feat2_id) {
                } else {
                    usr2_vec.push(rating2);
                    usr1_vec.push(0.0);
                }
            } else {
                panic!("user2 is not found!");
            }
        }
    } else {
        panic!("user1 not found!");
    }

    (usr1_vec, usr2_vec)
}

fn nearest_neighbors(db: &IndexedDB,
                     id: &str,
                     func: fn(&Vec<f32>, &Vec<f32>) -> f32)
                     -> Vec<(f32, String)> {
    let mut dist_vec: Vec<(f32, String)> = Vec::new();

    for (rec_id, _) in db.0.iter() {
        if id != rec_id.as_str() {
            let rec_str = rec_id.clone();
            let (obj_vec, rec_vec) = users_rating_vectors(db, id, rec_id);
            dist_vec.push((func(&obj_vec, &rec_vec), rec_str));
        }
    }

    dist_vec.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
    dist_vec
}

// fn get_feature_vec(db: &IndexedDB, feat_id: &String) -> Vec<f32> {
//     let mut feat_vec: Vec<f32> = Vec::new();

//     if let Some(ref ratings) = db.1.get(feat_id) {
//         for (_, &rating) in ratings.iter() {
//             feat_vec.push(rating);
//         }
//     } else {
//         panic!("Feature not found in DB!");
//     }

//     feat_vec
// }

fn standarize_db(mut db: &mut IndexedDB) {
    for (feat, ratings) in db.1.iter_mut() {
        let mut feat_vec: Vec<f32> = Vec::new();
        for rating in ratings.values() {
            feat_vec.push(*rating);
        }

        let (asd, median) = abs_standard_deviation(&feat_vec);
        for (usr, rating) in ratings.iter_mut() {
            *rating = (*rating - median) / asd;
            *db.0.get_mut(usr).unwrap().get_mut(feat).unwrap() = *rating;
        }
    }
}

fn main() {
    println!("Loading database, please wait...");
    let mut db = load_db("./data/music.csv");
    standarize_db(&mut db);
    println!("Database ready!\n---------------------------------------------");

    println!("{:?}", nearest_neighbors(&db, "Cagle", euclidian_dist));
    println!("{:?}", nearest_neighbors(&db, "Cagle", manhattan_dist));

    let nn = nearest_neighbors(&db, "Cagle", euclidian_dist);
    println!("{:?}", nn);
            //  nearest_neighbors(&db, "Dr Dog/Fate", manhattan_dist));

    // println!("Med: {:?}",
    //          abs_standard_deviation(&mut vec![43., 45., 55., 69., 70., 75., 105., 115.]));

    // println!("{:?}",
    //          mod_standard_score(&vec![43., 45., 55., 69., 70., 75., 105., 115.]));
}

// Cagle,piano,1
// Cagle,vocals,5
// Cagle,beat,2.5
// Cagle,blues,1
// Cagle,guitar,1
// Cagle,backup vocals,5
// Cagle,rap,1
<commit_msg>Finished<commit_after>extern crate csv;
extern crate rustc_serialize;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

//////////////////////////////DISTANCES////////////////////////////////
fn manhattan_dist(x: &Vec<f32>, y: &Vec<f32>) -> f32 {
    if x.len() != y.len() {
        panic!("Should compare vectors of same size");
    }

    let mut distance = 0.0;
    for i in 0..x.len() {
        distance += (x[i] - y[i]).abs();
    }

    distance
}

fn euclidian_dist(x: &Vec<f32>, y: &Vec<f32>) -> f32 {
    if x.len() != y.len() {
        panic!("Should compare vectors of same size");
    }
    let mut distance = 0.0;

    for i in 0..x.len() {
        distance += (x[i] - y[i]).powf(2.0);
    }

    distance.sqrt()
}
///////////////////////////////////////////////////////////////////////

struct IndexedDB(HashMap<String, HashMap<String, f32>>, HashMap<String, HashMap<String, f32>>);

fn load_db(path: &str) -> IndexedDB {
    let mut rdr = csv::Reader::from_file(path).unwrap().has_headers(false);
    let mut ratings: HashMap<String, HashMap<String, f32>> = HashMap::new();
    let mut features: HashMap<String, HashMap<String, f32>> = HashMap::new();

    for record in rdr.decode() {
        let (user_id, feat_id, rating): (String, String, f32) = record.unwrap();
        let (user_id2, feat_id2, rating2) = (user_id.clone(), feat_id.clone(), rating);

        match ratings.entry(user_id) {
            Vacant(entry) => {
                let mut user_ratings = HashMap::new();
                user_ratings.insert(feat_id, rating);
                entry.insert(user_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(feat_id, rating);
            }
        }

        match features.entry(feat_id2) {
            Vacant(entry) => {
                let mut movie_ratings = HashMap::new();
                movie_ratings.insert(user_id2, rating2);
                entry.insert(movie_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(user_id2, rating2);
            }
        }
    }

    IndexedDB(ratings, features)
}

fn median(vec: &Vec<f32>) -> f32 {
    let mut vec_cpy = vec.clone();
    vec_cpy.sort_by(|a, b| a.partial_cmp(b).unwrap());
    let length = vec_cpy.len();
    let mid = length / 2;
    let mut ret = vec_cpy[mid];
    if length % 2 == 0 {
        ret += vec_cpy[mid - 1];
        ret /= 2.0;
    }

    ret
}

fn abs_standard_deviation(vec: &Vec<f32>) -> (f32, f32) {
    let median = median(vec);
    let mut asd = 0.0;

    for x in vec.iter() {
        asd += (x - median).abs();
    }

    (asd / vec.len() as f32, median)
}

// fn mod_standard_score(vec: &Vec<f32>) -> Vec<f32> {
//     let (asd, median) = abs_standard_deviation(vec);
//     let mut stnzd_vec = Vec::new();

//     for val in vec.iter() {
//         stnzd_vec.push((val - median) / asd);
//     }

//     stnzd_vec
// }

fn users_rating_vectors(db: &IndexedDB, id1: &str, id2: &str) -> (Vec<f32>, Vec<f32>) {
    let mut usr1_vec: Vec<f32> = Vec::new();
    let mut usr2_vec: Vec<f32> = Vec::new();

    if let Some(ref ratings1) = db.0.get(&String::from(id1)) {
        for (feat1_id, &rating1) in ratings1.iter() {
            usr1_vec.push(rating1);
            if let Some(ref ratings2) = db.0.get(&String::from(id2)) {
                if let Some(rating2) = ratings2.get(feat1_id) {
                    usr2_vec.push(*rating2);
                } else {
                    usr2_vec.push(0.0);
                }
            } else {
                panic!("user2 is not found!");
            }
        }
    } else {
        panic!("user1 not found!");
    }

    if let Some(ref ratings2) = db.0.get(&String::from(id2)) {
        for (feat2_id, &rating2) in ratings2.iter() {
            if let Some(ref ratings1) = db.0.get(&String::from(id1)) {
                if let Some(_) = ratings1.get(feat2_id) {
                } else {
                    usr2_vec.push(rating2);
                    usr1_vec.push(0.0);
                }
            } else {
                panic!("user2 is not found!");
            }
        }
    } else {
        panic!("user1 not found!");
    }

    (usr1_vec, usr2_vec)
}

fn nearest_neighbors(db: &IndexedDB,
                     id: &str,
                     func: fn(&Vec<f32>, &Vec<f32>) -> f32)
                     -> Vec<(f32, String)> {
    let mut dist_vec: Vec<(f32, String)> = Vec::new();

    for (rec_id, _) in db.0.iter() {
        if id != rec_id.as_str() {
            let rec_str = rec_id.clone();
            let (obj_vec, rec_vec) = users_rating_vectors(db, id, rec_id);
            dist_vec.push((func(&obj_vec, &rec_vec), rec_str));
        }
    }

    dist_vec.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
    dist_vec
}

// fn get_feature_vec(db: &IndexedDB, feat_id: &String) -> Vec<f32> {
//     let mut feat_vec: Vec<f32> = Vec::new();

//     if let Some(ref ratings) = db.1.get(feat_id) {
//         for (_, &rating) in ratings.iter() {
//             feat_vec.push(rating);
//         }
//     } else {
//         panic!("Feature not found in DB!");
//     }

//     feat_vec
// }

fn standarize_db(mut db: &mut IndexedDB) {
    for (feat, ratings) in db.1.iter_mut() {
        let mut feat_vec: Vec<f32> = Vec::new();
        for rating in ratings.values() {
            feat_vec.push(*rating);
        }

        let (asd, median) = abs_standard_deviation(&feat_vec);
        for (usr, rating) in ratings.iter_mut() {
            *rating = (*rating - median) / asd;
            *db.0.get_mut(usr).unwrap().get_mut(feat).unwrap() = *rating;
        }
    }
}

fn comparison(db: &IndexedDB, id1: &str, id2: &str) {
    if let Some(ref ratings1) = db.0.get(&String::from(id1)) {
        for (feat1_id, &rating1) in ratings1.iter() {
            if let Some(ref ratings2) = db.0.get(&String::from(id2)) {
                if let Some(rating2) = ratings2.get(feat1_id) {
                    let diff = (rating1 - rating2).abs();
                    if diff < 0.8 && (rating1 + rating2).abs() / 2.0 > 0.3 {
                        println!("\t{}: {} <> {} -> {}", feat1_id, rating1, rating2, diff);
                    }
                }
            } else {
                panic!("user2 is not found!");
            }
        }
    } else {
        panic!("user1 not found!");
    }
}

fn main() {
    println!("Loading database, please wait...");
    let mut db = load_db("./data/music.csv");
    standarize_db(&mut db);
    println!("Database ready!\n---------------------------------------------");

    let nn = nearest_neighbors(&db, "Cagle", euclidian_dist);
    println!("KNN: {:?}\n\nR> {}:", nn, nn[0].1);
    comparison(&db, "Cagle", nn[0].1.as_ref());
}

// Cagle,piano,1
// Cagle,vocals,5
// Cagle,beat,2.5
// Cagle,blues,1
// Cagle,guitar,1
// Cagle,backup vocals,5
// Cagle,rap,1
<|endoftext|>


<commit_before>#![feature(core, std_misc, libc, os)]
extern crate libc;

#[cfg(target_os = "linux")]
mod linux;

#[cfg(target_os = "linux")]
pub use linux::*;

#[cfg(target_os = "windows")]
mod windows;

#[cfg(target_os = "windows")]
pub use windows::*;

#[derive(Copy, Debug)]
/// An event from a joystick
pub enum Event {
	/// Fires when a button is pressed with the button's index
	ButtonPressed(u8),
	/// Fires when a button is released with the button's index
	ButtonReleased(u8),
	/// Fires when a joystick / axis is moved with the axis index and its value,
	/// which is between MIN_JOYSTICK_VALUE and MAX_JOYSTICK_VALUE
	JoystickMoved(u8, i16)
}
/// Convert a raw event into a Reminisce event
pub trait IntoEvent {
	/// Convert this into a Reminisce event
	fn into_event(self) -> Event;
}

#[derive(Debug)]
/// A joystick that tracks its state
pub struct SmartJoystick {
	js: Joystick,
	/// The axes on the joystick
	///
	/// Typically the first two of these are the primary analog stick's x and y
	/// co-ordinates
	pub axes: Vec<f32>,
	/// The buttons on the joystick
	///
	/// These usually indicate the button priority with the first two being
	/// accept and back buttons
	pub buttons: Vec<bool>
}
impl SmartJoystick {
	/// Create a new joystick from its index
	pub fn new(index: u8) -> Result<SmartJoystick, &'static str> {
		let js = try!(Joystick::new(index));
		Ok(SmartJoystick {
			axes: vec![0.0f32; js.get_num_axes() as usize],
			buttons: vec![false; js.get_num_buttons() as usize],
			js: js
		})
	}
	/// Poll this joystick for events
	pub fn poll(&mut self) -> Option<Event> {
		let event = self.js.poll();
		match event {
			Some(Event::JoystickMoved(i, v)) => self.axes[i as usize] = v as f32 / MAX_JOYSTICK_VALUE as f32,
			Some(Event::ButtonPressed(i)) => self.buttons[i as usize] = true,
			Some(Event::ButtonReleased(i)) => self.buttons[i as usize] = false,
			_ => ()
		}
		event
	}
	/// Update the joystick's state
	pub fn update(&mut self) {
		while let Some(_) = self.poll() {}
	}
}
impl ::std::ops::Deref for SmartJoystick {
	type Target = Joystick;
	fn deref(&self) -> &Joystick {
		&self.js
	}
}
<commit_msg>Add library summary to documentation<commit_after>//! Reminisce is a lightweight library intended to be used for detecting and
//! reading from joysticks.

#![feature(core, std_misc, libc, os)]
extern crate libc;

#[cfg(target_os = "linux")]
mod linux;

#[cfg(target_os = "linux")]
pub use linux::*;

#[cfg(target_os = "windows")]
mod windows;

#[cfg(target_os = "windows")]
pub use windows::*;

#[derive(Copy, Debug)]
/// An event from a joystick
pub enum Event {
	/// Fires when a button is pressed with the button's index
	ButtonPressed(u8),
	/// Fires when a button is released with the button's index
	ButtonReleased(u8),
	/// Fires when a joystick / axis is moved with the axis index and its value,
	/// which is between MIN_JOYSTICK_VALUE and MAX_JOYSTICK_VALUE
	JoystickMoved(u8, i16)
}
/// Convert a raw event into a Reminisce event
pub trait IntoEvent {
	/// Convert this into a Reminisce event
	fn into_event(self) -> Event;
}

#[derive(Debug)]
/// A joystick that tracks its state
pub struct SmartJoystick {
	js: Joystick,
	/// The axes on the joystick
	///
	/// Typically the first two of these are the primary analog stick's x and y
	/// co-ordinates
	pub axes: Vec<f32>,
	/// The buttons on the joystick
	///
	/// These usually indicate the button priority with the first two being
	/// accept and back buttons
	pub buttons: Vec<bool>
}
impl SmartJoystick {
	/// Create a new joystick from its index
	pub fn new(index: u8) -> Result<SmartJoystick, &'static str> {
		let js = try!(Joystick::new(index));
		Ok(SmartJoystick {
			axes: vec![0.0f32; js.get_num_axes() as usize],
			buttons: vec![false; js.get_num_buttons() as usize],
			js: js
		})
	}
	/// Poll this joystick for events
	pub fn poll(&mut self) -> Option<Event> {
		let event = self.js.poll();
		match event {
			Some(Event::JoystickMoved(i, v)) => self.axes[i as usize] = v as f32 / MAX_JOYSTICK_VALUE as f32,
			Some(Event::ButtonPressed(i)) => self.buttons[i as usize] = true,
			Some(Event::ButtonReleased(i)) => self.buttons[i as usize] = false,
			_ => ()
		}
		event
	}
	/// Update the joystick's state
	pub fn update(&mut self) {
		while let Some(_) = self.poll() {}
	}
}
impl ::std::ops::Deref for SmartJoystick {
	type Target = Joystick;
	fn deref(&self) -> &Joystick {
		&self.js
	}
}
<|endoftext|>


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

extern crate cc;
extern crate gl_generator;

use gl_generator::{Api, Fallbacks, Profile, Registry};
use std::env;
use std::fs::File;
use std::path::Path;

fn main() {
    let target = env::var("TARGET").unwrap();
    if target.contains("android") {
        android_main()
    }
    generate_gl_bindings(&target);
}

fn android_main() {
    // Get the NDK path from NDK_HOME env.
    let ndk_path =
        env::var_os("ANDROID_NDK").expect("Please set the ANDROID_NDK environment variable");
    let ndk_path = Path::new(&ndk_path);

    let target = env::var("TARGET").unwrap();
    let arch = if target.contains("arm") {
        "arch-arm"
    } else if target.contains("aarch64") {
        "arch-arm64"
    } else if target.contains("x86") || target.contains("i686") {
        "arch-x86"
    } else if target.contains("mips") {
        "arch-mips"
    } else {
        panic!("Invalid target architecture {}", target);
    };

    let platform = if target.contains("aarch64") {
        "android-21"
    } else {
        "android-18"
    };

    // compiling android_native_app_glue.c
    let c_file = ndk_path
        .join("sources")
        .join("android")
        .join("native_app_glue")
        .join("android_native_app_glue.c");
    let sysroot = ndk_path.join("platforms").join(platform).join(arch);
    cc::Build::new()
        .file(c_file)
        .flag("--sysroot")
        .flag(sysroot.to_str().unwrap())
        .warnings(false)
        .compile("android_native_app_glue");

    // Get the output directory.
    let out_dir =
        env::var("OUT_DIR").expect("Cargo should have set the OUT_DIR environment variable");

    println!("cargo:rustc-link-lib=static=android_native_app_glue");
    println!("cargo:rustc-link-search=native={}", out_dir);
    println!("cargo:rustc-link-lib=log");
    println!("cargo:rustc-link-lib=android");
}

fn generate_gl_bindings(target: &str) {
    // For now, we only support EGL, and only on Windows and Android.
    if target.contains("android") || target.contains("windows") {
        let dest = env::var("OUT_DIR").unwrap();
        let mut file = File::create(&Path::new(&dest).join("egl_bindings.rs")).unwrap();
        if target.contains("android") {
            Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [])
                .write_bindings(gl_generator::StaticStructGenerator, &mut file)
                .unwrap();
        }
        if target.contains("windows") {
            Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [])
                .write_bindings(gl_generator::StructGenerator, &mut file)
                .unwrap();
        };
    }
}
<commit_msg>Auto merge of #21769 - servo:jdm-patch-28, r=asajeffrey<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/. */

extern crate cc;
extern crate gl_generator;

use gl_generator::{Api, Fallbacks, Profile, Registry};
use std::env;
use std::fs::File;
use std::path::Path;

fn main() {
    let target = env::var("TARGET").unwrap();
    if target.contains("android") {
        android_main()
    }
    generate_gl_bindings(&target);
}

fn android_main() {
    // Get the NDK path from NDK_HOME env.
    let ndk_path =
        env::var_os("ANDROID_NDK").expect("Please set the ANDROID_NDK environment variable");
    let ndk_path = Path::new(&ndk_path);

    // compiling android_native_app_glue.c
    let c_file = ndk_path
        .join("sources")
        .join("android")
        .join("native_app_glue")
        .join("android_native_app_glue.c");
    cc::Build::new()
        .file(c_file)
        .warnings(false)
        .compile("android_native_app_glue");

    // Get the output directory.
    let out_dir =
        env::var("OUT_DIR").expect("Cargo should have set the OUT_DIR environment variable");

    println!("cargo:rustc-link-lib=static=android_native_app_glue");
    println!("cargo:rustc-link-search=native={}", out_dir);
    println!("cargo:rustc-link-lib=log");
    println!("cargo:rustc-link-lib=android");
}

fn generate_gl_bindings(target: &str) {
    // For now, we only support EGL, and only on Windows and Android.
    if target.contains("android") || target.contains("windows") {
        let dest = env::var("OUT_DIR").unwrap();
        let mut file = File::create(&Path::new(&dest).join("egl_bindings.rs")).unwrap();
        if target.contains("android") {
            Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [])
                .write_bindings(gl_generator::StaticStructGenerator, &mut file)
                .unwrap();
        }
        if target.contains("windows") {
            Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [])
                .write_bindings(gl_generator::StructGenerator, &mut file)
                .unwrap();
        };
    }
}
<|endoftext|>


<commit_before>pub use self::def_id_forest::DefIdForest;

use crate::ty;
use crate::ty::context::TyCtxt;
use crate::ty::TyKind::*;
use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef};
use crate::ty::{AdtKind, Visibility};
use crate::ty::{DefId, SubstsRef};

mod def_id_forest;

// The methods in this module calculate `DefIdForest`s of modules in which a
// `AdtDef`/`VariantDef`/`FieldDef` is visibly uninhabited.
//
// # Example
// ```rust
// enum Void {}
// mod a {
//     pub mod b {
//         pub struct SecretlyUninhabited {
//             _priv: !,
//         }
//     }
// }
//
// mod c {
//     pub struct AlsoSecretlyUninhabited {
//         _priv: Void,
//     }
//     mod d {
//     }
// }
//
// struct Foo {
//     x: a::b::SecretlyUninhabited,
//     y: c::AlsoSecretlyUninhabited,
// }
// ```
// In this code, the type `Foo` will only be visibly uninhabited inside the
// modules `b`, `c` and `d`. Calling `uninhabited_from` on `Foo` or its `AdtDef` will
// return the forest of modules {`b`, `c`->`d`} (represented in a `DefIdForest` by the
// set {`b`, `c`}).
//
// We need this information for pattern-matching on `Foo` or types that contain
// `Foo`.
//
// # Example
// ```rust
// let foo_result: Result<T, Foo> = ... ;
// let Ok(t) = foo_result;
// ```
// This code should only compile in modules where the uninhabitedness of `Foo` is
// visible.

impl<'tcx> TyCtxt<'tcx> {
    /// Checks whether a type is visibly uninhabited from a particular module.
    ///
    /// # Example
    /// ```rust
    /// enum Void {}
    /// mod a {
    ///     pub mod b {
    ///         pub struct SecretlyUninhabited {
    ///             _priv: !,
    ///         }
    ///     }
    /// }
    ///
    /// mod c {
    ///     pub struct AlsoSecretlyUninhabited {
    ///         _priv: Void,
    ///     }
    ///     mod d {
    ///     }
    /// }
    ///
    /// struct Foo {
    ///     x: a::b::SecretlyUninhabited,
    ///     y: c::AlsoSecretlyUninhabited,
    /// }
    /// ```
    /// In this code, the type `Foo` will only be visibly uninhabited inside the
    /// modules b, c and d. This effects pattern-matching on `Foo` or types that
    /// contain `Foo`.
    ///
    /// # Example
    /// ```rust
    /// let foo_result: Result<T, Foo> = ... ;
    /// let Ok(t) = foo_result;
    /// ```
    /// This code should only compile in modules where the uninhabitedness of Foo is
    /// visible.
    pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool {
        // To check whether this type is uninhabited at all (not just from the
        // given node), you could check whether the forest is empty.
        // ```
        // forest.is_empty()
        // ```
        self.ty_inhabitedness_forest(ty).contains(self, module)
    }

    pub fn is_ty_uninhabited_from_any_module(self, ty: Ty<'tcx>) -> bool {
        !self.ty_inhabitedness_forest(ty).is_empty()
    }

    fn ty_inhabitedness_forest(self, ty: Ty<'tcx>) -> DefIdForest {
        ty.uninhabited_from(self)
    }
}

impl<'tcx> AdtDef {
    /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited.
    fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>) -> DefIdForest {
        // Non-exhaustive ADTs from other crates are always considered inhabited.
        if self.is_variant_list_non_exhaustive() && !self.did.is_local() {
            DefIdForest::empty()
        } else {
            DefIdForest::intersection(
                tcx,
                self.variants.iter().map(|v| v.uninhabited_from(tcx, substs, self.adt_kind())),
            )
        }
    }
}

impl<'tcx> VariantDef {
    /// Calculates the forest of `DefId`s from which this variant is visibly uninhabited.
    pub fn uninhabited_from(
        &self,
        tcx: TyCtxt<'tcx>,
        substs: SubstsRef<'tcx>,
        adt_kind: AdtKind,
    ) -> DefIdForest {
        let is_enum = match adt_kind {
            // For now, `union`s are never considered uninhabited.
            // The precise semantics of inhabitedness with respect to unions is currently undecided.
            AdtKind::Union => return DefIdForest::empty(),
            AdtKind::Enum => true,
            AdtKind::Struct => false,
        };
        // Non-exhaustive variants from other crates are always considered inhabited.
        if self.is_field_list_non_exhaustive() && !self.def_id.is_local() {
            DefIdForest::empty()
        } else {
            DefIdForest::union(
                tcx,
                self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum)),
            )
        }
    }
}

impl<'tcx> FieldDef {
    /// Calculates the forest of `DefId`s from which this field is visibly uninhabited.
    fn uninhabited_from(
        &self,
        tcx: TyCtxt<'tcx>,
        substs: SubstsRef<'tcx>,
        is_enum: bool,
    ) -> DefIdForest {
        let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx);
        // FIXME(canndrew): Currently enum fields are (incorrectly) stored with
        // `Visibility::Invisible` so we need to override `self.vis` if we're
        // dealing with an enum.
        if is_enum {
            data_uninhabitedness()
        } else {
            match self.vis {
                Visibility::Invisible => DefIdForest::empty(),
                Visibility::Restricted(from) => {
                    let forest = DefIdForest::from_id(from);
                    let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness()));
                    DefIdForest::intersection(tcx, iter)
                }
                Visibility::Public => data_uninhabitedness(),
            }
        }
    }
}

impl<'tcx> TyS<'tcx> {
    /// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
    fn uninhabited_from(&self, tcx: TyCtxt<'tcx>) -> DefIdForest {
        match self.kind {
            Adt(def, substs) => def.uninhabited_from(tcx, substs),

            Never => DefIdForest::full(tcx),

            Tuple(ref tys) => {
                DefIdForest::union(tcx, tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx)))
            }

            Array(ty, len) => match len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
                // If the array is definitely non-empty, it's uninhabited if
                // the type of its elements is uninhabited.
                Some(n) if n != 0 => ty.uninhabited_from(tcx),
                _ => DefIdForest::empty(),
            },

            // References to uninitialised memory is valid for any type, including
            // uninhabited types, in unsafe code, so we treat all references as
            // inhabited.
            // The precise semantics of inhabitedness with respect to references is currently
            // undecided.
            Ref(..) => DefIdForest::empty(),

            _ => DefIdForest::empty(),
        }
    }
}
<commit_msg>Remove trivial function.<commit_after>pub use self::def_id_forest::DefIdForest;

use crate::ty;
use crate::ty::context::TyCtxt;
use crate::ty::TyKind::*;
use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef};
use crate::ty::{AdtKind, Visibility};
use crate::ty::{DefId, SubstsRef};

mod def_id_forest;

// The methods in this module calculate `DefIdForest`s of modules in which a
// `AdtDef`/`VariantDef`/`FieldDef` is visibly uninhabited.
//
// # Example
// ```rust
// enum Void {}
// mod a {
//     pub mod b {
//         pub struct SecretlyUninhabited {
//             _priv: !,
//         }
//     }
// }
//
// mod c {
//     pub struct AlsoSecretlyUninhabited {
//         _priv: Void,
//     }
//     mod d {
//     }
// }
//
// struct Foo {
//     x: a::b::SecretlyUninhabited,
//     y: c::AlsoSecretlyUninhabited,
// }
// ```
// In this code, the type `Foo` will only be visibly uninhabited inside the
// modules `b`, `c` and `d`. Calling `uninhabited_from` on `Foo` or its `AdtDef` will
// return the forest of modules {`b`, `c`->`d`} (represented in a `DefIdForest` by the
// set {`b`, `c`}).
//
// We need this information for pattern-matching on `Foo` or types that contain
// `Foo`.
//
// # Example
// ```rust
// let foo_result: Result<T, Foo> = ... ;
// let Ok(t) = foo_result;
// ```
// This code should only compile in modules where the uninhabitedness of `Foo` is
// visible.

impl<'tcx> TyCtxt<'tcx> {
    /// Checks whether a type is visibly uninhabited from a particular module.
    ///
    /// # Example
    /// ```rust
    /// enum Void {}
    /// mod a {
    ///     pub mod b {
    ///         pub struct SecretlyUninhabited {
    ///             _priv: !,
    ///         }
    ///     }
    /// }
    ///
    /// mod c {
    ///     pub struct AlsoSecretlyUninhabited {
    ///         _priv: Void,
    ///     }
    ///     mod d {
    ///     }
    /// }
    ///
    /// struct Foo {
    ///     x: a::b::SecretlyUninhabited,
    ///     y: c::AlsoSecretlyUninhabited,
    /// }
    /// ```
    /// In this code, the type `Foo` will only be visibly uninhabited inside the
    /// modules b, c and d. This effects pattern-matching on `Foo` or types that
    /// contain `Foo`.
    ///
    /// # Example
    /// ```rust
    /// let foo_result: Result<T, Foo> = ... ;
    /// let Ok(t) = foo_result;
    /// ```
    /// This code should only compile in modules where the uninhabitedness of Foo is
    /// visible.
    pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool {
        // To check whether this type is uninhabited at all (not just from the
        // given node), you could check whether the forest is empty.
        // ```
        // forest.is_empty()
        // ```
        ty.uninhabited_from(self).contains(self, module)
    }

    pub fn is_ty_uninhabited_from_any_module(self, ty: Ty<'tcx>) -> bool {
        !ty.uninhabited_from(self).is_empty()
    }
}

impl<'tcx> AdtDef {
    /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited.
    fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>) -> DefIdForest {
        // Non-exhaustive ADTs from other crates are always considered inhabited.
        if self.is_variant_list_non_exhaustive() && !self.did.is_local() {
            DefIdForest::empty()
        } else {
            DefIdForest::intersection(
                tcx,
                self.variants.iter().map(|v| v.uninhabited_from(tcx, substs, self.adt_kind())),
            )
        }
    }
}

impl<'tcx> VariantDef {
    /// Calculates the forest of `DefId`s from which this variant is visibly uninhabited.
    pub fn uninhabited_from(
        &self,
        tcx: TyCtxt<'tcx>,
        substs: SubstsRef<'tcx>,
        adt_kind: AdtKind,
    ) -> DefIdForest {
        let is_enum = match adt_kind {
            // For now, `union`s are never considered uninhabited.
            // The precise semantics of inhabitedness with respect to unions is currently undecided.
            AdtKind::Union => return DefIdForest::empty(),
            AdtKind::Enum => true,
            AdtKind::Struct => false,
        };
        // Non-exhaustive variants from other crates are always considered inhabited.
        if self.is_field_list_non_exhaustive() && !self.def_id.is_local() {
            DefIdForest::empty()
        } else {
            DefIdForest::union(
                tcx,
                self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum)),
            )
        }
    }
}

impl<'tcx> FieldDef {
    /// Calculates the forest of `DefId`s from which this field is visibly uninhabited.
    fn uninhabited_from(
        &self,
        tcx: TyCtxt<'tcx>,
        substs: SubstsRef<'tcx>,
        is_enum: bool,
    ) -> DefIdForest {
        let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx);
        // FIXME(canndrew): Currently enum fields are (incorrectly) stored with
        // `Visibility::Invisible` so we need to override `self.vis` if we're
        // dealing with an enum.
        if is_enum {
            data_uninhabitedness()
        } else {
            match self.vis {
                Visibility::Invisible => DefIdForest::empty(),
                Visibility::Restricted(from) => {
                    let forest = DefIdForest::from_id(from);
                    let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness()));
                    DefIdForest::intersection(tcx, iter)
                }
                Visibility::Public => data_uninhabitedness(),
            }
        }
    }
}

impl<'tcx> TyS<'tcx> {
    /// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
    fn uninhabited_from(&self, tcx: TyCtxt<'tcx>) -> DefIdForest {
        match self.kind {
            Adt(def, substs) => def.uninhabited_from(tcx, substs),

            Never => DefIdForest::full(tcx),

            Tuple(ref tys) => {
                DefIdForest::union(tcx, tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx)))
            }

            Array(ty, len) => match len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
                // If the array is definitely non-empty, it's uninhabited if
                // the type of its elements is uninhabited.
                Some(n) if n != 0 => ty.uninhabited_from(tcx),
                _ => DefIdForest::empty(),
            },

            // References to uninitialised memory is valid for any type, including
            // uninhabited types, in unsafe code, so we treat all references as
            // inhabited.
            // The precise semantics of inhabitedness with respect to references is currently
            // undecided.
            Ref(..) => DefIdForest::empty(),

            _ => DefIdForest::empty(),
        }
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use rustc_data_structures::snapshot_vec as sv;
use rustc_data_structures::undo_log::{Rollback, UndoLogs};
use rustc_data_structures::unify as ut;
use rustc_middle::ty;

use crate::{
    infer::{region_constraints, type_variable, InferCtxtInner},
    traits,
};

pub struct Snapshot<'tcx> {
    pub(crate) undo_len: usize,
    _marker: PhantomData<&'tcx ()>,
}

/// Records the 'undo' data fora single operation that affects some form of inference variable.
pub(crate) enum UndoLog<'tcx> {
    TypeVariables(type_variable::UndoLog<'tcx>),
    ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
    IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
    FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
    RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
    RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>),
    ProjectionCache(traits::UndoLog<'tcx>),
    PushRegionObligation,
}

impl<'tcx> From<region_constraints::UndoLog<'tcx>> for UndoLog<'tcx> {
    fn from(l: region_constraints::UndoLog<'tcx>) -> Self {
        UndoLog::RegionConstraintCollector(l)
    }
}

impl<'tcx> From<sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>> for UndoLog<'tcx> {
    fn from(l: sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>) -> Self {
        UndoLog::TypeVariables(type_variable::UndoLog::EqRelation(l))
    }
}

impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::TyVid>>> for UndoLog<'tcx> {
    fn from(l: sv::UndoLog<ut::Delegate<ty::TyVid>>) -> Self {
        UndoLog::TypeVariables(type_variable::UndoLog::SubRelation(l))
    }
}

impl<'tcx> From<sv::UndoLog<type_variable::Delegate>> for UndoLog<'tcx> {
    fn from(l: sv::UndoLog<type_variable::Delegate>) -> Self {
        UndoLog::TypeVariables(type_variable::UndoLog::Values(l))
    }
}

impl<'tcx> From<type_variable::Instantiate> for UndoLog<'tcx> {
    fn from(l: type_variable::Instantiate) -> Self {
        UndoLog::TypeVariables(type_variable::UndoLog::from(l))
    }
}

impl From<type_variable::UndoLog<'tcx>> for UndoLog<'tcx> {
    fn from(t: type_variable::UndoLog<'tcx>) -> Self {
        Self::TypeVariables(t)
    }
}

impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>> for UndoLog<'tcx> {
    fn from(l: sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>) -> Self {
        Self::ConstUnificationTable(l)
    }
}

impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::IntVid>>> for UndoLog<'tcx> {
    fn from(l: sv::UndoLog<ut::Delegate<ty::IntVid>>) -> Self {
        Self::IntUnificationTable(l)
    }
}

impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::FloatVid>>> for UndoLog<'tcx> {
    fn from(l: sv::UndoLog<ut::Delegate<ty::FloatVid>>) -> Self {
        Self::FloatUnificationTable(l)
    }
}

impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::RegionVid>>> for UndoLog<'tcx> {
    fn from(l: sv::UndoLog<ut::Delegate<ty::RegionVid>>) -> Self {
        Self::RegionUnificationTable(l)
    }
}

impl<'tcx> From<traits::UndoLog<'tcx>> for UndoLog<'tcx> {
    fn from(l: traits::UndoLog<'tcx>) -> Self {
        Self::ProjectionCache(l)
    }
}

impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
    fn reverse(&mut self, undo: UndoLog<'tcx>) {
        match undo {
            UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo),
            UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),
            UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),
            UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo),
            UndoLog::RegionConstraintCollector(undo) => {
                self.region_constraints.as_mut().unwrap().reverse(undo)
            }
            UndoLog::RegionUnificationTable(undo) => {
                self.region_constraints.as_mut().unwrap().unification_table.reverse(undo)
            }
            UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo),
            UndoLog::PushRegionObligation => {
                self.region_obligations.pop();
            }
        }
    }
}

pub(crate) struct InferCtxtUndoLogs<'tcx> {
    logs: Vec<UndoLog<'tcx>>,
    num_open_snapshots: usize,
}

impl Default for InferCtxtUndoLogs<'_> {
    fn default() -> Self {
        Self { logs: Default::default(), num_open_snapshots: Default::default() }
    }
}

impl<'tcx, T> UndoLogs<T> for InferCtxtUndoLogs<'tcx>
where
    UndoLog<'tcx>: From<T>,
{
    fn num_open_snapshots(&self) -> usize {
        self.num_open_snapshots
    }
    fn push(&mut self, undo: T) {
        if self.in_snapshot() {
            self.logs.push(undo.into())
        }
    }
    fn clear(&mut self) {
        self.logs.clear();
        self.num_open_snapshots = 0;
    }
    fn extend<J>(&mut self, undos: J)
    where
        Self: Sized,
        J: IntoIterator<Item = T>,
    {
        if self.in_snapshot() {
            self.logs.extend(undos.into_iter().map(UndoLog::from))
        }
    }
}

impl<'tcx> InferCtxtInner<'tcx> {
    pub fn rollback_to(&mut self, snapshot: Snapshot<'tcx>) {
        debug!("rollback_to({})", snapshot.undo_len);
        self.undo_log.assert_open_snapshot(&snapshot);

        while self.undo_log.logs.len() > snapshot.undo_len {
            let undo = self.undo_log.logs.pop().unwrap();
            self.reverse(undo);
        }

        if self.undo_log.num_open_snapshots == 1 {
            // The root snapshot. It's safe to clear the undo log because
            // there's no snapshot further out that we might need to roll back
            // to.
            assert!(snapshot.undo_len == 0);
            self.undo_log.logs.clear();
        }

        self.undo_log.num_open_snapshots -= 1;
    }

    pub fn commit(&mut self, snapshot: Snapshot<'tcx>) {
        debug!("commit({})", snapshot.undo_len);

        if self.undo_log.num_open_snapshots == 1 {
            // The root snapshot. It's safe to clear the undo log because
            // there's no snapshot further out that we might need to roll back
            // to.
            assert!(snapshot.undo_len == 0);
            self.undo_log.logs.clear();
        }

        self.undo_log.num_open_snapshots -= 1;
    }
}

impl<'tcx> InferCtxtUndoLogs<'tcx> {
    pub fn actions_since_snapshot(&self, snapshot: &Snapshot<'tcx>) -> &[UndoLog<'tcx>] {
        &self.logs[snapshot.undo_len..]
    }

    pub fn start_snapshot(&mut self) -> Snapshot<'tcx> {
        self.num_open_snapshots += 1;
        Snapshot { undo_len: self.logs.len(), _marker: PhantomData }
    }

    pub(crate) fn region_constraints_in_snapshot(
        &self,
        s: &Snapshot<'tcx>,
    ) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone {
        self.logs[s.undo_len..].iter().filter_map(|log| match log {
            UndoLog::RegionConstraintCollector(log) => Some(log),
            _ => None,
        })
    }

    pub(crate) fn region_constraints(
        &self,
    ) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone {
        self.logs.iter().filter_map(|log| match log {
            UndoLog::RegionConstraintCollector(log) => Some(log),
            _ => None,
        })
    }

    fn assert_open_snapshot(&self, snapshot: &Snapshot<'tcx>) {
        // Failures here may indicate a failure to follow a stack discipline.
        assert!(self.logs.len() >= snapshot.undo_len);
        assert!(self.num_open_snapshots > 0);
    }

    pub(crate) fn iter(&self) -> std::slice::Iter<'_, UndoLog<'tcx>> {
        self.logs.iter()
    }
}

impl<'tcx> std::ops::Index<usize> for InferCtxtUndoLogs<'tcx> {
    type Output = UndoLog<'tcx>;
    fn index(&self, key: usize) -> &Self::Output {
        &self.logs[key]
    }
}

impl<'tcx> std::ops::IndexMut<usize> for InferCtxtUndoLogs<'tcx> {
    fn index_mut(&mut self, key: usize) -> &mut Self::Output {
        &mut self.logs[key]
    }
}
<commit_msg>Generate the UndoLog upcasts with a macro<commit_after>use std::marker::PhantomData;

use rustc_data_structures::snapshot_vec as sv;
use rustc_data_structures::undo_log::{Rollback, UndoLogs};
use rustc_data_structures::unify as ut;
use rustc_middle::ty;

use crate::{
    infer::{region_constraints, type_variable, InferCtxtInner},
    traits,
};

pub struct Snapshot<'tcx> {
    pub(crate) undo_len: usize,
    _marker: PhantomData<&'tcx ()>,
}

/// Records the 'undo' data fora single operation that affects some form of inference variable.
pub(crate) enum UndoLog<'tcx> {
    TypeVariables(type_variable::UndoLog<'tcx>),
    ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
    IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
    FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
    RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
    RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>),
    ProjectionCache(traits::UndoLog<'tcx>),
    PushRegionObligation,
}

macro_rules! impl_from {
    ($($ctor: ident ($ty: ty),)*) => {
        $(
        impl<'tcx> From<$ty> for UndoLog<'tcx> {
            fn from(x: $ty) -> Self {
                UndoLog::$ctor(x.into())
            }
        }
        )*
    }
}

// Upcast from a single kind of "undoable action" to the general enum
impl_from! {
    RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
    TypeVariables(type_variable::UndoLog<'tcx>),

    TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
    TypeVariables(sv::UndoLog<ut::Delegate<ty::TyVid>>),
    TypeVariables(sv::UndoLog<type_variable::Delegate>),
    TypeVariables(type_variable::Instantiate),

    IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),

    FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),

    ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),

    RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>),
    ProjectionCache(traits::UndoLog<'tcx>),
}

impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
    fn reverse(&mut self, undo: UndoLog<'tcx>) {
        match undo {
            UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo),
            UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),
            UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),
            UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo),
            UndoLog::RegionConstraintCollector(undo) => {
                self.region_constraints.as_mut().unwrap().reverse(undo)
            }
            UndoLog::RegionUnificationTable(undo) => {
                self.region_constraints.as_mut().unwrap().unification_table.reverse(undo)
            }
            UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo),
            UndoLog::PushRegionObligation => {
                self.region_obligations.pop();
            }
        }
    }
}

pub(crate) struct InferCtxtUndoLogs<'tcx> {
    logs: Vec<UndoLog<'tcx>>,
    num_open_snapshots: usize,
}

impl Default for InferCtxtUndoLogs<'_> {
    fn default() -> Self {
        Self { logs: Default::default(), num_open_snapshots: Default::default() }
    }
}

impl<'tcx, T> UndoLogs<T> for InferCtxtUndoLogs<'tcx>
where
    UndoLog<'tcx>: From<T>,
{
    fn num_open_snapshots(&self) -> usize {
        self.num_open_snapshots
    }
    fn push(&mut self, undo: T) {
        if self.in_snapshot() {
            self.logs.push(undo.into())
        }
    }
    fn clear(&mut self) {
        self.logs.clear();
        self.num_open_snapshots = 0;
    }
    fn extend<J>(&mut self, undos: J)
    where
        Self: Sized,
        J: IntoIterator<Item = T>,
    {
        if self.in_snapshot() {
            self.logs.extend(undos.into_iter().map(UndoLog::from))
        }
    }
}

impl<'tcx> InferCtxtInner<'tcx> {
    pub fn rollback_to(&mut self, snapshot: Snapshot<'tcx>) {
        debug!("rollback_to({})", snapshot.undo_len);
        self.undo_log.assert_open_snapshot(&snapshot);

        while self.undo_log.logs.len() > snapshot.undo_len {
            let undo = self.undo_log.logs.pop().unwrap();
            self.reverse(undo);
        }

        if self.undo_log.num_open_snapshots == 1 {
            // The root snapshot. It's safe to clear the undo log because
            // there's no snapshot further out that we might need to roll back
            // to.
            assert!(snapshot.undo_len == 0);
            self.undo_log.logs.clear();
        }

        self.undo_log.num_open_snapshots -= 1;
    }

    pub fn commit(&mut self, snapshot: Snapshot<'tcx>) {
        debug!("commit({})", snapshot.undo_len);

        if self.undo_log.num_open_snapshots == 1 {
            // The root snapshot. It's safe to clear the undo log because
            // there's no snapshot further out that we might need to roll back
            // to.
            assert!(snapshot.undo_len == 0);
            self.undo_log.logs.clear();
        }

        self.undo_log.num_open_snapshots -= 1;
    }
}

impl<'tcx> InferCtxtUndoLogs<'tcx> {
    pub fn actions_since_snapshot(&self, snapshot: &Snapshot<'tcx>) -> &[UndoLog<'tcx>] {
        &self.logs[snapshot.undo_len..]
    }

    pub fn start_snapshot(&mut self) -> Snapshot<'tcx> {
        self.num_open_snapshots += 1;
        Snapshot { undo_len: self.logs.len(), _marker: PhantomData }
    }

    pub(crate) fn region_constraints_in_snapshot(
        &self,
        s: &Snapshot<'tcx>,
    ) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone {
        self.logs[s.undo_len..].iter().filter_map(|log| match log {
            UndoLog::RegionConstraintCollector(log) => Some(log),
            _ => None,
        })
    }

    pub(crate) fn region_constraints(
        &self,
    ) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone {
        self.logs.iter().filter_map(|log| match log {
            UndoLog::RegionConstraintCollector(log) => Some(log),
            _ => None,
        })
    }

    fn assert_open_snapshot(&self, snapshot: &Snapshot<'tcx>) {
        // Failures here may indicate a failure to follow a stack discipline.
        assert!(self.logs.len() >= snapshot.undo_len);
        assert!(self.num_open_snapshots > 0);
    }

    pub(crate) fn iter(&self) -> std::slice::Iter<'_, UndoLog<'tcx>> {
        self.logs.iter()
    }
}

impl<'tcx> std::ops::Index<usize> for InferCtxtUndoLogs<'tcx> {
    type Output = UndoLog<'tcx>;
    fn index(&self, key: usize) -> &Self::Output {
        &self.logs[key]
    }
}

impl<'tcx> std::ops::IndexMut<usize> for InferCtxtUndoLogs<'tcx> {
    fn index_mut(&mut self, key: usize) -> &mut Self::Output {
        &mut self.logs[key]
    }
}
<|endoftext|>


<commit_before>extern crate "gfx_phase" as phase;
extern crate gfx;
extern crate cgmath;

use std::marker::PhantomData;

#[derive(Debug)]
pub enum Error {
    Batch(gfx::batch::Error),
    Flush(phase::FlushError),
}

pub trait ViewInfo<S, T: cgmath::Transform3<S>>: phase::ToDepth<Depth = S> {
    fn new(mvp: cgmath::Matrix4<S>, view: T, model: T) -> Self;
}

/// Abstract scene that can be drawn into something
pub trait AbstractScene<D: gfx::Device> {
    type ViewInfo;
    type Entity;
    type Camera;

    fn draw<H: phase::AbstractPhase<D, Self::Entity, Self::ViewInfo> + ?Sized>(
            &mut self, &mut H, &Self::Camera, &gfx::Frame<D::Resources>,
            &mut gfx::Renderer<D::Resources, D::CommandBuffer>) -> Result<(), Error>;
}

/// A class that manages spatial relations between objects
pub trait World {
    type Scalar: cgmath::BaseFloat + 'static;
    type Rotation: cgmath::Rotation3<Self::Scalar>;
    type Transform: cgmath::CompositeTransform3<Self::Scalar, Self::Rotation> + Clone;
    type NodePtr;
    type SkeletonPtr;
    type Iter: Iterator<Item = Self::Transform>;

    fn get_transform(&self, &Self::NodePtr) -> &Self::Transform;
    fn iter_bones(&self, &Self::SkeletonPtr) -> Self::Iter;
}

pub struct Entity<R: gfx::Resources, M, W: World, B> {
    pub name: String,
    pub material: M,
    mesh: gfx::Mesh<R>,
    slice: gfx::Slice<R>,
    node: W::NodePtr,
    skeleton: Option<W::SkeletonPtr>,
    pub bound: B,
}

impl<R: gfx::Resources, M: phase::Material, W: World, B> phase::Entity<R, M> for Entity<R, M, W, B> {
    fn get_material(&self) -> &M {
        &self.material
    }
    fn get_mesh(&self) -> (&gfx::Mesh<R>, &gfx::Slice<R>) {
        (&self.mesh, &self.slice)
    }
}

pub struct Camera<P, N> {
    pub name: String,
    pub projection: P,
    pub node: N,
}

pub struct Scene<R: gfx::Resources, M, W: World, B, P, V> {
    pub entities: Vec<Entity<R, M, W, B>>,
    pub cameras: Vec<Camera<P, W::NodePtr>>,
    pub world: W,
    context: gfx::batch::Context<R>,
    _view_dummy: PhantomData<V>,
}

impl<
    D: gfx::Device,
    M: phase::Material,
    W: World,
    B: cgmath::Bound<W::Scalar>,
    P: cgmath::Projection<W::Scalar>,
    V: ViewInfo<W::Scalar, W::Transform>,
> AbstractScene<D> for Scene<D::Resources, M, W, B, P, V> {
    type ViewInfo = V;
    type Entity = Entity<D::Resources, M, W, B>;
    type Camera = Camera<P, W::NodePtr>;

    fn draw<H: phase::AbstractPhase<D, Entity<D::Resources, M, W, B>, V> + ?Sized>(
            &mut self, phase: &mut H, camera: &Camera<P, W::NodePtr>,
            frame: &gfx::Frame<D::Resources>,
            renderer: &mut gfx::Renderer<D::Resources, D::CommandBuffer>)
            -> Result<(), Error> {
        use cgmath::{Matrix, ToMatrix4, Transform};
        let cam_inverse = self.world.get_transform(&camera.node)
                                    .invert().unwrap();
        let projection = camera.projection.to_matrix4()
                               .mul_m(&cam_inverse.to_matrix4());
        for entity in self.entities.iter_mut() {
            if !phase.test(entity) {
                continue
            }
            let model = self.world.get_transform(&entity.node);
            let view = cam_inverse.concat(&model);
            let mvp = projection.mul_m(&model.to_matrix4());
            if entity.bound.relate_clip_space(&mvp) == cgmath::Relation::Out {
                continue
            }
            let view_info = ViewInfo::new(mvp, view, model.clone());
            match phase.enqueue(entity, view_info, &mut self.context) {
                Ok(()) => (),
                Err(e) => return Err(Error::Batch(e)),
            }
        }
        phase.flush(frame, &self.context, renderer)
             .map_err(|e| Error::Flush(e))
    }
}

/// Wrapper around a scene that carries a list of phases as well as the
/// `Renderer`, allowing to isolate a command buffer completely.
pub struct PhaseHarness<D: gfx::Device, C: AbstractScene<D>> {
    pub scene: C,
    pub phases: Vec<Box<phase::AbstractPhase<D, C::Entity, C::ViewInfo>>>,
    pub renderer: gfx::Renderer<D::Resources, D::CommandBuffer>,
}

impl<
    D: gfx::Device,
    C: AbstractScene<D>,
> PhaseHarness<D, C> {
    pub fn draw(&mut self, camera: &C::Camera, frame: &gfx::Frame<D::Resources>)
                -> Result<(), Error> {
        use std::ops::DerefMut;
        self.renderer.reset();
        for phase in self.phases.iter_mut() {
            match self.scene.draw(phase.deref_mut(), camera, frame, &mut self.renderer) {
                Ok(_) => (),
                Err(e) => return Err(e),
            }
        }
        Ok(())
    }
}

pub type PerspectiveCam<W: World> = Camera<
    cgmath::PerspectiveFov<W::Scalar, cgmath::Rad<W::Scalar>>,
    W::NodePtr
>;
<commit_msg>Implemented an external function for drawing entities (closes #1)<commit_after>extern crate "gfx_phase" as phase;
extern crate gfx;
extern crate cgmath;

use std::marker::PhantomData;

#[derive(Debug)]
pub enum Error {
    Batch(gfx::batch::Error),
    Flush(phase::FlushError),
}

pub trait ViewInfo<S, T: cgmath::Transform3<S>>: phase::ToDepth<Depth = S> {
    fn new(mvp: cgmath::Matrix4<S>, view: T, model: T) -> Self;
}

/// Abstract scene that can be drawn into something
pub trait AbstractScene<D: gfx::Device> {
    type ViewInfo;
    type Entity;
    type Camera;

    fn draw<H: phase::AbstractPhase<D, Self::Entity, Self::ViewInfo> + ?Sized>(
            &mut self, &mut H, &Self::Camera, &gfx::Frame<D::Resources>,
            &mut gfx::Renderer<D::Resources, D::CommandBuffer>) -> Result<(), Error>;
}

/// A class that manages spatial relations between objects
pub trait World {
    type Scalar: cgmath::BaseFloat + 'static;
    type Rotation: cgmath::Rotation3<Self::Scalar>;
    type Transform: cgmath::CompositeTransform3<Self::Scalar, Self::Rotation> + Clone;
    type NodePtr;
    type SkeletonPtr;
    type Iter: Iterator<Item = Self::Transform>;

    fn get_transform(&self, &Self::NodePtr) -> &Self::Transform;
    fn iter_bones(&self, &Self::SkeletonPtr) -> Self::Iter;
}

pub struct Entity<R: gfx::Resources, M, W: World, B> {
    pub name: String,
    pub material: M,
    mesh: gfx::Mesh<R>,
    slice: gfx::Slice<R>,
    node: W::NodePtr,
    skeleton: Option<W::SkeletonPtr>,
    pub bound: B,
}

impl<R: gfx::Resources, M: phase::Material, W: World, B> phase::Entity<R, M> for Entity<R, M, W, B> {
    fn get_material(&self) -> &M {
        &self.material
    }
    fn get_mesh(&self) -> (&gfx::Mesh<R>, &gfx::Slice<R>) {
        (&self.mesh, &self.slice)
    }
}

pub struct Camera<P, N> {
    pub name: String,
    pub projection: P,
    pub node: N,
}

pub fn draw_entities<'a,
    D: gfx::Device,
    M: phase::Material + 'a,
    W: World + 'a,
    B: cgmath::Bound<W::Scalar> + 'a,
    H: phase::AbstractPhase<D, Entity<D::Resources, M, W, B>, V> + ?Sized,
    P: cgmath::Projection<W::Scalar>,
    V: ViewInfo<W::Scalar, W::Transform>,
    I: Iterator<Item = &'a mut Entity<D::Resources, M, W, B>>,
>
(   entities: I, phase: &mut H, world: &W, camera: &Camera<P, W::NodePtr>,
    frame: &gfx::Frame<D::Resources>, context: &mut gfx::batch::Context<D::Resources>,
    renderer: &mut gfx::Renderer<D::Resources, D::CommandBuffer>)
    -> Result<(), Error>
where
    D::Resources: 'a,
    <D::Resources as gfx::Resources>::Buffer: 'a,
    <D::Resources as gfx::Resources>::ArrayBuffer: 'a,
    <D::Resources as gfx::Resources>::Shader: 'a,
    <D::Resources as gfx::Resources>::Program: 'a,
    <D::Resources as gfx::Resources>::FrameBuffer: 'a,
    <D::Resources as gfx::Resources>::Surface: 'a,
    <D::Resources as gfx::Resources>::Texture: 'a,
    <D::Resources as gfx::Resources>::Sampler: 'a,
    W::Rotation: 'a,
    W::Transform: 'a,
    W::NodePtr: 'a,
    W::SkeletonPtr: 'a,
    W::Iter: 'a,
{
    use cgmath::{Matrix, ToMatrix4, Transform};
    let cam_inverse = world.get_transform(&camera.node)
                           .invert().unwrap();
    let projection = camera.projection.to_matrix4()
                           .mul_m(&cam_inverse.to_matrix4());
    for entity in entities {
        if !phase.test(entity) {
            continue
        }
        let model = world.get_transform(&entity.node);
        let view = cam_inverse.concat(&model);
        let mvp = projection.mul_m(&model.to_matrix4());
        if entity.bound.relate_clip_space(&mvp) == cgmath::Relation::Out {
            continue
        }
        let view_info = ViewInfo::new(mvp, view, model.clone());
        match phase.enqueue(entity, view_info, context) {
            Ok(()) => (),
            Err(e) => return Err(Error::Batch(e)),
        }
    }
    phase.flush(frame, context, renderer)
         .map_err(|e| Error::Flush(e))
}

pub struct Scene<R: gfx::Resources, M, W: World, B, P, V> {
    pub entities: Vec<Entity<R, M, W, B>>,
    pub cameras: Vec<Camera<P, W::NodePtr>>,
    pub world: W,
    context: gfx::batch::Context<R>,
    _view_dummy: PhantomData<V>,
}

impl<
    D: gfx::Device,
    M: phase::Material,
    W: World,
    B: cgmath::Bound<W::Scalar>,
    P: cgmath::Projection<W::Scalar>,
    V: ViewInfo<W::Scalar, W::Transform>,
> AbstractScene<D> for Scene<D::Resources, M, W, B, P, V> {
    type ViewInfo = V;
    type Entity = Entity<D::Resources, M, W, B>;
    type Camera = Camera<P, W::NodePtr>;

    fn draw<H: phase::AbstractPhase<D, Entity<D::Resources, M, W, B>, V> + ?Sized>(
            &mut self, phase: &mut H, camera: &Camera<P, W::NodePtr>,
            frame: &gfx::Frame<D::Resources>,
            renderer: &mut gfx::Renderer<D::Resources, D::CommandBuffer>)
            -> Result<(), Error> {
        draw_entities(self.entities.iter_mut(), phase, &self.world, camera,
                     frame, &mut self.context, renderer)
    }
}

/// Wrapper around a scene that carries a list of phases as well as the
/// `Renderer`, allowing to isolate a command buffer completely.
pub struct PhaseHarness<D: gfx::Device, C: AbstractScene<D>> {
    pub scene: C,
    pub phases: Vec<Box<phase::AbstractPhase<D, C::Entity, C::ViewInfo>>>,
    pub renderer: gfx::Renderer<D::Resources, D::CommandBuffer>,
}

impl<
    D: gfx::Device,
    C: AbstractScene<D>,
> PhaseHarness<D, C> {
    pub fn draw(&mut self, camera: &C::Camera, frame: &gfx::Frame<D::Resources>)
                -> Result<(), Error> {
        use std::ops::DerefMut;
        self.renderer.reset();
        for phase in self.phases.iter_mut() {
            match self.scene.draw(phase.deref_mut(), camera, frame, &mut self.renderer) {
                Ok(_) => (),
                Err(e) => return Err(e),
            }
        }
        Ok(())
    }
}

pub type PerspectiveCam<W: World> = Camera<
    cgmath::PerspectiveFov<W::Scalar, cgmath::Rad<W::Scalar>>,
    W::NodePtr
>;
<|endoftext|>


<commit_before>/// Exercise: BSD-based systems provide a function called funopen that
/// allows us to intercept read, write, seek, and close calls
/// on a stream. Use this function to implement fmemopen
/// for FreeBSD and Mac OS X.
///
/// Solution: This is only a basic solution which handles
/// opening in a+, reading, writing and seeking and takes care that you don't
/// read/write over the buffers end.
/// The solution on page 913 in the book goes much further but I didn't find
/// motivation to go that far :-)
///
/// Takeaways from this exercise:
///
/// - write is only called when I call seek (maybe also close), so I guess
///   instead of calling write right away it's queued somehow
/// - when MemStream.buffer is not mutable the code compiles and there is no
///   segfault when writing to the buffer but the buffer is just not altered.
///   This was somehow unexpected (and a segfault would have been helpful here),
///   but when changing buffer to a mut it all worked as expected.
/// - handing around the struct as a pointer is scary, but I guess still nicer
///   than a public singleton (which isn't really supported by rust).
///   As the struct instance outlives the pointer (is only dropped at end of main)
///   we're safe here

extern crate libc;
#[macro_use(cstr)]
extern crate apue;

#[cfg(any(target_os = "macos", target_os= "bsd"))]
mod fmemopen {
    use libc::{c_void, c_char, c_int, off_t, FILE, SEEK_SET, memset, memcpy, fgets, fputs, printf,
               fseek};
    use std::option::Option;
    use std::cmp::min;
    use std::mem::uninitialized;

    pub const BUFLEN: usize = 30;

    pub struct MemStream<'a> {
        buffer: &'a mut [u8; BUFLEN],
        pos: u8,
    }

    extern "C" {
        fn funopen(cookie: *mut c_void,
                   readfn: Option<unsafe extern "C" fn(cookie: *mut c_void,
                                                       buffer: *mut c_char,
                                                       nbyte: c_int)
                                                       -> c_int>,
                   writefn: Option<unsafe extern "C" fn(cookie: *mut c_void,
                                                        buffer: *mut c_char,
                                                        nbyte: c_int)
                                                        -> c_int>,
                   seekfn: Option<unsafe extern "C" fn(cookie: *mut c_void,
                                                       offset: off_t,
                                                       whence: c_int)
                                                       -> off_t>,
                   closefn: Option<unsafe extern "C" fn(cookie: *mut c_void) -> c_int>)
                   -> *mut FILE;
    }

    trait CArray {
        fn as_muti8(&self) -> *mut i8;
        fn as_void(&self) -> *mut c_void;
    }

    impl CArray for [u8] {
        fn as_muti8(&self) -> *mut i8 {
            self.as_ptr() as *mut i8
        }
        fn as_void(&self) -> *mut c_void {
            self.as_ptr() as *mut c_void
        }
    }

    unsafe fn max_bytes(nbyte: u8, status: *mut MemStream) -> u8 {
        min(nbyte, ((*status).buffer.len() as u8 - (*status).pos))
    }

    unsafe extern "C" fn read(cookie: *mut c_void, buffer: *mut c_char, nbyte: c_int) -> c_int {
        let status = cookie as *mut MemStream;
        println!("position is: {:?}", (*status).pos);
        let nbyte = max_bytes(nbyte as u8, status);
        if nbyte > 0 {
            memcpy(buffer as _, (*status).buffer.as_void(), nbyte as usize);
            (*status).pos += nbyte;
            nbyte as _
        } else {
            -1
        }
    }

    unsafe extern "C" fn write(cookie: *mut c_void, buffer: *mut c_char, nbyte: c_int) -> c_int {
        let status = cookie as *mut MemStream;
        let nbyte = max_bytes(nbyte as u8, status);
        if nbyte > 0 {
            println!("need to write.. position is: {:?}", (*status).pos);
            memcpy((*(*status).buffer).as_void().offset((*status).pos as _),
                   buffer as *mut _,
                   nbyte as usize);
            (*status).pos += nbyte;
            nbyte as _
        } else {
            -1
        }
    }

    unsafe extern "C" fn seek(cookie: *mut c_void, offset: off_t, _: c_int) -> off_t {
        let status = cookie as *mut MemStream;
        (*status).pos = offset as u8;
        offset
    }

    unsafe fn fmemopen(cookie: *mut c_void) -> *mut FILE {
        funopen(cookie, Some(read), Some(write), Some(seek), None)
    }

    pub fn runit() {
        unsafe {
            let mut buf: [u8; BUFLEN] = uninitialized();
            memset(buf.as_ptr() as *mut c_void, 'a' as c_int, BUFLEN - 2);
            buf[BUFLEN - 2] = '\0' as u8;
            buf[BUFLEN - 1] = 'X' as u8;
            printf(cstr!("buffer = %s\n"), buf.as_ptr());
            let mut status = MemStream {
                buffer: &mut buf,
                pos: 0,
            };
            // could be written as &mut status as *mut _ as *mut _
            // so the types would be coerced but for clarity I wrote
            // out the types. Two casts are neeeded because first
            // the reference is cast into a pointer and then the pointer
            // type is changed
            let cookie = &mut status as *mut MemStream as *mut c_void;
            let fd = fmemopen(cookie);

            // let status2 = cookie as *mut MemStream;
            // let mut buf:[u8;BUFLEN] = *((*status2).buffer);
            // println!("buf = {:?}", buf);
            // buf[0] = 55;
            // println!("buf = {:?}", buf);

            let tmpbuf: [u8; 5] = [55; 5];
            fputs("lorem ipsum dolor\0".as_ptr() as _, fd);
            fseek(fd, 10, SEEK_SET);
            printf(cstr!("mem buffer = %s\n"), status.buffer.as_ptr());
            fputs(cstr!("hansaplast!") as _, fd);
            fseek(fd, 0, SEEK_SET);
            printf(cstr!("mem buffer = %s\n"), status.buffer.as_ptr());
            while !fgets(tmpbuf.as_ptr() as *mut i8, 5, fd).is_null() {
                printf(cstr!("buffer = %s\n"), tmpbuf.as_ptr());
            }
        }
    }
}

fn main() {
    #[cfg(any(target_os = "macos", target_os= "bsd"))]
    fmemopen::runit();
}
<commit_msg>add doctest shell tests for all binaries (tested by test.py)<commit_after>/// Exercise: BSD-based systems provide a function called funopen that
/// allows us to intercept read, write, seek, and close calls
/// on a stream. Use this function to implement fmemopen
/// for FreeBSD and Mac OS X.
///
/// Solution: This is only a basic solution which handles
/// opening in a+, reading, writing and seeking and takes care that you don't
/// read/write over the buffers end.
/// The solution on page 913 in the book goes much further but I didn't find
/// motivation to go that far :-)
///
/// Takeaways from this exercise:
///
/// - write is only called when I call seek (maybe also close), so I guess
///   instead of calling write right away it's queued somehow
/// - when MemStream.buffer is not mutable the code compiles and there is no
///   segfault when writing to the buffer but the buffer is just not altered.
///   This was somehow unexpected (and a segfault would have been helpful here),
///   but when changing buffer to a mut it all worked as expected.
/// - handing around the struct as a pointer is scary, but I guess still nicer
///   than a public singleton (which isn't really supported by rust).
///   As the struct instance outlives the pointer (is only dropped at end of main)
///   we're safe here
///
/// $ e07-fmemopen-bsd 2>/dev/null
/// buffer = aaaaaaaaaaaaaaaaaaaaaaaaaaaa
/// mem buffer = lorem ipsum doloraaaaaaaaaaa
/// mem buffer = lorem ipsuhansaplast!aaaaaaa

extern crate libc;
#[macro_use(cstr)]
extern crate apue;

#[cfg(any(target_os = "macos", target_os= "bsd"))]
mod fmemopen {
    use libc::{c_void, c_char, c_int, off_t, FILE, SEEK_SET, memset, memcpy, fgets, fputs, printf,
               fseek};
    use std::option::Option;
    use std::cmp::min;
    use std::mem::uninitialized;

    pub const BUFLEN: usize = 30;

    pub struct MemStream<'a> {
        buffer: &'a mut [u8; BUFLEN],
        pos: u8,
    }

    extern "C" {
        fn funopen(cookie: *mut c_void,
                   readfn: Option<unsafe extern "C" fn(cookie: *mut c_void,
                                                       buffer: *mut c_char,
                                                       nbyte: c_int)
                                                       -> c_int>,
                   writefn: Option<unsafe extern "C" fn(cookie: *mut c_void,
                                                        buffer: *mut c_char,
                                                        nbyte: c_int)
                                                        -> c_int>,
                   seekfn: Option<unsafe extern "C" fn(cookie: *mut c_void,
                                                       offset: off_t,
                                                       whence: c_int)
                                                       -> off_t>,
                   closefn: Option<unsafe extern "C" fn(cookie: *mut c_void) -> c_int>)
                   -> *mut FILE;
    }

    trait CArray {
        fn as_muti8(&self) -> *mut i8;
        fn as_void(&self) -> *mut c_void;
    }

    impl CArray for [u8] {
        fn as_muti8(&self) -> *mut i8 {
            self.as_ptr() as *mut i8
        }
        fn as_void(&self) -> *mut c_void {
            self.as_ptr() as *mut c_void
        }
    }

    unsafe fn max_bytes(nbyte: u8, status: *mut MemStream) -> u8 {
        min(nbyte, ((*status).buffer.len() as u8 - (*status).pos))
    }

    unsafe extern "C" fn read(cookie: *mut c_void, buffer: *mut c_char, nbyte: c_int) -> c_int {
        let status = cookie as *mut MemStream;
        let nbyte = max_bytes(nbyte as u8, status);
        if nbyte > 0 {
            memcpy(buffer as _, (*status).buffer.as_void(), nbyte as usize);
            (*status).pos += nbyte;
            nbyte as _
        } else {
            -1
        }
    }

    unsafe extern "C" fn write(cookie: *mut c_void, buffer: *mut c_char, nbyte: c_int) -> c_int {
        let status = cookie as *mut MemStream;
        let nbyte = max_bytes(nbyte as u8, status);
        if nbyte > 0 {
            memcpy((*(*status).buffer).as_void().offset((*status).pos as _),
                   buffer as *mut _,
                   nbyte as usize);
            (*status).pos += nbyte;
            nbyte as _
        } else {
            -1
        }
    }

    unsafe extern "C" fn seek(cookie: *mut c_void, offset: off_t, _: c_int) -> off_t {
        let status = cookie as *mut MemStream;
        (*status).pos = offset as u8;
        offset
    }

    unsafe fn fmemopen(cookie: *mut c_void) -> *mut FILE {
        funopen(cookie, Some(read), Some(write), Some(seek), None)
    }

    pub fn runit() {
        unsafe {
            let mut buf: [u8; BUFLEN] = uninitialized();
            memset(buf.as_ptr() as *mut c_void, 'a' as c_int, BUFLEN - 2);
            buf[BUFLEN - 2] = '\0' as u8;
            buf[BUFLEN - 1] = 'X' as u8;
            printf(cstr!("buffer = %s\n"), buf.as_ptr());
            let mut status = MemStream {
                buffer: &mut buf,
                pos: 0,
            };
            // could be written as &mut status as *mut _ as *mut _
            // so the types would be coerced but for clarity I wrote
            // out the types. Two casts are neeeded because first
            // the reference is cast into a pointer and then the pointer
            // type is changed
            let cookie = &mut status as *mut MemStream as *mut c_void;
            let fd = fmemopen(cookie);

            // let status2 = cookie as *mut MemStream;
            // let mut buf:[u8;BUFLEN] = *((*status2).buffer);
            // println!("buf = {:?}", buf);
            // buf[0] = 55;
            // println!("buf = {:?}", buf);

            let tmpbuf: [u8; 5] = [55; 5];
            fputs("lorem ipsum dolor\0".as_ptr() as _, fd);
            fseek(fd, 10, SEEK_SET);
            printf(cstr!("mem buffer = %s\n"), status.buffer.as_ptr());
            fputs(cstr!("hansaplast!") as _, fd);
            fseek(fd, 0, SEEK_SET);
            printf(cstr!("mem buffer = %s\n"), status.buffer.as_ptr());
            while !fgets(tmpbuf.as_ptr() as *mut i8, 5, fd).is_null() {
                printf(cstr!("buffer = %s\n"), tmpbuf.as_ptr());
            }
        }
    }
}

fn main() {
    #[cfg(any(target_os = "macos", target_os= "bsd"))]
    fmemopen::runit();
}
<|endoftext|>


<commit_before>extern crate time;

use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Debug)]
pub struct Session {
    pub id: u64,
    pub user: &'static str,
}

impl Session {
    pub fn new() -> Session {
        let now = SystemTime::now();
        let seconds = now.duration_since(UNIX_EPOCH).unwrap().as_secs();
        Session {
            id: seconds,
            user: "Rafael",
        }
    }
}
<commit_msg>add event enum<commit_after>extern crate time;

use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Debug)]
enum Event {
    WeekBegin,
    WeekEnd,
    SessionBegin,
    SessionEnd,
    Break,
    Continue,
    Meta { text: String },
    Commit { hash: u64 },
    Branch { text: String },
}

#[derive(Debug)]
pub struct Session {
    pub id: u64,
    pub user: &'static str,
    events: Vec<Event>
}

impl Session {
    pub fn new() -> Session {
        let now = SystemTime::now();
        let seconds = now.duration_since(UNIX_EPOCH).unwrap().as_secs();
        Session {
            id: seconds,
            user: "Rafael",
            events: Vec::<Event>::new(),
        }
    }
}
<|endoftext|>