<commit_before>use core::ops::Deref;
use diesel;
use diesel::expression::sql;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;
use diesel::types;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};

use db::schema::{directories, songs};
use errors::*;
use vfs::Vfs;

mod index;
mod models;
mod schema;

pub use self::index::{Index, IndexConfig};
pub use self::models::{CollectionFile, Directory, Song};

#[allow(dead_code)]
const DB_MIGRATIONS_PATH: &'static str = "src/db/migrations";
embed_migrations!("src/db/migrations");

pub struct DB {
	vfs: Arc<Vfs>,
	connection: Arc<Mutex<SqliteConnection>>,
	index: Index,
}

impl DB {
	pub fn new(vfs: Arc<Vfs>, config: &IndexConfig) -> Result<DB> {
		let path = &config.path;
		println!("Index file path: {}", path.to_string_lossy());
		let connection =
			Arc::new(Mutex::new(SqliteConnection::establish(&path.to_string_lossy())?));
		let db = DB {
			vfs: vfs.clone(),
			connection: connection.clone(),
			index: Index::new(vfs, connection.clone(), config),
		};
		db.init()?;
		Ok(db)
	}

	fn init(&self) -> Result<()> {
		{
			let connection = self.connection.lock().unwrap();
			connection.execute("PRAGMA synchronous = NORMAL")?;
		}
		self.migrate_up()?;
		Ok(())
	}

	pub fn get_index(&self) -> &Index {
		&self.index
	}

	#[allow(dead_code)]
	fn migrate_down(&self) -> Result<()> {
		let connection = self.connection.lock().unwrap();
		let connection = connection.deref();
		loop {
			match diesel::migrations::revert_latest_migration_in_directory(connection, Path::new(DB_MIGRATIONS_PATH)) {
				Ok(_) => (),
				Err(diesel::migrations::RunMigrationsError::MigrationError(diesel::migrations::MigrationError::NoMigrationRun)) => break,
				Err(e) => bail!(e),
			}
		}
		Ok(())
	}

	fn migrate_up(&self) -> Result<()> {
		let connection = self.connection.lock().unwrap();
		let connection = connection.deref();
		embedded_migrations::run(connection)?;
		Ok(())
	}

	fn virtualize_song(&self, mut song: Song) -> Option<Song> {
		song.path = match self.vfs.real_to_virtual(Path::new(&song.path)) {
			Ok(p) => p.to_string_lossy().into_owned(),
			_ => return None,
		};
		if let Some(artwork_path) = song.artwork {
			song.artwork = match self.vfs.real_to_virtual(Path::new(&artwork_path)) {
				Ok(p) => Some(p.to_string_lossy().into_owned()),
				_ => None,
			};
		}
		Some(song)
	}

	fn virtualize_directory(&self, mut directory: Directory) -> Option<Directory> {
		directory.path = match self.vfs.real_to_virtual(Path::new(&directory.path)) {
			Ok(p) => p.to_string_lossy().into_owned(),
			_ => return None,
		};
		if let Some(artwork_path) = directory.artwork {
			directory.artwork = match self.vfs.real_to_virtual(Path::new(&artwork_path)) {
				Ok(p) => Some(p.to_string_lossy().into_owned()),
				_ => None,
			};
		}
		Some(directory)
	}

	pub fn browse(&self, virtual_path: &Path) -> Result<Vec<CollectionFile>> {
		let mut output = Vec::new();
		let connection = self.connection.lock().unwrap();
		let connection = connection.deref();

		if virtual_path.components().count() == 0 {
			// Browse top-level
			let real_directories: Vec<Directory> = directories::table
				.filter(directories::columns::parent.is_null())
				.load(connection)?;
			let virtual_directories = real_directories
				.into_iter()
				.filter_map(|s| self.virtualize_directory(s));
			output.extend(virtual_directories
			                  .into_iter()
			                  .map(|d| CollectionFile::Directory(d)));

		} else {
			// Browse sub-directory
			let real_path = self.vfs.virtual_to_real(virtual_path)?;
			let real_path_string = real_path.as_path().to_string_lossy().into_owned();

			let real_songs: Vec<Song> = songs::table
				.filter(songs::columns::parent.eq(&real_path_string))
				.load(connection)?;
			let virtual_songs = real_songs
				.into_iter()
				.filter_map(|s| self.virtualize_song(s));
			output.extend(virtual_songs.map(|s| CollectionFile::Song(s)));

			let real_directories: Vec<Directory> = directories::table
				.filter(directories::columns::parent.eq(&real_path_string))
				.load(connection)?;
			let virtual_directories = real_directories
				.into_iter()
				.filter_map(|s| self.virtualize_directory(s));
			output.extend(virtual_directories.map(|d| CollectionFile::Directory(d)));
		}

		Ok(output)
	}

	pub fn flatten(&self, virtual_path: &Path) -> Result<Vec<Song>> {
		let connection = self.connection.lock().unwrap();
		let connection = connection.deref();
		let real_path = self.vfs.virtual_to_real(virtual_path)?;
		let like_path = real_path.as_path().to_string_lossy().into_owned() + "%";
		let real_songs: Vec<Song> = songs::table
			.filter(songs::columns::path.like(&like_path))
			.load(connection)?;
		let virtual_songs = real_songs
			.into_iter()
			.filter_map(|s| self.virtualize_song(s));
		Ok(virtual_songs.collect::<Vec<_>>())
	}

	pub fn get_random_albums(&self, count: i64) -> Result<Vec<Directory>> {
		let connection = self.connection.lock().unwrap();
		let connection = connection.deref();
		let real_directories = directories::table
			.filter(directories::columns::album.is_not_null())
			.limit(count)
			.order(sql::<types::Bool>("RANDOM()"))
			.load(connection)?;
		let virtual_directories = real_directories
			.into_iter()
			.filter_map(|s| self.virtualize_directory(s));
		Ok(virtual_directories.collect::<Vec<_>>())
	}

	pub fn get_recent_albums(&self, count: i64) -> Result<Vec<Directory>> {
		let connection = self.connection.lock().unwrap();
		let connection = connection.deref();
		let real_directories: Vec<Directory> = directories::table
			.filter(directories::columns::album.is_not_null())
			.order(directories::columns::date_added.desc())
			.limit(count)
			.load(connection)?;
		let virtual_directories = real_directories
			.into_iter()
			.filter_map(|s| self.virtualize_directory(s));
		Ok(virtual_directories.collect::<Vec<_>>())
	}
}

fn _get_test_db(name: &str) -> DB {
	use vfs::VfsConfig;
	use std::collections::HashMap;

	let mut collection_path = PathBuf::new();
	collection_path.push("test");
	collection_path.push("collection");
	let mut mount_points = HashMap::new();
	mount_points.insert("root".to_owned(), collection_path);
	let vfs = Arc::new(Vfs::new(VfsConfig { mount_points: mount_points }));

	let mut index_config = IndexConfig::new();
	index_config.path = PathBuf::new();
	index_config.path.push("test");
	index_config.path.push(name);

	if index_config.path.exists() {
		fs::remove_file(&index_config.path).unwrap();
	}

	DB::new(vfs, &index_config).unwrap()
}

#[test]
fn test_migrations_up() {
	_get_test_db("migrations_up.sqlite");
}

#[test]
fn test_migrations_down() {
	let db = _get_test_db("migrations_down.sqlite");
	db.migrate_down().unwrap();
	db.migrate_up().unwrap();
}

#[test]
fn test_browse_top_level() {
	let mut root_path = PathBuf::new();
	root_path.push("root");

	let db = _get_test_db("browse_top_level.sqlite");
	db.get_index().update_index().unwrap();
	let results = db.browse(Path::new("")).unwrap();

	assert_eq!(results.len(), 1);
	match results[0] {
		CollectionFile::Directory(ref d) => assert_eq!(d.path, root_path.to_str().unwrap()),
		_ => panic!("Expected directory"),
	}
}

#[test]
fn test_browse() {
	let mut khemmis_path = PathBuf::new();
	khemmis_path.push("root");
	khemmis_path.push("Khemmis");

	let mut tobokegao_path = PathBuf::new();
	tobokegao_path.push("root");
	tobokegao_path.push("Tobokegao");

	let db = _get_test_db("browse.sqlite");
	db.get_index().update_index().unwrap();
	let results = db.browse(Path::new("root")).unwrap();

	assert_eq!(results.len(), 2);
	match results[0] {
		CollectionFile::Directory(ref d) => assert_eq!(d.path, khemmis_path.to_str().unwrap()),
		_ => panic!("Expected directory"),
	}
	match results[1] {
		CollectionFile::Directory(ref d) => assert_eq!(d.path, tobokegao_path.to_str().unwrap()),
		_ => panic!("Expected directory"),
	}
}

#[test]
fn test_flatten() {
	let db = _get_test_db("flatten.sqlite");
	db.get_index().update_index().unwrap();
	let results = db.flatten(Path::new("root")).unwrap();
	assert_eq!(results.len(), 12);
}

#[test]
fn test_random() {
	let db = _get_test_db("random.sqlite");
	db.get_index().update_index().unwrap();
	let results = db.get_random_albums(1).unwrap();
	assert_eq!(results.len(), 1);
}

#[test]
fn test_recent() {
	let db = _get_test_db("recent.sqlite");
	db.get_index().update_index().unwrap();
	let results = db.get_recent_albums(2).unwrap();
	assert_eq!(results.len(), 2);
	assert!(results[0].date_added >= results[1].date_added);
}
<commit_msg>Fixed a bug where browse results were not sorted alphabetically<commit_after>use core::ops::Deref;
use diesel;
use diesel::expression::sql;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;
use diesel::types;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};

use db::schema::{directories, songs};
use errors::*;
use vfs::Vfs;

mod index;
mod models;
mod schema;

pub use self::index::{Index, IndexConfig};
pub use self::models::{CollectionFile, Directory, Song};

#[allow(dead_code)]
const DB_MIGRATIONS_PATH: &'static str = "src/db/migrations";
embed_migrations!("src/db/migrations");

pub struct DB {
	vfs: Arc<Vfs>,
	connection: Arc<Mutex<SqliteConnection>>,
	index: Index,
}

impl DB {
	pub fn new(vfs: Arc<Vfs>, config: &IndexConfig) -> Result<DB> {
		let path = &config.path;
		println!("Index file path: {}", path.to_string_lossy());
		let connection =
			Arc::new(Mutex::new(SqliteConnection::establish(&path.to_string_lossy())?));
		let db = DB {
			vfs: vfs.clone(),
			connection: connection.clone(),
			index: Index::new(vfs, connection.clone(), config),
		};
		db.init()?;
		Ok(db)
	}

	fn init(&self) -> Result<()> {
		{
			let connection = self.connection.lock().unwrap();
			connection.execute("PRAGMA synchronous = NORMAL")?;
		}
		self.migrate_up()?;
		Ok(())
	}

	pub fn get_index(&self) -> &Index {
		&self.index
	}

	#[allow(dead_code)]
	fn migrate_down(&self) -> Result<()> {
		let connection = self.connection.lock().unwrap();
		let connection = connection.deref();
		loop {
			match diesel::migrations::revert_latest_migration_in_directory(connection, Path::new(DB_MIGRATIONS_PATH)) {
				Ok(_) => (),
				Err(diesel::migrations::RunMigrationsError::MigrationError(diesel::migrations::MigrationError::NoMigrationRun)) => break,
				Err(e) => bail!(e),
			}
		}
		Ok(())
	}

	fn migrate_up(&self) -> Result<()> {
		let connection = self.connection.lock().unwrap();
		let connection = connection.deref();
		embedded_migrations::run(connection)?;
		Ok(())
	}

	fn virtualize_song(&self, mut song: Song) -> Option<Song> {
		song.path = match self.vfs.real_to_virtual(Path::new(&song.path)) {
			Ok(p) => p.to_string_lossy().into_owned(),
			_ => return None,
		};
		if let Some(artwork_path) = song.artwork {
			song.artwork = match self.vfs.real_to_virtual(Path::new(&artwork_path)) {
				Ok(p) => Some(p.to_string_lossy().into_owned()),
				_ => None,
			};
		}
		Some(song)
	}

	fn virtualize_directory(&self, mut directory: Directory) -> Option<Directory> {
		directory.path = match self.vfs.real_to_virtual(Path::new(&directory.path)) {
			Ok(p) => p.to_string_lossy().into_owned(),
			_ => return None,
		};
		if let Some(artwork_path) = directory.artwork {
			directory.artwork = match self.vfs.real_to_virtual(Path::new(&artwork_path)) {
				Ok(p) => Some(p.to_string_lossy().into_owned()),
				_ => None,
			};
		}
		Some(directory)
	}

	pub fn browse(&self, virtual_path: &Path) -> Result<Vec<CollectionFile>> {
		let mut output = Vec::new();
		let connection = self.connection.lock().unwrap();
		let connection = connection.deref();

		if virtual_path.components().count() == 0 {
			// Browse top-level
			let real_directories: Vec<Directory> = directories::table
				.filter(directories::columns::parent.is_null())
				.load(connection)?;
			let virtual_directories = real_directories
				.into_iter()
				.filter_map(|s| self.virtualize_directory(s));
			output.extend(virtual_directories
			                  .into_iter()
			                  .map(|d| CollectionFile::Directory(d)));

		} else {
			// Browse sub-directory
			let real_path = self.vfs.virtual_to_real(virtual_path)?;
			let real_path_string = real_path.as_path().to_string_lossy().into_owned();

			let real_directories: Vec<Directory> = directories::table
				.filter(directories::columns::parent.eq(&real_path_string))
				.order(directories::columns::path)
				.load(connection)?;
			let virtual_directories = real_directories
				.into_iter()
				.filter_map(|s| self.virtualize_directory(s));
			output.extend(virtual_directories.map(|d| CollectionFile::Directory(d)));

			let real_songs: Vec<Song> = songs::table
				.filter(songs::columns::parent.eq(&real_path_string))
				.order(songs::columns::path)
				.load(connection)?;
			let virtual_songs = real_songs
				.into_iter()
				.filter_map(|s| self.virtualize_song(s));
			output.extend(virtual_songs.map(|s| CollectionFile::Song(s)));
		}

		Ok(output)
	}

	pub fn flatten(&self, virtual_path: &Path) -> Result<Vec<Song>> {
		let connection = self.connection.lock().unwrap();
		let connection = connection.deref();
		let real_path = self.vfs.virtual_to_real(virtual_path)?;
		let like_path = real_path.as_path().to_string_lossy().into_owned() + "%";
		let real_songs: Vec<Song> = songs::table
			.filter(songs::columns::path.like(&like_path))
			.load(connection)?;
		let virtual_songs = real_songs
			.into_iter()
			.filter_map(|s| self.virtualize_song(s));
		Ok(virtual_songs.collect::<Vec<_>>())
	}

	pub fn get_random_albums(&self, count: i64) -> Result<Vec<Directory>> {
		let connection = self.connection.lock().unwrap();
		let connection = connection.deref();
		let real_directories = directories::table
			.filter(directories::columns::album.is_not_null())
			.limit(count)
			.order(sql::<types::Bool>("RANDOM()"))
			.load(connection)?;
		let virtual_directories = real_directories
			.into_iter()
			.filter_map(|s| self.virtualize_directory(s));
		Ok(virtual_directories.collect::<Vec<_>>())
	}

	pub fn get_recent_albums(&self, count: i64) -> Result<Vec<Directory>> {
		let connection = self.connection.lock().unwrap();
		let connection = connection.deref();
		let real_directories: Vec<Directory> = directories::table
			.filter(directories::columns::album.is_not_null())
			.order(directories::columns::date_added.desc())
			.limit(count)
			.load(connection)?;
		let virtual_directories = real_directories
			.into_iter()
			.filter_map(|s| self.virtualize_directory(s));
		Ok(virtual_directories.collect::<Vec<_>>())
	}
}

fn _get_test_db(name: &str) -> DB {
	use vfs::VfsConfig;
	use std::collections::HashMap;

	let mut collection_path = PathBuf::new();
	collection_path.push("test");
	collection_path.push("collection");
	let mut mount_points = HashMap::new();
	mount_points.insert("root".to_owned(), collection_path);
	let vfs = Arc::new(Vfs::new(VfsConfig { mount_points: mount_points }));

	let mut index_config = IndexConfig::new();
	index_config.path = PathBuf::new();
	index_config.path.push("test");
	index_config.path.push(name);

	if index_config.path.exists() {
		fs::remove_file(&index_config.path).unwrap();
	}

	DB::new(vfs, &index_config).unwrap()
}

#[test]
fn test_migrations_up() {
	_get_test_db("migrations_up.sqlite");
}

#[test]
fn test_migrations_down() {
	let db = _get_test_db("migrations_down.sqlite");
	db.migrate_down().unwrap();
	db.migrate_up().unwrap();
}

#[test]
fn test_browse_top_level() {
	let mut root_path = PathBuf::new();
	root_path.push("root");

	let db = _get_test_db("browse_top_level.sqlite");
	db.get_index().update_index().unwrap();
	let results = db.browse(Path::new("")).unwrap();

	assert_eq!(results.len(), 1);
	match results[0] {
		CollectionFile::Directory(ref d) => assert_eq!(d.path, root_path.to_str().unwrap()),
		_ => panic!("Expected directory"),
	}
}

#[test]
fn test_browse() {
	let mut khemmis_path = PathBuf::new();
	khemmis_path.push("root");
	khemmis_path.push("Khemmis");

	let mut tobokegao_path = PathBuf::new();
	tobokegao_path.push("root");
	tobokegao_path.push("Tobokegao");

	let db = _get_test_db("browse.sqlite");
	db.get_index().update_index().unwrap();
	let results = db.browse(Path::new("root")).unwrap();

	assert_eq!(results.len(), 2);
	match results[0] {
		CollectionFile::Directory(ref d) => assert_eq!(d.path, khemmis_path.to_str().unwrap()),
		_ => panic!("Expected directory"),
	}
	match results[1] {
		CollectionFile::Directory(ref d) => assert_eq!(d.path, tobokegao_path.to_str().unwrap()),
		_ => panic!("Expected directory"),
	}
}

#[test]
fn test_flatten() {
	let db = _get_test_db("flatten.sqlite");
	db.get_index().update_index().unwrap();
	let results = db.flatten(Path::new("root")).unwrap();
	assert_eq!(results.len(), 12);
}

#[test]
fn test_random() {
	let db = _get_test_db("random.sqlite");
	db.get_index().update_index().unwrap();
	let results = db.get_random_albums(1).unwrap();
	assert_eq!(results.len(), 1);
}

#[test]
fn test_recent() {
	let db = _get_test_db("recent.sqlite");
	db.get_index().update_index().unwrap();
	let results = db.get_recent_albums(2).unwrap();
	assert_eq!(results.len(), 2);
	assert!(results[0].date_added >= results[1].date_added);
}
<|endoftext|>


<commit_before>#[derive(Debug,Clone,RustcEncodable)]
pub struct Image {
    pub id: i32,
    pub name: String,
    pub tags: Vec<String>,
    pub got_from: Option<String>,
    pub original_link: Option<String>,
    pub uploader: Option<String>,
    pub rating: Option<char>,
    pub score: i32
}

/// Image voting error
pub enum VoteImageError {
    /// Voting up/down twice
    Already,
    /// No such image
    NoImage
}

/// Partial tags, e.g. `Some*`
#[derive(Debug,Clone)]
enum AnyWith {
    After(String),
    Before(String)
}

/// Ascending/descending sort
#[derive(Debug,Clone)]
enum AscDesc {
    Asc,
    Desc
}

/// Sorting, e.g. `sort:asc/desc:id/score`
#[derive(Debug,Clone)]
enum OrderBy {
    Id,
    Score
}

#[derive(Debug,Clone)]
enum Tag {
    /// Just a tag
    Include(String),
    /// Exlude tag
    Exclude(String),
    /// Rating, e.g. rating:s for safe
    Rating(Vec<String>),
    /// Partial tag
    AnyWith(AnyWith),
    /// from:derpibooru,konachan etc.
    From(Vec<String>),
    /// Uploader search
    Uploader(Vec<String>),
    /// Sorting
    OrderBy(OrderBy, AscDesc)
}

/// `pub` is used to switch DBs, though only postgres works TODO: fix sqlite sometime
pub mod postgres;
mod sqlite;

#[cfg(feature = "sqlite")]
pub use self::sqlite::Db;

#[cfg(feature = "postgresql")]
pub use self::postgres::Db;

/// Tag parsing, many copy-paste code and kinda ugly, probably could be better
fn parse_tag(tag: &str) -> Tag {
    if tag.starts_with("rating") {
        let tag = tag.split("rating:").collect::<Vec<_>>()[1];
        Tag::Rating(tag.split(',').map(String::from).collect::<Vec<_>>())
    } else if tag.starts_with("from") {
        let tag = tag.split("from:").collect::<Vec<_>>()[1];
        Tag::From(tag.split(',').map(String::from).collect::<Vec<_>>())
    } else if tag.starts_with("uploader") {
        let tag = tag.split("uploader:").collect::<Vec<_>>()[1];
        Tag::Uploader(tag.split(',').map(String::from).collect::<Vec<_>>())
    } else if tag.starts_with('-') {
        Tag::Exclude(tag[1..].to_string())
    } else if tag.starts_with('*') {
        Tag::AnyWith(AnyWith::After(tag[1..].to_string()))
    } else if tag.ends_with('*') {
        let mut n = tag.to_string();
        n.pop();
        Tag::AnyWith(AnyWith::Before(n))
    } else if tag.starts_with("sort:") {
        let t = tag.split(":").collect::<Vec<_>>();
        let s = t[1];
        let aod = match s {
            "asc" => AscDesc::Asc, // - -> +
            "desc" => AscDesc::Desc, // + -> -
            _   => AscDesc::Desc
        };
        let by = match t[2] {
            "id" => OrderBy::Id,
            "score" => OrderBy::Score,
            _   => OrderBy::Id
        };

        Tag::OrderBy(by, aod)
    } else {
        Tag::Include(tag.to_string())
    }
}

/// Strcture to ease image addition
pub struct ImageBuilder {
    name: String,
    tags: Vec<String>,
    got_from: Option<String>,
    original_link: Option<String>,
    uploader: Option<String>,
    score: i32,
    rating: Option<char>
}

impl ImageBuilder {
    pub fn new(name: &str, tags: &[String]) -> Self {
        ImageBuilder{
            name: name.to_string(),
            tags: tags.to_owned(),
            got_from: None,
            original_link: None,
            uploader: None,
            score: 0,
            rating: None
        }
    }

    pub fn got_from(mut self, got_from: &str) -> Self {
        self.got_from = Some(got_from.to_string());
        self
    }

    pub fn original_link(mut self, original_link: &str) -> Self {
        self.original_link = Some(original_link.to_string());
        self
    }

    pub fn uploader(mut self, uploader: &str) -> Self {
        self.uploader = Some(uploader.to_string());
        self
    }

    pub fn score(mut self, score: i32) -> Self {
        self.score = score;
        self
    }

    pub fn rating(mut self, rating: char) -> Self {
        self.rating = Some(rating);
        self
    }

    pub fn finalize(self) -> Self { self }
}
<commit_msg>Tag parsing implementation rewrite<commit_after>#[derive(Debug,Clone,RustcEncodable)]
pub struct Image {
    pub id: i32,
    pub name: String,
    pub tags: Vec<String>,
    pub got_from: Option<String>,
    pub original_link: Option<String>,
    pub uploader: Option<String>,
    pub rating: Option<char>,
    pub score: i32
}

/// Image voting error
pub enum VoteImageError {
    /// Voting up/down twice
    Already,
    /// No such image
    NoImage
}

/// Partial tags, e.g. `Some*`
#[derive(Debug,Clone)]
enum AnyWith {
    After(String),
    Before(String)
}

/// Ascending/descending sort
#[derive(Debug,Clone)]
enum AscDesc {
    Asc,
    Desc
}

/// Sorting, e.g. `sort:asc/desc:id/score`
#[derive(Debug,Clone)]
enum OrderBy {
    Id,
    Score
}

#[derive(Debug,Clone)]
enum Tag {
    /// Just a tag
    Include(String),
    /// Exlude tag
    Exclude(String),
    /// Rating, e.g. rating:s for safe
    Rating(Vec<String>),
    /// Partial tag
    AnyWith(AnyWith),
    /// from:derpibooru,konachan etc.
    From(Vec<String>),
    /// Uploader search
    Uploader(Vec<String>),
    /// Sorting
    OrderBy(OrderBy, AscDesc)
}

/// `pub` is used to switch DBs, though only postgres works TODO: fix sqlite sometime
pub mod postgres;
mod sqlite;

#[cfg(feature = "sqlite")]
pub use self::sqlite::Db;

#[cfg(feature = "postgresql")]
pub use self::postgres::Db;

/// Tag parsing
fn parse_tag(tag: &str) -> Tag {
    let all = tag.split(":").collect::<Vec<_>>();
    match all.len() {
        1 => {
            let tag = all[0];
            if tag.starts_with("-") {
                Tag::Exclude(tag[1..].to_string())
            } else if tag.starts_with('*') {
                Tag::AnyWith(AnyWith::After(tag[1..].to_string()))
            } else if tag.ends_with('*') {
                let mut n = tag.to_string();
                n.pop();
                Tag::AnyWith(AnyWith::Before(n))
            } else {
                Tag::Include(tag.to_string())
            }
        },
        2 => {
            let kind = all[0];
            let values = all[1].split(',').map(String::from).collect::<Vec<_>>();
            match kind {
                "rating"    => Tag::Rating(values),
                "from"      => Tag::From(values),
                "uploader"  => Tag::Uploader(values),
                _           => Tag::Include(tag.to_string()) // Probably shouldn't be anything there?
            }
        },
        3 => { // Probably sort, but should check
            if all[0] == "sort" {
                let aod = match all[1] {
                    "asc" => AscDesc::Asc, // - -> +
                    "desc" => AscDesc::Desc, // + -> -
                    _   => AscDesc::Desc
                };
                let by = match all[2] {
                    "id" => OrderBy::Id,
                    "score" => OrderBy::Score,
                    _   => OrderBy::Id
                };

                Tag::OrderBy(by, aod)
            } else {
                Tag::Include(tag.to_string())
            }
        },
        _   => { // Shouldn't happen
            Tag::Include(tag.to_string())
        }
    }
}

/// Strcture to ease image addition
pub struct ImageBuilder {
    name: String,
    tags: Vec<String>,
    got_from: Option<String>,
    original_link: Option<String>,
    uploader: Option<String>,
    score: i32,
    rating: Option<char>
}

impl ImageBuilder {
    pub fn new(name: &str, tags: &[String]) -> Self {
        ImageBuilder{
            name: name.to_string(),
            tags: tags.to_owned(),
            got_from: None,
            original_link: None,
            uploader: None,
            score: 0,
            rating: None
        }
    }

    pub fn got_from(mut self, got_from: &str) -> Self {
        self.got_from = Some(got_from.to_string());
        self
    }

    pub fn original_link(mut self, original_link: &str) -> Self {
        self.original_link = Some(original_link.to_string());
        self
    }

    pub fn uploader(mut self, uploader: &str) -> Self {
        self.uploader = Some(uploader.to_string());
        self
    }

    pub fn score(mut self, score: i32) -> Self {
        self.score = score;
        self
    }

    pub fn rating(mut self, rating: char) -> Self {
        self.rating = Some(rating);
        self
    }

    pub fn finalize(self) -> Self { self }
}
<|endoftext|>


<commit_before>use cocoa::base::{id, nil};
use cocoa::foundation::{NSUInteger, NSString};
use sys::{MTLCreateSystemDefaultDevice, MTLDevice};
use std::borrow::Cow;
use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::ffi::CStr;
use {Size};

pub struct Device(id);

impl Device {
    pub fn system_default_device() -> Result<Self, DeviceError> {
        let device = unsafe { MTLCreateSystemDefaultDevice() };
        if device != nil {
            Ok(Device(device))
        } else {
            Err(DeviceError::ConstructionFailed)
        }
    }

    pub unsafe fn get_raw(&self) -> id {
        self.0
    }

    pub fn is_headless(&self) -> bool {
        unsafe { self.0.headless() != 0 }
    }

    pub fn is_low_power(&self) -> bool {
        unsafe { self.0.lowPower() != 0 }
    }

    pub fn max_threads_per_group(&self) -> Size {
        unsafe { self.0.maxThreadsPerGroup().into() }
    }

    pub fn get_name(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(self.0.name().UTF8String()).to_string_lossy() }
    }

    pub fn supports_texture_sample_count(&self, sample_count: usize) -> bool {
        unsafe { self.0.supportsTextureSampleCount(sample_count as NSUInteger) != 0 }
    }
}

/// Internal utility function to create a Device without exposing internals.
/// Not exported publicly from this crate.
#[doc(hidden)]
pub unsafe fn _make_device(device: id) -> Device {
    Device(device)
}

#[derive(Clone, Debug)]
pub enum DeviceError {
    ConstructionFailed
}

impl Display for DeviceError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let descr = match *self {
            DeviceError::ConstructionFailed => "DeviceError::ConstructionFailed"
        };
        write!(f, "{}", descr)
    }
}

impl Error for DeviceError {
    fn description(&self) -> &str {
        match *self {
            DeviceError::ConstructionFailed =>
                "Could not create a default device. Please ensure that you are using at least OSX 10.11 or iOS 8.0"
        }
    }
}
<commit_msg>Add `ReadOnlyDevice` trait, which will be implemented by a future DeviceRef struct<commit_after>use cocoa::base::{id, nil};
use cocoa::foundation::{NSUInteger, NSString};
use sys::{MTLCreateSystemDefaultDevice, MTLDevice};
use std::borrow::Cow;
use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::ffi::CStr;
use {Size};

pub trait ReadOnlyDevice {
    pub fn is_headless(&self) -> bool;
    pub fn is_low_power(&self) -> bool;
    pub fn max_threads_per_group(&self) -> bool;
    pub fn get_name(&self) -> Cow<str>;
    pub fn supports_texture_sample_count(&self, sample_count: usize) -> bool;
}

pub struct Device(id);

impl Device {
    pub fn system_default_device() -> Result<Self, DeviceError> {
        let device = unsafe { MTLCreateSystemDefaultDevice() };
        if device != nil {
            Ok(Device(device))
        } else {
            Err(DeviceError::ConstructionFailed)
        }
    }

    pub unsafe fn get_raw(&self) -> id {
        self.0
    }

    pub fn is_headless(&self) -> bool {
        unsafe { self.0.headless() != 0 }
    }

    pub fn is_low_power(&self) -> bool {
        unsafe { self.0.lowPower() != 0 }
    }

    pub fn max_threads_per_group(&self) -> Size {
        unsafe { self.0.maxThreadsPerGroup().into() }
    }

    pub fn get_name(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(self.0.name().UTF8String()).to_string_lossy() }
    }

    pub fn supports_texture_sample_count(&self, sample_count: usize) -> bool {
        unsafe { self.0.supportsTextureSampleCount(sample_count as NSUInteger) != 0 }
    }
}

/// Internal utility function to create a Device without exposing internals.
/// Not exported publicly from this crate.
#[doc(hidden)]
pub unsafe fn _make_device(device: id) -> Device {
    Device(device)
}

#[derive(Clone, Debug)]
pub enum DeviceError {
    ConstructionFailed
}

impl Display for DeviceError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let descr = match *self {
            DeviceError::ConstructionFailed => "DeviceError::ConstructionFailed"
        };
        write!(f, "{}", descr)
    }
}

impl Error for DeviceError {
    fn description(&self) -> &str {
        match *self {
            DeviceError::ConstructionFailed =>
                "Could not create a default device. Please ensure that you are using at least OSX 10.11 or iOS 8.0"
        }
    }
}
<|endoftext|>


<commit_before>// -*- tab-width: 2 -*-

use libc;
use std::borrow::Borrow;
use std::borrow::BorrowMut;
use std::cmp;
use std::ffi::CStr;
use std::mem;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ops::Index;
use std::ops::IndexMut;
use std::ops::Range;
use std::ops::RangeFrom;
use std::ops::RangeFull;
use std::ops::RangeTo;
use std::ptr;
use std::slice;

/// Fixed-length heap-allocated vector.
/// This is basically a `Box<[T]>`, except that that type can't actually be constructed.
/// Furthermore, `[T; N]` can't be constructed if N is not a compile-time constant.
#[derive(Debug)]
pub struct Buffer<T> {
  ptr: *mut T,
  length: usize,
  owned: bool,
}

impl<T: Default> Buffer<T> {
  /// Creates a new buffer initialized to zeros.
  ///
  /// `len` is the number of elements.
  pub fn new(len: usize) -> Self {
    let mut b = unsafe {
      Buffer::new_uninitialized(len)
    };
    // TODO: Use libc::memset for primitives once we have impl specialization and memset is included
    for i in 0..len {
      b[i] = T::default();
    }
    b
  }
}

impl<T> Buffer<T> {
  /// Creates a new uninitialized buffer.
  ///
  /// `len` is the number of elements.
  /// The caller is responsible for initializing the data.
  pub unsafe fn new_uninitialized(len: usize) -> Self {
    let elem_size = mem::size_of::<T>();
    let alloc_size = len * elem_size;
    let align = cmp::max(mem::align_of::<T>(), mem::size_of::<*const libc::c_void>());
    // posix_memalign requires the alignment to be at least sizeof(void*).
    // TODO: Use alloc::heap::allocate once it's stable, or at least libc::aligned_alloc once it exists
    let mut ptr = ptr::null::<libc::c_void>() as *mut libc::c_void;
    let err = libc::posix_memalign(&mut ptr, align, alloc_size);
    if err != 0 {
      let c_msg = libc::strerror(err);
      let msg = CStr::from_ptr(c_msg);
      panic!("Failed to allocate: {}", msg.to_str().unwrap());
    }
    Buffer {
      ptr: ptr as *mut T,
      length: len,
      owned: true,
    }
  }

  /// Creates a buffer from data owned by the C API.
  ///
  /// `len` is the number of elements.
  /// The underlying data is *not* freed when the buffer is destroyed.
  pub unsafe fn from_ptr(ptr: *mut T, len: usize) -> Self {
    Buffer {
      ptr: ptr,
      length: len,
      owned: false,
    }
  }
}

impl<T> Drop for Buffer<T> {
  fn drop(&mut self) {
    if self.owned {
      // It would be nice to skip the loop entirely if std::intrinsics::needs_drop() returns false,
      // but it's not stable, and the docs say it probably never will be.
      // Note that checking to see if T implements Drop is not sufficient,
      // because T may not implement Drop, but may contain a type that does.
      unsafe {
        for x in self.iter_mut() {
          // TODO: use std::ptr::drop_in_place
          mem::drop(mem::replace(x, mem::uninitialized()));
        }
        libc::free(self.ptr as *mut libc::c_void);
      }
    }
  }
}

impl<T> AsRef<[T]> for Buffer<T> {
  #[inline]
  fn as_ref(&self) -> &[T] {
    unsafe {
      slice::from_raw_parts(self.ptr, self.length)
    }
  }
}

impl<T> AsMut<[T]> for Buffer<T> {
  #[inline]
  fn as_mut(&mut self) -> &mut [T] {
    unsafe {
      slice::from_raw_parts_mut(self.ptr, self.length)
    }
  }
}

impl<T> Deref for Buffer<T> {
  type Target = [T];

  #[inline]
  fn deref(&self) -> &[T] {
    self.as_ref()
  }
}

impl<T> DerefMut for Buffer<T> {
  #[inline]
  fn deref_mut<'a>(&'a mut self) -> &'a mut [T] {
    self.as_mut()
  }
}

impl<T> Borrow<[T]> for Buffer<T> {
  #[inline]
  fn borrow(&self) -> &[T] {
    self.as_ref()
  }
}

impl<T> BorrowMut<[T]> for Buffer<T> {
  #[inline]
  fn borrow_mut(&mut self) -> &mut [T] {
    self.as_mut()
  }
}

impl<T: Clone> Clone for Buffer<T> where T: Clone {
  #[inline]
  fn clone(&self) -> Buffer<T> {
    let mut b = unsafe {
      Buffer::new_uninitialized(self.length)
    };
    // TODO: Use std::ptr::copy for primitives once we have impl specialization
    for i in 0..self.length {
      b[i] = self[i].clone();
    }
    b
  }

  #[inline]
  fn clone_from(&mut self, other: &Buffer<T>) {
    assert!(self.length == other.length, "self.length = {}, other.length = {}", self.length, other.length);
    // TODO: Use std::ptr::copy for primitives once we have impl specialization
    for i in 0..self.length {
      self[i] = other[i].clone();
    }
  }
}

impl<T> Index<usize> for Buffer<T> {
  type Output = T;

  #[inline]
  fn index(&self, index: usize) -> &T {
    assert!(index < self.length, "index = {}, length = {}", index, self.length);
    unsafe {
      &*self.ptr.offset(index as isize)
    }
  }
}

impl<T> IndexMut<usize> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: usize) -> &mut T {
    assert!(index < self.length, "index = {}, length = {}", index, self.length);
    unsafe {
      &mut *self.ptr.offset(index as isize)
    }
  }
}

impl<T> Index<Range<usize>> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, index: Range<usize>) -> &[T] {
    assert!(index.start <= index.end, "index.start = {}, index.end = {}", index.start, index.end);
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts(&*self.ptr.offset(index.start as isize), index.len())
    }
  }
}

impl<T> IndexMut<Range<usize>> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: Range<usize>) -> &mut [T] {
    assert!(index.start <= index.end, "index.start = {}, index.end = {}", index.start, index.end);
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr.offset(index.start as isize), index.len())
    }
  }
}

impl<T> Index<RangeTo<usize>> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, index: RangeTo<usize>) -> &[T] {
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts(&*self.ptr, index.end)
    }
  }
}

impl<T> IndexMut<RangeTo<usize>> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: RangeTo<usize>) -> &mut [T] {
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr, index.end)
    }
  }
}

impl<T> Index<RangeFrom<usize>> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, index: RangeFrom<usize>) -> &[T] {
    assert!(index.start <= self.length, "index.start = {}, length = {}", index.start, self.length);
    unsafe {
      slice::from_raw_parts(&*self.ptr.offset(index.start as isize), self.length - index.start)
    }
  }
}

impl<T> IndexMut<RangeFrom<usize>> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: RangeFrom<usize>) -> &mut [T] {
    assert!(index.start <= self.length, "index.start = {}, length = {}", index.start, self.length);
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr.offset(index.start as isize), self.length - index.start)
    }
  }
}

impl<T> Index<RangeFull> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, _: RangeFull) -> &[T] {
    unsafe {
      slice::from_raw_parts(&*self.ptr, self.length)
    }
  }
}

impl<T> IndexMut<RangeFull> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, _: RangeFull) -> &mut [T] {
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr, self.length)
    }
  }
}

////////////////////////

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn basic() {
    let mut buf = Buffer::new(10);
    assert_eq!(buf.len(), 10);
    buf[0] = 1;
    assert_eq!(buf[0], 1);
  }
}
<commit_msg>Use drop_in_place when dropping Buffer instead of swapping and dropping<commit_after>// -*- tab-width: 2 -*-

use libc;
use std::borrow::Borrow;
use std::borrow::BorrowMut;
use std::cmp;
use std::ffi::CStr;
use std::mem;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ops::Index;
use std::ops::IndexMut;
use std::ops::Range;
use std::ops::RangeFrom;
use std::ops::RangeFull;
use std::ops::RangeTo;
use std::ptr;
use std::slice;

/// Fixed-length heap-allocated vector.
/// This is basically a `Box<[T]>`, except that that type can't actually be constructed.
/// Furthermore, `[T; N]` can't be constructed if N is not a compile-time constant.
#[derive(Debug)]
pub struct Buffer<T> {
  ptr: *mut T,
  length: usize,
  owned: bool,
}

impl<T: Default> Buffer<T> {
  /// Creates a new buffer initialized to zeros.
  ///
  /// `len` is the number of elements.
  pub fn new(len: usize) -> Self {
    let mut b = unsafe {
      Buffer::new_uninitialized(len)
    };
    // TODO: Use libc::memset for primitives once we have impl specialization and memset is included
    for i in 0..len {
      b[i] = T::default();
    }
    b
  }
}

impl<T> Buffer<T> {
  /// Creates a new uninitialized buffer.
  ///
  /// `len` is the number of elements.
  /// The caller is responsible for initializing the data.
  pub unsafe fn new_uninitialized(len: usize) -> Self {
    let elem_size = mem::size_of::<T>();
    let alloc_size = len * elem_size;
    let align = cmp::max(mem::align_of::<T>(), mem::size_of::<*const libc::c_void>());
    // posix_memalign requires the alignment to be at least sizeof(void*).
    // TODO: Use alloc::heap::allocate once it's stable, or at least libc::aligned_alloc once it exists
    let mut ptr = ptr::null::<libc::c_void>() as *mut libc::c_void;
    let err = libc::posix_memalign(&mut ptr, align, alloc_size);
    if err != 0 {
      let c_msg = libc::strerror(err);
      let msg = CStr::from_ptr(c_msg);
      panic!("Failed to allocate: {}", msg.to_str().unwrap());
    }
    Buffer {
      ptr: ptr as *mut T,
      length: len,
      owned: true,
    }
  }

  /// Creates a buffer from data owned by the C API.
  ///
  /// `len` is the number of elements.
  /// The underlying data is *not* freed when the buffer is destroyed.
  pub unsafe fn from_ptr(ptr: *mut T, len: usize) -> Self {
    Buffer {
      ptr: ptr,
      length: len,
      owned: false,
    }
  }
}

impl<T> Drop for Buffer<T> {
  fn drop(&mut self) {
    if self.owned {
      // It would be nice to skip the loop entirely if std::intrinsics::needs_drop() returns false,
      // but it's not stable, and the docs say it probably never will be.
      // Note that checking to see if T implements Drop is not sufficient,
      // because T may not implement Drop, but may contain a type that does.
      unsafe {
        for x in self.iter_mut() {
          ptr::drop_in_place(x)
        }
        libc::free(self.ptr as *mut libc::c_void);
      }
    }
  }
}

impl<T> AsRef<[T]> for Buffer<T> {
  #[inline]
  fn as_ref(&self) -> &[T] {
    unsafe {
      slice::from_raw_parts(self.ptr, self.length)
    }
  }
}

impl<T> AsMut<[T]> for Buffer<T> {
  #[inline]
  fn as_mut(&mut self) -> &mut [T] {
    unsafe {
      slice::from_raw_parts_mut(self.ptr, self.length)
    }
  }
}

impl<T> Deref for Buffer<T> {
  type Target = [T];

  #[inline]
  fn deref(&self) -> &[T] {
    self.as_ref()
  }
}

impl<T> DerefMut for Buffer<T> {
  #[inline]
  fn deref_mut<'a>(&'a mut self) -> &'a mut [T] {
    self.as_mut()
  }
}

impl<T> Borrow<[T]> for Buffer<T> {
  #[inline]
  fn borrow(&self) -> &[T] {
    self.as_ref()
  }
}

impl<T> BorrowMut<[T]> for Buffer<T> {
  #[inline]
  fn borrow_mut(&mut self) -> &mut [T] {
    self.as_mut()
  }
}

impl<T: Clone> Clone for Buffer<T> where T: Clone {
  #[inline]
  fn clone(&self) -> Buffer<T> {
    let mut b = unsafe {
      Buffer::new_uninitialized(self.length)
    };
    // TODO: Use std::ptr::copy for primitives once we have impl specialization
    for i in 0..self.length {
      b[i] = self[i].clone();
    }
    b
  }

  #[inline]
  fn clone_from(&mut self, other: &Buffer<T>) {
    assert!(self.length == other.length, "self.length = {}, other.length = {}", self.length, other.length);
    // TODO: Use std::ptr::copy for primitives once we have impl specialization
    for i in 0..self.length {
      self[i] = other[i].clone();
    }
  }
}

impl<T> Index<usize> for Buffer<T> {
  type Output = T;

  #[inline]
  fn index(&self, index: usize) -> &T {
    assert!(index < self.length, "index = {}, length = {}", index, self.length);
    unsafe {
      &*self.ptr.offset(index as isize)
    }
  }
}

impl<T> IndexMut<usize> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: usize) -> &mut T {
    assert!(index < self.length, "index = {}, length = {}", index, self.length);
    unsafe {
      &mut *self.ptr.offset(index as isize)
    }
  }
}

impl<T> Index<Range<usize>> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, index: Range<usize>) -> &[T] {
    assert!(index.start <= index.end, "index.start = {}, index.end = {}", index.start, index.end);
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts(&*self.ptr.offset(index.start as isize), index.len())
    }
  }
}

impl<T> IndexMut<Range<usize>> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: Range<usize>) -> &mut [T] {
    assert!(index.start <= index.end, "index.start = {}, index.end = {}", index.start, index.end);
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr.offset(index.start as isize), index.len())
    }
  }
}

impl<T> Index<RangeTo<usize>> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, index: RangeTo<usize>) -> &[T] {
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts(&*self.ptr, index.end)
    }
  }
}

impl<T> IndexMut<RangeTo<usize>> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: RangeTo<usize>) -> &mut [T] {
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr, index.end)
    }
  }
}

impl<T> Index<RangeFrom<usize>> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, index: RangeFrom<usize>) -> &[T] {
    assert!(index.start <= self.length, "index.start = {}, length = {}", index.start, self.length);
    unsafe {
      slice::from_raw_parts(&*self.ptr.offset(index.start as isize), self.length - index.start)
    }
  }
}

impl<T> IndexMut<RangeFrom<usize>> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: RangeFrom<usize>) -> &mut [T] {
    assert!(index.start <= self.length, "index.start = {}, length = {}", index.start, self.length);
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr.offset(index.start as isize), self.length - index.start)
    }
  }
}

impl<T> Index<RangeFull> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, _: RangeFull) -> &[T] {
    unsafe {
      slice::from_raw_parts(&*self.ptr, self.length)
    }
  }
}

impl<T> IndexMut<RangeFull> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, _: RangeFull) -> &mut [T] {
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr, self.length)
    }
  }
}

////////////////////////

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn basic() {
    let mut buf = Buffer::new(10);
    assert_eq!(buf.len(), 10);
    buf[0] = 1;
    assert_eq!(buf[0], 1);
  }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::net::tcp;
use std::io::net::ip::SocketAddr;
use std::io::BufferedReader;
use common::{Header, HTTPVersion, Method};
use Request;
use url::Path;
use sequential::{SequentialReader, SequentialReaderBuilder, SequentialWriterBuilder};

/// A ClientConnection is an object that will store a socket to a client
/// and return Request objects.
pub struct ClientConnection {
    // address of the client
    remote_addr: io::IoResult<SocketAddr>,

    // sequence of Readers to the stream, so that the data is not read in
    //  the wrong order
    source: SequentialReaderBuilder<tcp::TcpStream>,

    // sequence of Writers to the stream, to avoid writing response #2 before
    //  response #1
    sink: SequentialWriterBuilder<tcp::TcpStream>,

    // Reader to read the next header from
	next_header_source: BufferedReader<SequentialReader<tcp::TcpStream>>,

    // set to true if the client sent a "Connection: close" in the previous request
    connection_must_close: bool,
}

impl ClientConnection {
    /// Creates a new ClientConnection that takes ownership of the TcpStream.
    pub fn new(mut socket: tcp::TcpStream) -> ClientConnection {
        socket.set_timeout(Some(10000));

        let remote_addr = socket.peer_name();

        let mut source = SequentialReaderBuilder::new(socket.clone());
        let first_header = source.next().unwrap();

        ClientConnection {
            source: source,
            sink: SequentialWriterBuilder::new(socket),
            remote_addr: remote_addr,
            next_header_source: BufferedReader::new(first_header),
            connection_must_close: false,
        }
    }

    /// Reads a request from the stream.
    /// Blocks until the header has been read.
    fn read(&mut self) -> io::IoResult<Request> {
        let (method, path, version, headers) = {
            let mut lines = self.next_header_source.lines();

            // reading the request line
            let (method, path, version) =
                try!(parse_request_line(
                    match lines.next() {
                        Some(line) => try!(line),
                        None => return Err(gen_invalid_input(
                                    "Missing request line"))
                    }.as_slice().trim()
                ));

            // getting all headers
            let headers = {
                let mut headers = Vec::new();
                loop {
                    match lines.next() {
                        Some(line) => {
                            let line = try!(line);
                            if line.as_slice().trim().len() == 0 { break };
                            headers.push(
                                match from_str(line.as_slice().trim()) {
                                    Some(h) => h,
                                    None => return Err(gen_invalid_input(
                                        "Could not parse header"))
                                }
                            );
                        },
                        None => break
                    }
                }
                headers
            };

            (method, path, version, headers)
        };

        // finding length of body
        let body_length = headers.iter()
            .find(|h: &&Header| h.field.equiv(&"Content-Length"))
            .and_then(|h| from_str::<uint>(h.value.as_slice()))
            .unwrap_or(0u);

        // building the next reader
        let data_reader = self.source.next().unwrap();
        self.next_header_source = BufferedReader::new(self.source.next().unwrap());

        // building the writer
        let writer = self.sink.next().unwrap();

        // building the request
        Ok(Request {
            data_reader: box data_reader,
            response_writer: box writer,
            remote_addr: self.remote_addr.clone().unwrap(),     // TODO: could fail
            method: method,
            path: path,
            http_version: version,
            headers: headers,
            body_length: body_length,
        })
    }
}

impl Iterator<Request> for ClientConnection {
    /// Blocks until the next Request is available.
    /// Returns None when no new Requests will come from the client.
    fn next(&mut self) -> Option<Request> {
        // the client sent a "connection: close" header in this previous request
        //  or is using HTTP 1.0, meaning that no new request will come
        if self.connection_must_close {
            return None
        }

        // TODO: send back message to client in case of parsing error
        loop {
            let rq = match self.read() {
                Err(_) => return None,
                Ok(rq) => rq
            };

            // updating the status of the connection
            {
                let connection_header = rq.headers.iter()
                    .find(|h| h.field.equiv(&"Connection")).map(|h| h.value.as_slice());

                if connection_header == Some("close") {
                    self.connection_must_close = true;
                } else if rq.http_version == HTTPVersion(1, 0) &&
                        connection_header != Some("keep-alive")
                {
                    self.connection_must_close = true;
                }
            }

            // returning the request
            return Some(rq);
        }
    }
}

/// Generates an IoError with invalid input.
/// This function is here because it is incredibly annoying to create this error.
fn gen_invalid_input(desc: &'static str) -> io::IoError {
    io::IoError {
        kind: io::InvalidInput,
        desc: desc,
        detail: None
    }
}

/// Parses a "HTTP/1.1" string.
fn parse_http_version(version: &str) -> io::IoResult<HTTPVersion> {
    let elems = version.splitn('/', 2).map(|e| e.to_string()).collect::<Vec<String>>();
    if elems.len() != 2 {
        return Err(gen_invalid_input("Wrong HTTP version format"))
    }

    let elems = elems.get(1).as_slice().splitn('.', 2)
        .map(|e| e.to_string()).collect::<Vec<String>>();
    if elems.len() != 2 {
        return Err(gen_invalid_input("Wrong HTTP version format"))
    }

    match (from_str(elems.get(0).as_slice()), from_str(elems.get(1).as_slice())) {
        (Some(major), Some(minor)) =>
            Ok(HTTPVersion(major, minor)),
        _ => Err(gen_invalid_input("Wrong HTTP version format"))
    }
}

/// Parses the request line of the request.
/// eg. GET / HTTP/1.1
fn parse_request_line(line: &str) -> io::IoResult<(Method, Path, HTTPVersion)> {
    let mut words = line.words();

    let method = words.next();
    let path = words.next();
    let version = words.next();

    let (method, path, version) = match (method, path, version) {
        (Some(m), Some(p), Some(v)) => (m, p, v),
        _ => return Err(gen_invalid_input("Missing element in request line"))
    };

    let method = match from_str(method) {
        Some(method) => method,
        None => return Err(gen_invalid_input("Could not parse method"))
    };

    let path = match Path::parse(path) {
        Ok(p) => p,
        Err(_) => return Err(gen_invalid_input("Wrong requested URL"))
    };

    let version = try!(parse_http_version(version));

    Ok((method, path, version))
}

#[cfg(test)]
mod test {
    #[test]
    fn test_parse_request_line() {
        let (method, path, ver) =
            super::parse_request_line("GET /hello HTTP/1.1").unwrap();

        assert!(method.equiv(&"get"));
        assert!(path == from_str("/hello").unwrap());
        assert!(ver == ::common::HTTPVersion(1, 1));

        assert!(super::parse_request_line("GET /hello").is_err());
        assert!(super::parse_request_line("qsd qsd qsd").is_err());
    }
}
<commit_msg>Reading the header no longer reads too much<commit_after>use std::io;
use std::io::IoResult;
use std::io::net::tcp;
use std::io::net::ip::SocketAddr;
use std::io::BufferedReader;
use common::{Header, HTTPVersion, Method};
use Request;
use url::Path;
use sequential::{SequentialReader, SequentialReaderBuilder, SequentialWriterBuilder};

/// A ClientConnection is an object that will store a socket to a client
/// and return Request objects.
pub struct ClientConnection {
    // address of the client
    remote_addr: io::IoResult<SocketAddr>,

    // sequence of Readers to the stream, so that the data is not read in
    //  the wrong order
    source: SequentialReaderBuilder<tcp::TcpStream>,

    // sequence of Writers to the stream, to avoid writing response #2 before
    //  response #1
    sink: SequentialWriterBuilder<tcp::TcpStream>,

    // Reader to read the next header from
	next_header_source: SequentialReader<tcp::TcpStream>,

    // set to true if the client sent a "Connection: close" in the previous request
    connection_must_close: bool,
}

impl ClientConnection {
    /// Creates a new ClientConnection that takes ownership of the TcpStream.
    pub fn new(mut socket: tcp::TcpStream) -> ClientConnection {
        socket.set_timeout(Some(10000));

        let remote_addr = socket.peer_name();

        let mut source = SequentialReaderBuilder::new(socket.clone());
        let first_header = source.next().unwrap();

        ClientConnection {
            source: source,
            sink: SequentialWriterBuilder::new(socket),
            remote_addr: remote_addr,
            next_header_source: first_header,
            connection_must_close: false,
        }
    }

    /// Reads the next line from self.next_header_source.
    ///
    /// Reads until `CRLF` is reached. The next read will start
    ///  at the first byte of the new line.
    fn read_next_line(&mut self) -> IoResult<String> {
        use std::io;
        use std::path::BytesContainer;

        let mut buf = Vec::new();
        let mut prev_byte_was_cr = false;

        loop {
            let byte = try!(self.next_header_source.read_byte());

            if byte == b'\n' && prev_byte_was_cr {
                return match buf.container_as_str() {
                    Some(s) => Ok(s.to_string()),
                    None => Err(io::standard_error(io::InvalidInput))
                }
            }

            if byte == b'\r' {
                prev_byte_was_cr = true;
            } else {
                prev_byte_was_cr = false;
            }

            buf.push(byte);
        }
    }

    /// Reads a request from the stream.
    /// Blocks until the header has been read.
    fn read(&mut self) -> io::IoResult<Request> {
        let (method, path, version, headers) = {
            // reading the request line
            let (method, path, version) = {
                let line = try!(self.read_next_line());

                try!(parse_request_line(
                    line.as_slice().trim()
                ))
            };

            // getting all headers
            let headers = {
                let mut headers = Vec::new();
                loop {
                    let line = try!(self.read_next_line());

                    if line.as_slice().trim().len() == 0 { break };
                    headers.push(
                        match from_str(line.as_slice().trim()) {
                            Some(h) => h,
                            None => return Err(gen_invalid_input(
                                "Could not parse header"))
                        }
                    );
                }
                headers
            };

            (method, path, version, headers)
        };

        // finding length of body
        let body_length = headers.iter()
            .find(|h: &&Header| h.field.equiv(&"Content-Length"))
            .and_then(|h| from_str::<uint>(h.value.as_slice()))
            .unwrap_or(0u);

        // building the next reader
        let data_reader = self.source.next().unwrap();
        self.next_header_source = self.source.next().unwrap();

        // building the writer
        let writer = self.sink.next().unwrap();

        // building the request
        Ok(Request {
            data_reader: box data_reader,
            response_writer: box writer,
            remote_addr: self.remote_addr.clone().unwrap(),     // TODO: could fail
            method: method,
            path: path,
            http_version: version,
            headers: headers,
            body_length: body_length,
        })
    }
}

impl Iterator<Request> for ClientConnection {
    /// Blocks until the next Request is available.
    /// Returns None when no new Requests will come from the client.
    fn next(&mut self) -> Option<Request> {
        // the client sent a "connection: close" header in this previous request
        //  or is using HTTP 1.0, meaning that no new request will come
        if self.connection_must_close {
            return None
        }

        // TODO: send back message to client in case of parsing error
        loop {
            let rq = match self.read() {
                Err(_) => return None,
                Ok(rq) => rq
            };

            // updating the status of the connection
            {
                let connection_header = rq.headers.iter()
                    .find(|h| h.field.equiv(&"Connection")).map(|h| h.value.as_slice());

                if connection_header == Some("close") {
                    self.connection_must_close = true;
                } else if rq.http_version == HTTPVersion(1, 0) &&
                        connection_header != Some("keep-alive")
                {
                    self.connection_must_close = true;
                }
            }

            // returning the request
            return Some(rq);
        }
    }
}

/// Generates an IoError with invalid input.
/// This function is here because it is incredibly annoying to create this error.
fn gen_invalid_input(desc: &'static str) -> io::IoError {
    io::IoError {
        kind: io::InvalidInput,
        desc: desc,
        detail: None
    }
}

/// Parses a "HTTP/1.1" string.
fn parse_http_version(version: &str) -> io::IoResult<HTTPVersion> {
    let elems = version.splitn('/', 2).map(|e| e.to_string()).collect::<Vec<String>>();
    if elems.len() != 2 {
        return Err(gen_invalid_input("Wrong HTTP version format"))
    }

    let elems = elems.get(1).as_slice().splitn('.', 2)
        .map(|e| e.to_string()).collect::<Vec<String>>();
    if elems.len() != 2 {
        return Err(gen_invalid_input("Wrong HTTP version format"))
    }

    match (from_str(elems.get(0).as_slice()), from_str(elems.get(1).as_slice())) {
        (Some(major), Some(minor)) =>
            Ok(HTTPVersion(major, minor)),
        _ => Err(gen_invalid_input("Wrong HTTP version format"))
    }
}

/// Parses the request line of the request.
/// eg. GET / HTTP/1.1
fn parse_request_line(line: &str) -> io::IoResult<(Method, Path, HTTPVersion)> {
    let mut words = line.words();

    let method = words.next();
    let path = words.next();
    let version = words.next();

    let (method, path, version) = match (method, path, version) {
        (Some(m), Some(p), Some(v)) => (m, p, v),
        _ => return Err(gen_invalid_input("Missing element in request line"))
    };

    let method = match from_str(method) {
        Some(method) => method,
        None => return Err(gen_invalid_input("Could not parse method"))
    };

    let path = match Path::parse(path) {
        Ok(p) => p,
        Err(_) => return Err(gen_invalid_input("Wrong requested URL"))
    };

    let version = try!(parse_http_version(version));

    Ok((method, path, version))
}

#[cfg(test)]
mod test {
    #[test]
    fn test_parse_request_line() {
        let (method, path, ver) =
            super::parse_request_line("GET /hello HTTP/1.1").unwrap();

        assert!(method.equiv(&"get"));
        assert!(path == from_str("/hello").unwrap());
        assert!(ver == ::common::HTTPVersion(1, 1));

        assert!(super::parse_request_line("GET /hello").is_err());
        assert!(super::parse_request_line("qsd qsd qsd").is_err());
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::net::{
    IpAddr,
    Ipv4Addr,
    SocketAddr,
};
use std::sync::mpsc::sync_channel;
use std::time::{Duration, Instant};
use std::thread;

use kudu_pb::master::{
    DeleteTableRequestPB,
    IsCreateTableDoneRequestPB,
};
use uuid::Uuid;

use backoff::Backoff;
use master::MasterProxy;
use rpc::Messenger;
use table::TableBuilder;
use Result;

#[derive(Clone)]
pub struct Client {
    messenger: Messenger,
    master: MasterProxy,
    config: ClientConfig,
}

impl Client {

    fn new(config: ClientConfig) -> Client {
        let messenger = Messenger::new().unwrap();
        let master = MasterProxy::new(config.master_addresses(), messenger.clone());
        Client {
            master: master,
            messenger: messenger,
            config: config,
        }
    }

    /// Creates a new Kudu table with the schema and options specified by `builder`. Returns the
    /// new table's ID, or an error on failure.
    fn create_table(&self, builder: TableBuilder, deadline: Instant) -> Result<Uuid> {
        let (send, recv) = sync_channel(0);
        self.master.create_table(deadline, builder.into_pb(), move |resp| send.send(resp).unwrap());
        recv.recv().unwrap().map(|resp| Uuid::parse_str(&String::from_utf8_lossy(resp.get_table_id())).unwrap())
    }

    /// Returns true if the table is fully created.
    fn is_create_table_done(&self, table: Uuid, deadline: Instant) -> Result<bool> {
        let mut request = IsCreateTableDoneRequestPB::new();
        request.mut_table().set_table_id(table.simple().to_string().into_bytes());

        let (send, recv) = sync_channel(0);
        self.master.is_create_table_done(deadline, request, move |resp| send.send(resp).unwrap());
        recv.recv().unwrap().map(|resp| resp.get_done())
    }

    /// Synchronously waits until the table is created. If an error is returned, the table may not
    /// be created yet.
    fn wait_for_table_creation(&self, table: Uuid, deadline: Instant) -> Result<()> {
        let mut backoff = Backoff::with_duration_range(16, 4096);

        let mut is_create_table_done = self.is_create_table_done(table.clone(), deadline);
        while let Ok(false) = is_create_table_done {
            let sleep_ms = backoff.next_backoff_ms();
            debug!("create table not yet complete, waiting {}ms", sleep_ms);
            // TODO: don't sleep if it would expire the deadline.
            thread::sleep(Duration::from_millis(sleep_ms));
            is_create_table_done = self.is_create_table_done(table.clone(), deadline);
        }
        is_create_table_done.map(|_| ())
    }

    /// Deletes the Kudu table.
    fn delete_table(&self, table: Uuid, deadline: Instant) -> Result<()> {
        let mut request = DeleteTableRequestPB::new();
        request.mut_table().set_table_id(table.simple().to_string().into_bytes());

        let (send, recv) = sync_channel(0);
        self.master.delete_table(deadline, request, move |resp| send.send(resp).unwrap());
        recv.recv().unwrap().map(|_| ())
    }
}

impl fmt::Debug for Client {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Client")
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ClientConfig {

    /// A seed set of master addresses. Must contain at least one active master in the cluster.
    master_addresses: Vec<SocketAddr>,

    /// The default timeout for admin operations.
    default_admin_operation_timeout: Duration,
}

impl ClientConfig {
    fn new(master_addresses: Vec<SocketAddr>) -> ClientConfig {
        ClientConfig {
            master_addresses: master_addresses,
            ..Default::default()
        }
    }

    fn master_addresses(&self) -> &[SocketAddr] {
        &self.master_addresses
    }

    fn set_master_addresses(&mut self, master_addresses: Vec<SocketAddr>) -> &mut ClientConfig {
        self.master_addresses = master_addresses;
        self
    }

    fn default_admin_operation_timeout(&self) -> Duration {
        self.default_admin_operation_timeout
    }

    fn set_default_admin_operation_timeout(&mut self, timeout: Duration) -> &mut ClientConfig {
        self.default_admin_operation_timeout = timeout;
        self
    }
}

impl Default for ClientConfig {
    fn default() -> ClientConfig {
        ClientConfig {
            master_addresses: vec![SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 7051)],
            default_admin_operation_timeout: Duration::from_secs(30),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::time::{Duration, Instant};

    use mini_cluster::MiniCluster;
    use SchemaBuilder;
    use super::*;
    use TableBuilder;
    use DataType;

    use env_logger;

    fn deadline() -> Instant {
        Instant::now() + Duration::from_secs(5)
    }

    #[test]
    fn create_and_delete_table() {
        let _ = env_logger::init();
        let cluster = MiniCluster::default();

        let client = Client::new(ClientConfig::new(cluster.master_addrs().to_owned()));

        let mut schema_builder = SchemaBuilder::new();
        schema_builder.add_column("key", DataType::Int32).set_not_null();
        schema_builder.add_column("val", DataType::Int32);
        schema_builder.set_primary_key(vec!["key".to_owned()]);

        let mut table_builder = TableBuilder::new("create_and_delete_table",
                                                  schema_builder.build().unwrap());
        table_builder.add_hash_partitions(vec!["key".to_owned()], 4);
        table_builder.set_num_replicas(1);

        // The tablet server is real slow coming up.
        // TODO: add MiniCluster::wait_for_startup() or equivalent.
        ::std::thread::sleep_ms(2000);

        let table_id = client.create_table(table_builder, deadline()).unwrap();
        client.wait_for_table_creation(table_id, deadline()).unwrap();

        client.delete_table(table_id, deadline()).unwrap();
    }
}
<commit_msg>Client methods should be public<commit_after>use std::fmt;
use std::net::{
    IpAddr,
    Ipv4Addr,
    SocketAddr,
};
use std::sync::mpsc::sync_channel;
use std::time::{Duration, Instant};
use std::thread;

use kudu_pb::master::{
    DeleteTableRequestPB,
    IsCreateTableDoneRequestPB,
};
use uuid::Uuid;

use backoff::Backoff;
use master::MasterProxy;
use rpc::Messenger;
use table::TableBuilder;
use Result;

#[derive(Clone)]
pub struct Client {
    messenger: Messenger,
    master: MasterProxy,
    config: ClientConfig,
}

impl Client {

    pub fn new(config: ClientConfig) -> Client {
        let messenger = Messenger::new().unwrap();
        let master = MasterProxy::new(config.master_addresses(), messenger.clone());
        Client {
            master: master,
            messenger: messenger,
            config: config,
        }
    }

    /// Creates a new Kudu table with the schema and options specified by `builder`. Returns the
    /// new table's ID, or an error on failure.
    pub fn create_table(&self, builder: TableBuilder, deadline: Instant) -> Result<Uuid> {
        let (send, recv) = sync_channel(0);
        self.master.create_table(deadline, builder.into_pb(), move |resp| send.send(resp).unwrap());
        recv.recv().unwrap().map(|resp| Uuid::parse_str(&String::from_utf8_lossy(resp.get_table_id())).unwrap())
    }

    /// Returns true if the table is fully created.
    pub fn is_create_table_done(&self, table: Uuid, deadline: Instant) -> Result<bool> {
        let mut request = IsCreateTableDoneRequestPB::new();
        request.mut_table().set_table_id(table.simple().to_string().into_bytes());

        let (send, recv) = sync_channel(0);
        self.master.is_create_table_done(deadline, request, move |resp| send.send(resp).unwrap());
        recv.recv().unwrap().map(|resp| resp.get_done())
    }

    /// Synchronously waits until the table is created. If an error is returned, the table may not
    /// be created yet.
    pub fn wait_for_table_creation(&self, table: Uuid, deadline: Instant) -> Result<()> {
        let mut backoff = Backoff::with_duration_range(16, 4096);

        let mut is_create_table_done = self.is_create_table_done(table.clone(), deadline);
        while let Ok(false) = is_create_table_done {
            let sleep_ms = backoff.next_backoff_ms();
            debug!("create table not yet complete, waiting {}ms", sleep_ms);
            // TODO: don't sleep if it would expire the deadline.
            thread::sleep(Duration::from_millis(sleep_ms));
            is_create_table_done = self.is_create_table_done(table.clone(), deadline);
        }
        is_create_table_done.map(|_| ())
    }

    /// Deletes the Kudu table.
    pub fn delete_table(&self, table: Uuid, deadline: Instant) -> Result<()> {
        let mut request = DeleteTableRequestPB::new();
        request.mut_table().set_table_id(table.simple().to_string().into_bytes());

        let (send, recv) = sync_channel(0);
        self.master.delete_table(deadline, request, move |resp| send.send(resp).unwrap());
        recv.recv().unwrap().map(|_| ())
    }
}

impl fmt::Debug for Client {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Client")
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ClientConfig {

    /// A seed set of master addresses. Must contain at least one active master in the cluster.
    master_addresses: Vec<SocketAddr>,

    /// The default timeout for admin operations.
    default_admin_operation_timeout: Duration,
}

impl ClientConfig {
    pub fn new(master_addresses: Vec<SocketAddr>) -> ClientConfig {
        ClientConfig {
            master_addresses: master_addresses,
            ..Default::default()
        }
    }

    pub fn master_addresses(&self) -> &[SocketAddr] {
        &self.master_addresses
    }

    pub fn set_master_addresses(&mut self, master_addresses: Vec<SocketAddr>) -> &mut ClientConfig {
        self.master_addresses = master_addresses;
        self
    }

    pub fn default_admin_operation_timeout(&self) -> Duration {
        self.default_admin_operation_timeout
    }

    pub fn set_default_admin_operation_timeout(&mut self, timeout: Duration) -> &mut ClientConfig {
        self.default_admin_operation_timeout = timeout;
        self
    }
}

impl Default for ClientConfig {
    fn default() -> ClientConfig {
        ClientConfig {
            master_addresses: vec![SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 7051)],
            default_admin_operation_timeout: Duration::from_secs(30),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::time::{Duration, Instant};

    use mini_cluster::MiniCluster;
    use SchemaBuilder;
    use super::*;
    use TableBuilder;
    use DataType;

    use env_logger;

    fn deadline() -> Instant {
        Instant::now() + Duration::from_secs(5)
    }

    #[test]
    fn create_and_delete_table() {
        let _ = env_logger::init();
        let cluster = MiniCluster::default();

        let client = Client::new(ClientConfig::new(cluster.master_addrs().to_owned()));

        let mut schema_builder = SchemaBuilder::new();
        schema_builder.add_column("key", DataType::Int32).set_not_null();
        schema_builder.add_column("val", DataType::Int32);
        schema_builder.set_primary_key(vec!["key".to_owned()]);

        let mut table_builder = TableBuilder::new("create_and_delete_table",
                                                  schema_builder.build().unwrap());
        table_builder.add_hash_partitions(vec!["key".to_owned()], 4);
        table_builder.set_num_replicas(1);

        // The tablet server is real slow coming up.
        // TODO: add MiniCluster::wait_for_startup() or equivalent.
        ::std::thread::sleep_ms(2000);

        let table_id = client.create_table(table_builder, deadline()).unwrap();
        client.wait_for_table_creation(table_id, deadline()).unwrap();

        client.delete_table(table_id, deadline()).unwrap();
    }
}
<|endoftext|>


<commit_before>use hb;

/// A type to represent 4 byte tags that are used in many font formats for naming font tables,
/// font features and similar.
///
/// The user-facing representation is a 4-character ASCII string. `Tag` provides methods to create
/// `Tag`s from such a representation and to get the string representation from a `Tag`.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct Tag(pub hb::hb_tag_t);

impl Tag {
    /// Create a `Tag` from its four-char textual representation.
    ///
    /// # Examples
    ///
    /// ```
    /// use harfbuzz_rs::Tag;
    /// let cmap_tag = Tag::new('c', 'm', 'a', 'p');
    /// assert_eq!(cmap_tag.to_string(), "cmap")
    /// ```
    ///
    pub fn new(a: char, b: char, c: char, d: char) -> Self {
        Tag(((a as u32) << 24) | ((b as u32) << 16) | ((c as u32) << 8) | (d as u32))
    }

    fn tag_to_string(self) -> String {
        let mut buf: [u8; 4] = [0; 4];
        unsafe { hb::hb_tag_to_string(self.0, buf.as_mut_ptr() as *mut _) };
        String::from_utf8_lossy(&buf).into()
    }
}

use std::fmt;
use std::fmt::{Debug, Display, Formatter};
impl Debug for Tag {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let string = self.tag_to_string();
        let mut chars = string.chars().chain(std::iter::repeat('\u{FFFD}'));
        write!(f,
               "Tag({:?}, {:?}, {:?}, {:?})",
               chars.next().unwrap(),
               chars.next().unwrap(),
               chars.next().unwrap(),
               chars.next().unwrap())
    }
}

impl Display for Tag {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}", self.tag_to_string())
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
/// An Error generated when a `Tag` fails to parse from a `&str` with the `from_str` function.
pub enum TagFromStrErr {
    /// The string contains non-ASCII characters.
    NonAscii,
    /// The string has length zero.
    ZeroLengthString,
}

use std;
use std::str::FromStr;
use std::ascii::AsciiExt;

impl FromStr for Tag {
    type Err = TagFromStrErr;
    /// Parses a `Tag` from a `&str` that contains four or less ASCII characters. When the string's
    /// length is smaller than 4 it is extended with `' '` (Space) characters. The remaining bytes
    /// of strings longer than 4 bytes are ignored.
    ///
    /// # Examples
    ///
    /// ```
    /// use harfbuzz_rs::Tag;
    /// use std::str::FromStr;
    /// let tag1 = Tag::from_str("ABCD").unwrap();
    /// let tag2 = Tag::new('A', 'B', 'C', 'D');
    /// assert_eq!(tag1, tag2);
    /// ```
    ///
    fn from_str(s: &str) -> Result<Tag, TagFromStrErr> {
        if s.is_ascii() == false {
            return Err(TagFromStrErr::NonAscii);
        }
        if s.len() == 0 {
            return Err(TagFromStrErr::ZeroLengthString);
        }
        let len = std::cmp::max(s.len(), 4) as i32;
        unsafe { Ok(Tag(hb::hb_tag_from_string(s.as_ptr() as *mut _, len))) }
    }
}

pub struct Language(pub hb::hb_language_t);

impl Default for Language {
    fn default() -> Language {
        Language(unsafe { hb::hb_language_get_default() })
    }
}

impl Debug for Language {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Language(\"{}\")", self)
    }
}

use std::ffi::CStr;
impl Display for Language {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let string = unsafe {
            let char_ptr = hb::hb_language_to_string(self.0);
            CStr::from_ptr(char_ptr)
                .to_str()
                .expect("String representation of language is not valid utf8.")
        };
        write!(f, "{}", string)
    }
}

pub struct InvalidLanguage;

impl FromStr for Language {
    type Err = InvalidLanguage;
    fn from_str(s: &str) -> Result<Language, InvalidLanguage> {
        let len = std::cmp::max(s.len(), std::i32::MAX as _) as i32;
        let lang = unsafe { hb::hb_language_from_string(s.as_ptr() as *mut _, len) };
        if lang.is_null() {
            Err(InvalidLanguage {})
        } else {
            Ok(Language(lang))
        }
    }
}

/// All trait all wrappers for harfbuzz objects implement. It exposes common functionality for
/// converting from and to the underlying raw harfbuzz pointers.
pub trait HarfbuzzObject: Clone {
    /// Type of the raw harfbuzz object pointer;
    type Raw;

    /// Creates a value safely wrapping the raw harfbuzz pointer. Transfers ownership. _Use of the
    /// original pointer is now forbidden!_ Unsafe because a dereference of a raw pointer is
    /// necesarry.
    unsafe fn from_raw(val: Self::Raw) -> Self;

    /// Creates a value safely wrapping the raw harfbuzz pointer and references it immediately so
    /// that the existing pointer can still be used as normal. Unsafe because a dereference of a
    /// raw pointer is necesarry.
    unsafe fn from_raw_referenced(val: Self::Raw) -> Self {
        let result = Self::from_raw(val);
        std::mem::forget(result.clone()); // increase reference count
        result
    }

    /// Returns the underlying harfbuzz object pointer. The caller must ensure, that this pointer is
    /// not used after the `self`'s destruction.
    fn as_raw(&self) -> Self::Raw;

    /// Returns the underlying harfbuzz object pointer after referencing the object. The resulting
    /// pointer has to be manually destroyed using `hb_TYPE_destroy` or be converted back into the
    /// wrapper using the `from_raw` function.
    fn as_raw_referenced(&self) -> Self::Raw {
        std::mem::forget(self.clone()); // increase reference count
        self.as_raw()
    }

    /// Converts `self` into the underlying harfbuzz object pointer value. The resulting pointer
    /// has to be manually destroyed using `hb_TYPE_destroy` or be converted back into the wrapper
    /// using the `from_raw` function.
    fn into_raw(self) -> Self::Raw {
        let result = self.as_raw();
        std::mem::forget(self);
        result
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::FromStr;

    #[test]
    fn test_tag_debugging() {
        let tag = Tag::from_str("ABCD").unwrap();
        assert_eq!("ABCD", format!("{}", tag));
        assert_eq!("Tag('A', 'B', 'C', 'D')", format!("{:?}", tag));
    }

    #[test]
    fn test_tag_creation() {
        assert!(Tag::from_str("∞BCD").is_err());
        assert!(Tag::from_str("").is_err());
        assert_eq!(Tag::from_str("ABCDE"), Tag::from_str("ABCD"));
        assert_eq!(Tag::from_str("abWd").unwrap(), Tag::new('a', 'b', 'W', 'd'));
    }
}
<commit_msg>Fix bug and add tests for Language<commit_after>use hb;

/// A type to represent 4 byte tags that are used in many font formats for naming font tables,
/// font features and similar.
///
/// The user-facing representation is a 4-character ASCII string. `Tag` provides methods to create
/// `Tag`s from such a representation and to get the string representation from a `Tag`.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct Tag(pub hb::hb_tag_t);

impl Tag {
    /// Create a `Tag` from its four-char textual representation.
    ///
    /// # Examples
    ///
    /// ```
    /// use harfbuzz_rs::Tag;
    /// let cmap_tag = Tag::new('c', 'm', 'a', 'p');
    /// assert_eq!(cmap_tag.to_string(), "cmap")
    /// ```
    ///
    pub fn new(a: char, b: char, c: char, d: char) -> Self {
        Tag(((a as u32) << 24) | ((b as u32) << 16) | ((c as u32) << 8) | (d as u32))
    }

    fn tag_to_string(self) -> String {
        let mut buf: [u8; 4] = [0; 4];
        unsafe { hb::hb_tag_to_string(self.0, buf.as_mut_ptr() as *mut _) };
        String::from_utf8_lossy(&buf).into()
    }
}

use std::fmt;
use std::fmt::{Debug, Display, Formatter};
impl Debug for Tag {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let string = self.tag_to_string();
        let mut chars = string.chars().chain(std::iter::repeat('\u{FFFD}'));
        write!(f,
               "Tag({:?}, {:?}, {:?}, {:?})",
               chars.next().unwrap(),
               chars.next().unwrap(),
               chars.next().unwrap(),
               chars.next().unwrap())
    }
}

impl Display for Tag {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}", self.tag_to_string())
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
/// An Error generated when a `Tag` fails to parse from a `&str` with the `from_str` function.
pub enum TagFromStrErr {
    /// The string contains non-ASCII characters.
    NonAscii,
    /// The string has length zero.
    ZeroLengthString,
}

use std;
use std::str::FromStr;
use std::ascii::AsciiExt;

impl FromStr for Tag {
    type Err = TagFromStrErr;
    /// Parses a `Tag` from a `&str` that contains four or less ASCII characters. When the string's
    /// length is smaller than 4 it is extended with `' '` (Space) characters. The remaining bytes
    /// of strings longer than 4 bytes are ignored.
    ///
    /// # Examples
    ///
    /// ```
    /// use harfbuzz_rs::Tag;
    /// use std::str::FromStr;
    /// let tag1 = Tag::from_str("ABCD").unwrap();
    /// let tag2 = Tag::new('A', 'B', 'C', 'D');
    /// assert_eq!(tag1, tag2);
    /// ```
    ///
    fn from_str(s: &str) -> Result<Tag, TagFromStrErr> {
        if s.is_ascii() == false {
            return Err(TagFromStrErr::NonAscii);
        }
        if s.len() == 0 {
            return Err(TagFromStrErr::ZeroLengthString);
        }
        let len = std::cmp::max(s.len(), 4) as i32;
        unsafe { Ok(Tag(hb::hb_tag_from_string(s.as_ptr() as *mut _, len))) }
    }
}

pub struct Language(pub hb::hb_language_t);

impl Default for Language {
    fn default() -> Language {
        Language(unsafe { hb::hb_language_get_default() })
    }
}

impl Debug for Language {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Language(\"{}\")", self)
    }
}

use std::ffi::CStr;
impl Display for Language {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let string = unsafe {
            let char_ptr = hb::hb_language_to_string(self.0);
            CStr::from_ptr(char_ptr)
                .to_str()
                .expect("String representation of language is not valid utf8.")
        };
        write!(f, "{}", string)
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct InvalidLanguage;

impl FromStr for Language {
    type Err = InvalidLanguage;
    fn from_str(s: &str) -> Result<Language, InvalidLanguage> {
        let len = std::cmp::min(s.len(), std::i32::MAX as _) as i32;
        let lang = unsafe { hb::hb_language_from_string(s.as_ptr() as *mut _, len) };
        if lang.is_null() {
            Err(InvalidLanguage {})
        } else {
            Ok(Language(lang))
        }
    }
}

/// All trait all wrappers for harfbuzz objects implement. It exposes common functionality for
/// converting from and to the underlying raw harfbuzz pointers.
pub trait HarfbuzzObject: Clone {
    /// Type of the raw harfbuzz object pointer;
    type Raw;

    /// Creates a value safely wrapping the raw harfbuzz pointer. Transfers ownership. _Use of the
    /// original pointer is now forbidden!_ Unsafe because a dereference of a raw pointer is
    /// necesarry.
    unsafe fn from_raw(val: Self::Raw) -> Self;

    /// Creates a value safely wrapping the raw harfbuzz pointer and references it immediately so
    /// that the existing pointer can still be used as normal. Unsafe because a dereference of a
    /// raw pointer is necesarry.
    unsafe fn from_raw_referenced(val: Self::Raw) -> Self {
        let result = Self::from_raw(val);
        std::mem::forget(result.clone()); // increase reference count
        result
    }

    /// Returns the underlying harfbuzz object pointer. The caller must ensure, that this pointer is
    /// not used after the `self`'s destruction.
    fn as_raw(&self) -> Self::Raw;

    /// Returns the underlying harfbuzz object pointer after referencing the object. The resulting
    /// pointer has to be manually destroyed using `hb_TYPE_destroy` or be converted back into the
    /// wrapper using the `from_raw` function.
    fn as_raw_referenced(&self) -> Self::Raw {
        std::mem::forget(self.clone()); // increase reference count
        self.as_raw()
    }

    /// Converts `self` into the underlying harfbuzz object pointer value. The resulting pointer
    /// has to be manually destroyed using `hb_TYPE_destroy` or be converted back into the wrapper
    /// using the `from_raw` function.
    fn into_raw(self) -> Self::Raw {
        let result = self.as_raw();
        std::mem::forget(self);
        result
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::FromStr;

    #[test]
    fn test_tag_debugging() {
        let tag = Tag::from_str("ABCD").unwrap();
        assert_eq!("ABCD", format!("{}", tag));
        assert_eq!("Tag('A', 'B', 'C', 'D')", format!("{:?}", tag));
    }

    #[test]
    fn test_tag_creation() {
        assert!(Tag::from_str("∞BCD").is_err());
        assert!(Tag::from_str("").is_err());
        assert_eq!(Tag::from_str("ABCDE"), Tag::from_str("ABCD"));
        assert_eq!(Tag::from_str("abWd").unwrap(), Tag::new('a', 'b', 'W', 'd'));
    }

    #[test]
    fn test_language() {
        assert_eq!(Language::default().to_string(), "c");
        assert_eq!(Language::from_str("ger").unwrap().to_string(), "ger");
        assert_eq!(Language::from_str("ge!").unwrap().to_string(), "ge");
        assert_eq!(Language::from_str("German").unwrap().to_string(), "german");
    }
}
<|endoftext|>