<commit_before>//! Library for manipulating Game Maker Studio's "data.win" (GEN8) data files.
//!
//! Typical usage consists of reading [GameData](struct.GameData.html) from a file, doing stuff with it,
//! then writing it back to a file.
//!
//! Example:
//!
//! ```no_run
//! let mut game_data = rgmk::GameData::from_file("data.win").expect("Failed to open data.win");
//! game_data.strings.strings[0] = "NYEH HEH HEH!".into();
//! game_data.save_to_file("data.win").expect("Failed to save data.win");
//! ```
//!

#![feature(read_exact, associated_consts, associated_type_defaults)]
#![warn(missing_docs, trivial_casts, trivial_numeric_casts)]

#[macro_use]
extern crate quick_error;
extern crate byteorder;
#[macro_use]
extern crate log;

mod gamedata_io;

pub use gamedata_io::{ReadError, StringReadError};

use std::io::{self, Read, Write};
use std::path;

/// The data of a Game Maker Studio game.
///
/// This is the collective information acquired from "data.win".
pub struct GameData {
    metadata: MetaData,
    options: Options,
    extn: Extn,
    /// The sounds of the game.
    pub sounds: Sounds,
    audio_groups: Option<AudioGroups>,
    /// The sprites of the game.
    pub sprites: Sprites,
    backgrounds: Backgrounds,
    paths: Paths,
    scripts: Scripts,
    shaders: Shaders,
    /// The fonts of the game.
    pub fonts: Fonts,
    timelines: Timelines,
    objects: Objects,
    rooms: Rooms,
    dafl: Dafl,
    tpag: Tpag,
    code: Code,
    variables: Variables,
    functions: Functions,
    /// The strings of the game.
    pub strings: Strings,
    /// The texture data of the game.
    pub textures: Textures,
    audio: Audio,
}

/// A reader that satisfies the requirements for reading a GameData.
pub trait GameDataRead: Read + io::Seek {}
impl<T: Read + io::Seek> GameDataRead for T {}
/// A writer that satisfies the requirements for writing a GameData.
pub trait GameDataWrite: Write + io::Seek {}
impl<T: Write + io::Seek> GameDataWrite for T {}

impl GameData {
    /// Reads a GameData from a reader.
    pub fn from_reader<R: GameDataRead>(reader: &mut R) -> Result<GameData, ReadError> {
        gamedata_io::read(reader)
    }
    /// Reads a GameData from a file.
    pub fn from_file<P: AsRef<path::Path>>(path: P) -> Result<GameData, ReadError> {
        use std::fs::File;
        use std::io::BufReader;
        let file = try!(File::open(path));
        GameData::from_reader(&mut BufReader::new(file))
    }
    /// Writes self to a writer.
    pub fn write_to_writer<W: GameDataWrite>(&self, writer: &mut W) -> io::Result<()> {
        gamedata_io::write(self, writer)
    }
    /// Writes self to a file.
    pub fn save_to_file<P: AsRef<path::Path>>(&self, path: P) -> io::Result<()> {
        use std::fs::File;
        use std::io::BufWriter;
        let file = try!(File::create(path));
        self.write_to_writer(&mut BufWriter::new(file))
    }
    /// Returns the window width of the game.
    pub fn window_width(&self) -> u32 {
        self.metadata.window_width
    }
    /// Returns the window height of the game.
    pub fn window_height(&self) -> u32 {
        self.metadata.window_height
    }
    /// Sets the window dimensions of the game.
    pub fn set_window_dimensions(&mut self, width: u32, height: u32) {
        self.metadata.window_width = width;
        self.metadata.window_height = height;
    }
    /// Returns the window title of the game.
    pub fn window_title(&self) -> &str {
        &self.strings.strings[self.metadata.window_title_index]
    }
    /// Sets the window title of the game.
    pub fn set_window_title<S: Into<String>>(&mut self, new: S) {
        self.strings.strings[self.metadata.window_title_index] = new.into();
    }
}

/// Contains various metadata, for example, the window width/height/title.
pub struct MetaData {
    unk1: u32, // Purpose unknown
    game_id_1_index: usize, // Some kind of game id
    default_index: usize, // Points to "Default"
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    game_id_2_index: usize, // Some kind of game id, identical to game_id_1
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    window_width: u32,
    window_height: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    unk16: u32,
    unk17: u32,
    unk18: u32,
    unk19: u32,
    unk20: u32,
    window_title_index: usize,
    unknown: Vec<u32>,
}

/// Game Maker project Options
pub struct Options {
    unk1: u32, // Unknown
    unk2: u32, // Unknown
    icon_offset: u32, // Points to texture data (icon?)
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    constant1_name_index: usize, // Offset of the name of this constant in the string table
    constant2_name_index: usize, // Offset of the name of this constant in the string table
    constant3_name_index: usize, // Offset of the name of this constant in the string table
    constant4_name_index: usize, // Offset of the name of this constant in the string table
    constant5_name_index: usize, // Offset of the name of this constant in the string table
    constant6_name_index: usize, // Offset of the name of this constant in the string table
    constant7_name_index: usize, // Offset of the name of this constant in the string table
    constant8_name_index: usize, // Offset of the name of this constant in the string table
    constant9_name_index: usize, // Offset of the name of this constant in the string table
    constant10_name_index: usize, // Offset of the name of this constant in the string table
    constant11_name_index: usize, // Offset of the name of this constant in the string table
    constant12_name_index: usize, // Offset of the name of this constant in the string table
    constant13_name_index: usize, // Offset of the name of this constant in the string table
    constant14_name_index: usize, // Offset of the name of this constant in the string table
}

/// Purpose unknown.
pub struct Extn {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker sound.
#[derive(Clone, Copy)]
pub struct Sound {
    /// Index of the name in the string table.
    pub name_index: usize,
    unk1: u32,
    /// Index of the extension in the string table.
    pub ext_index: usize,
    /// Index of the filename in the string table.
    pub filename_index: usize,
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
}

/// A collection of sounds.
pub struct Sounds {
    /// The sounds.
    pub sounds: Vec<Sound>,
}

/// Collection of audio groups. Not present in all games.
pub struct AudioGroups {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker sprite.
#[derive(Clone)]
pub struct Sprite {
    /// The index of the resource name in the string table.
    pub name_index: usize,
    /// The width of the sprite
    pub width: u32,
    /// The height of the sprite
    pub height: u32,
    unknown: Vec<u8>,
}

/// A collection of sprites.
pub struct Sprites {
    /// The sprites
    pub sprites: Vec<Sprite>,
}

/// A collection of backgrounds.
pub struct Backgrounds {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of paths.
pub struct Paths {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker script.
pub struct Script {
    /// Index of the name of the script in the string table
    pub name_index: usize,
    unknown: u32, // Unknown
}

/// A collection of scripts.
pub struct Scripts {
    /// The scripts.
    pub scripts: Vec<Script>,
}

/// A collection of shaders.
pub struct Shaders {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A font.
#[derive(Clone)]
pub struct Font {
    /// Index of the font's resource name in the string table.
    pub name_index: usize,
    /// Index of the font's font name in the string table.
    pub font_name_index: usize,
    /// Point size of the font.
    pub point_size: u32,
    data: Vec<u8>,
}

/// A collection of fonts.
pub struct Fonts {
    /// The fonts.
    pub fonts: Vec<Font>,
    unknown: Vec<u8>, // Unknown trailing data
}

/// A collection of timelines.
pub struct Timelines {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of objects.
pub struct Objects {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of rooms.
pub struct Rooms {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
pub struct Dafl {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
pub struct Tpag {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Something to do with code. Maybe code of scripts?
pub struct Code {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker variable.
pub struct Variable {
    /// Index of the name of the variable in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section
}

/// A collection of variables.
pub struct Variables {
    /// The variables.
    pub variables: Vec<Variable>,
}

/// A game maker function.
pub struct Function {
    /// Index of the name of the function in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section.
}

/// A collection of functions.
pub struct Functions {
    /// The functions.
    pub functions: Vec<Function>,
}

/// A collection of strings.
///
/// All strings are assumed to be valid UTF-8.
pub struct Strings {
    /// The vector holding the strings.
    pub strings: Vec<String>,
}

/// A texture.
///
/// Currently only PNG textures are supported.
pub struct Texture {
    unknown: u32, // Purpose unknown. Always seems to be 1.
    /// The PNG data associated with this texture.
    pub png_data: Vec<u8>,
}

/// A collection of textures.
pub struct Textures {
    /// The textures.
    pub textures: Vec<Texture>,
}

/// Raw audio data.
pub struct AudioData {
    data: Vec<u8>,
}

/// A collection of audio data.
pub struct Audio {
    audio: Vec<AudioData>,
    offsets: Vec<u32>, // Audio data is not contiguous, so we need to store relative offsets
}
<commit_msg>Remove `associated_type_defaults` feature flag<commit_after>//! Library for manipulating Game Maker Studio's "data.win" (GEN8) data files.
//!
//! Typical usage consists of reading [GameData](struct.GameData.html) from a file, doing stuff with it,
//! then writing it back to a file.
//!
//! Example:
//!
//! ```no_run
//! let mut game_data = rgmk::GameData::from_file("data.win").expect("Failed to open data.win");
//! game_data.strings.strings[0] = "NYEH HEH HEH!".into();
//! game_data.save_to_file("data.win").expect("Failed to save data.win");
//! ```
//!

#![feature(read_exact, associated_consts)]
#![warn(missing_docs, trivial_casts, trivial_numeric_casts)]

#[macro_use]
extern crate quick_error;
extern crate byteorder;
#[macro_use]
extern crate log;

mod gamedata_io;

pub use gamedata_io::{ReadError, StringReadError};

use std::io::{self, Read, Write};
use std::path;

/// The data of a Game Maker Studio game.
///
/// This is the collective information acquired from "data.win".
pub struct GameData {
    metadata: MetaData,
    options: Options,
    extn: Extn,
    /// The sounds of the game.
    pub sounds: Sounds,
    audio_groups: Option<AudioGroups>,
    /// The sprites of the game.
    pub sprites: Sprites,
    backgrounds: Backgrounds,
    paths: Paths,
    scripts: Scripts,
    shaders: Shaders,
    /// The fonts of the game.
    pub fonts: Fonts,
    timelines: Timelines,
    objects: Objects,
    rooms: Rooms,
    dafl: Dafl,
    tpag: Tpag,
    code: Code,
    variables: Variables,
    functions: Functions,
    /// The strings of the game.
    pub strings: Strings,
    /// The texture data of the game.
    pub textures: Textures,
    audio: Audio,
}

/// A reader that satisfies the requirements for reading a GameData.
pub trait GameDataRead: Read + io::Seek {}
impl<T: Read + io::Seek> GameDataRead for T {}
/// A writer that satisfies the requirements for writing a GameData.
pub trait GameDataWrite: Write + io::Seek {}
impl<T: Write + io::Seek> GameDataWrite for T {}

impl GameData {
    /// Reads a GameData from a reader.
    pub fn from_reader<R: GameDataRead>(reader: &mut R) -> Result<GameData, ReadError> {
        gamedata_io::read(reader)
    }
    /// Reads a GameData from a file.
    pub fn from_file<P: AsRef<path::Path>>(path: P) -> Result<GameData, ReadError> {
        use std::fs::File;
        use std::io::BufReader;
        let file = try!(File::open(path));
        GameData::from_reader(&mut BufReader::new(file))
    }
    /// Writes self to a writer.
    pub fn write_to_writer<W: GameDataWrite>(&self, writer: &mut W) -> io::Result<()> {
        gamedata_io::write(self, writer)
    }
    /// Writes self to a file.
    pub fn save_to_file<P: AsRef<path::Path>>(&self, path: P) -> io::Result<()> {
        use std::fs::File;
        use std::io::BufWriter;
        let file = try!(File::create(path));
        self.write_to_writer(&mut BufWriter::new(file))
    }
    /// Returns the window width of the game.
    pub fn window_width(&self) -> u32 {
        self.metadata.window_width
    }
    /// Returns the window height of the game.
    pub fn window_height(&self) -> u32 {
        self.metadata.window_height
    }
    /// Sets the window dimensions of the game.
    pub fn set_window_dimensions(&mut self, width: u32, height: u32) {
        self.metadata.window_width = width;
        self.metadata.window_height = height;
    }
    /// Returns the window title of the game.
    pub fn window_title(&self) -> &str {
        &self.strings.strings[self.metadata.window_title_index]
    }
    /// Sets the window title of the game.
    pub fn set_window_title<S: Into<String>>(&mut self, new: S) {
        self.strings.strings[self.metadata.window_title_index] = new.into();
    }
}

/// Contains various metadata, for example, the window width/height/title.
pub struct MetaData {
    unk1: u32, // Purpose unknown
    game_id_1_index: usize, // Some kind of game id
    default_index: usize, // Points to "Default"
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    game_id_2_index: usize, // Some kind of game id, identical to game_id_1
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    window_width: u32,
    window_height: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    unk16: u32,
    unk17: u32,
    unk18: u32,
    unk19: u32,
    unk20: u32,
    window_title_index: usize,
    unknown: Vec<u32>,
}

/// Game Maker project Options
pub struct Options {
    unk1: u32, // Unknown
    unk2: u32, // Unknown
    icon_offset: u32, // Points to texture data (icon?)
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    constant1_name_index: usize, // Offset of the name of this constant in the string table
    constant2_name_index: usize, // Offset of the name of this constant in the string table
    constant3_name_index: usize, // Offset of the name of this constant in the string table
    constant4_name_index: usize, // Offset of the name of this constant in the string table
    constant5_name_index: usize, // Offset of the name of this constant in the string table
    constant6_name_index: usize, // Offset of the name of this constant in the string table
    constant7_name_index: usize, // Offset of the name of this constant in the string table
    constant8_name_index: usize, // Offset of the name of this constant in the string table
    constant9_name_index: usize, // Offset of the name of this constant in the string table
    constant10_name_index: usize, // Offset of the name of this constant in the string table
    constant11_name_index: usize, // Offset of the name of this constant in the string table
    constant12_name_index: usize, // Offset of the name of this constant in the string table
    constant13_name_index: usize, // Offset of the name of this constant in the string table
    constant14_name_index: usize, // Offset of the name of this constant in the string table
}

/// Purpose unknown.
pub struct Extn {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker sound.
#[derive(Clone, Copy)]
pub struct Sound {
    /// Index of the name in the string table.
    pub name_index: usize,
    unk1: u32,
    /// Index of the extension in the string table.
    pub ext_index: usize,
    /// Index of the filename in the string table.
    pub filename_index: usize,
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
}

/// A collection of sounds.
pub struct Sounds {
    /// The sounds.
    pub sounds: Vec<Sound>,
}

/// Collection of audio groups. Not present in all games.
pub struct AudioGroups {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker sprite.
#[derive(Clone)]
pub struct Sprite {
    /// The index of the resource name in the string table.
    pub name_index: usize,
    /// The width of the sprite
    pub width: u32,
    /// The height of the sprite
    pub height: u32,
    unknown: Vec<u8>,
}

/// A collection of sprites.
pub struct Sprites {
    /// The sprites
    pub sprites: Vec<Sprite>,
}

/// A collection of backgrounds.
pub struct Backgrounds {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of paths.
pub struct Paths {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker script.
pub struct Script {
    /// Index of the name of the script in the string table
    pub name_index: usize,
    unknown: u32, // Unknown
}

/// A collection of scripts.
pub struct Scripts {
    /// The scripts.
    pub scripts: Vec<Script>,
}

/// A collection of shaders.
pub struct Shaders {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A font.
#[derive(Clone)]
pub struct Font {
    /// Index of the font's resource name in the string table.
    pub name_index: usize,
    /// Index of the font's font name in the string table.
    pub font_name_index: usize,
    /// Point size of the font.
    pub point_size: u32,
    data: Vec<u8>,
}

/// A collection of fonts.
pub struct Fonts {
    /// The fonts.
    pub fonts: Vec<Font>,
    unknown: Vec<u8>, // Unknown trailing data
}

/// A collection of timelines.
pub struct Timelines {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of objects.
pub struct Objects {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of rooms.
pub struct Rooms {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
pub struct Dafl {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
pub struct Tpag {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Something to do with code. Maybe code of scripts?
pub struct Code {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker variable.
pub struct Variable {
    /// Index of the name of the variable in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section
}

/// A collection of variables.
pub struct Variables {
    /// The variables.
    pub variables: Vec<Variable>,
}

/// A game maker function.
pub struct Function {
    /// Index of the name of the function in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section.
}

/// A collection of functions.
pub struct Functions {
    /// The functions.
    pub functions: Vec<Function>,
}

/// A collection of strings.
///
/// All strings are assumed to be valid UTF-8.
pub struct Strings {
    /// The vector holding the strings.
    pub strings: Vec<String>,
}

/// A texture.
///
/// Currently only PNG textures are supported.
pub struct Texture {
    unknown: u32, // Purpose unknown. Always seems to be 1.
    /// The PNG data associated with this texture.
    pub png_data: Vec<u8>,
}

/// A collection of textures.
pub struct Textures {
    /// The textures.
    pub textures: Vec<Texture>,
}

/// Raw audio data.
pub struct AudioData {
    data: Vec<u8>,
}

/// A collection of audio data.
pub struct Audio {
    audio: Vec<AudioData>,
    offsets: Vec<u32>, // Audio data is not contiguous, so we need to store relative offsets
}
<|endoftext|>


<commit_before>#![feature(box_patterns)]
#![feature(futures_api)]
#![feature(async_await, await_macro)]
#![feature(try_blocks)]

#[macro_use]
extern crate error_chain;

#[cfg(feature = "sqlite")]
#[macro_use]
extern crate diesel;
#[cfg(feature = "sqlite")]
#[macro_use]
extern crate diesel_migrations;

use std::hash::{Hash, Hasher};

use chrono::prelude::*;
use chrono::Duration;
use derive_new::new;
use futures::prelude::*;

use crate::configuration::{Configuration, SchedulingStrategy};

pub use crate::errors::*;
pub use crate::scheduling::{Schedule, ScheduledTask};

#[macro_use]
mod util;

pub mod configuration;
pub mod database;
mod scheduling;

pub mod errors {
    use crate::scheduling;

    error_chain! {
        links {
            Schedule(scheduling::Error, scheduling::ErrorKind);
        }
        errors {
            Parse(what: String, how_it_should_be: String) {
                description("parse error")
                display("I could not parse the {}. {}", what, how_it_should_be)
            }
            Database(when: String) {
                description("database error")
                display("A database error occurred {}", when)
            }
            Internal(more_info: String) {
                description("internal error")
                display("An internal error occurred (This shouldn't happen.): {}", more_info)
            }
        }
    }
}

#[derive(Debug, new, Clone)]
pub struct NewTask {
    pub content: String,
    pub deadline: DateTime<Utc>,
    pub duration: Duration,
    pub importance: u32,
}

#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Task {
    pub id: u32,
    pub content: String,
    pub deadline: DateTime<Utc>,
    pub duration: Duration,
    pub importance: u32,
}

// Hack because chrono::Duration doesn't implement the Hash trait.
impl Hash for Task {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.id.hash(state);
        self.content.hash(state);
        self.deadline.hash(state);
        self.duration
            .to_std()
            .expect(&format!(
                "Internal error: duration of {} was negative",
                self
            ))
            .hash(state);
        self.importance.hash(state);
    }
}

pub fn add<'a: 'b, 'b>(
    configuration: &'a Configuration,
    new_task: NewTask,
) -> impl Future<Output = Result<Task>> + 'b {
    configuration.database.add_task(new_task)
}

pub fn remove<'a: 'b, 'b>(
    configuration: &'a Configuration,
    id: u32,
) -> impl Future<Output = Result<()>> + 'b {
    configuration.database.remove_task(id)
}

pub fn get<'a: 'b, 'b>(
    configuration: &'a Configuration,
    id: u32,
) -> impl Future<Output = Result<Task>> + 'b {
    configuration.database.find_task(id)
}

pub fn update<'a: 'b, 'b>(
    configuration: &'a Configuration,
    task: Task,
) -> impl Future<Output = Result<()>> + 'b {
    configuration.database.update_task(task)
}

pub fn all<'a: 'b, 'b>(
    configuration: &'a Configuration,
) -> impl Future<Output = Result<Vec<Task>>> + 'b {
    configuration.database.all_tasks()
}

pub fn schedule<'a: 'c, 'b: 'c, 'c>(
    configuration: &'a Configuration,
    strategy: &'b str,
) -> impl Future<Output = Result<Schedule>> + 'c {
    let strategy = match strategy {
        "importance" => SchedulingStrategy::Importance,
        "urgency" => SchedulingStrategy::Urgency,
        _ => panic!("Unsupported scheduling strategy provided"),
    };
    let start = configuration.now();

    configuration.database.all_tasks().and_then(move |tasks| {
        future::ready(Schedule::schedule(start, tasks, strategy)).map_err(Error::from)
    })
}
<commit_msg>Remove workaround because Duration impls Hash now<commit_after>#![feature(box_patterns)]
#![feature(futures_api)]
#![feature(async_await, await_macro)]
#![feature(try_blocks)]

#[macro_use]
extern crate error_chain;

#[cfg(feature = "sqlite")]
#[macro_use]
extern crate diesel;
#[cfg(feature = "sqlite")]
#[macro_use]
extern crate diesel_migrations;

use chrono::prelude::*;
use chrono::Duration;
use derive_new::new;
use futures::prelude::*;

use crate::configuration::{Configuration, SchedulingStrategy};

pub use crate::errors::*;
pub use crate::scheduling::{Schedule, ScheduledTask};

#[macro_use]
mod util;

pub mod configuration;
pub mod database;
mod scheduling;

pub mod errors {
    use crate::scheduling;

    error_chain! {
        links {
            Schedule(scheduling::Error, scheduling::ErrorKind);
        }
        errors {
            Parse(what: String, how_it_should_be: String) {
                description("parse error")
                display("I could not parse the {}. {}", what, how_it_should_be)
            }
            Database(when: String) {
                description("database error")
                display("A database error occurred {}", when)
            }
            Internal(more_info: String) {
                description("internal error")
                display("An internal error occurred (This shouldn't happen.): {}", more_info)
            }
        }
    }
}

#[derive(Debug, new, Clone)]
pub struct NewTask {
    pub content: String,
    pub deadline: DateTime<Utc>,
    pub duration: Duration,
    pub importance: u32,
}

#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct Task {
    pub id: u32,
    pub content: String,
    pub deadline: DateTime<Utc>,
    pub duration: Duration,
    pub importance: u32,
}

pub fn add<'a: 'b, 'b>(
    configuration: &'a Configuration,
    new_task: NewTask,
) -> impl Future<Output = Result<Task>> + 'b {
    configuration.database.add_task(new_task)
}

pub fn remove<'a: 'b, 'b>(
    configuration: &'a Configuration,
    id: u32,
) -> impl Future<Output = Result<()>> + 'b {
    configuration.database.remove_task(id)
}

pub fn get<'a: 'b, 'b>(
    configuration: &'a Configuration,
    id: u32,
) -> impl Future<Output = Result<Task>> + 'b {
    configuration.database.find_task(id)
}

pub fn update<'a: 'b, 'b>(
    configuration: &'a Configuration,
    task: Task,
) -> impl Future<Output = Result<()>> + 'b {
    configuration.database.update_task(task)
}

pub fn all<'a: 'b, 'b>(
    configuration: &'a Configuration,
) -> impl Future<Output = Result<Vec<Task>>> + 'b {
    configuration.database.all_tasks()
}

pub fn schedule<'a: 'c, 'b: 'c, 'c>(
    configuration: &'a Configuration,
    strategy: &'b str,
) -> impl Future<Output = Result<Schedule>> + 'c {
    let strategy = match strategy {
        "importance" => SchedulingStrategy::Importance,
        "urgency" => SchedulingStrategy::Urgency,
        _ => panic!("Unsupported scheduling strategy provided"),
    };
    let start = configuration.now();

    configuration.database.all_tasks().and_then(move |tasks| {
        future::ready(Schedule::schedule(start, tasks, strategy)).map_err(Error::from)
    })
}
<|endoftext|>


<commit_before>//
// nfa.rs
// Nondeterministic Finite Automata
//

type StateID = usize;

struct State {
    id: StateID,
    trans: Vec<Transition>
}

impl State {
    // finds the outgoing transitions for a given label
    pub fn find_transition(&self, label: Label) -> Vec<&Transition> {
        let mut res : Vec<&Transition> = Vec::new();
        for t in self.trans.iter() {
            if t.label == label {
                res.push(&t);
            }
        }

        res
    }
}

#[derive(PartialEq, Eq, Debug)]
enum Label {
    Epsilon,
    Any,
    Symbol(char)
}

struct Transition {
    label: Label,
    target: StateID
}

#[test]
fn states() {
    let mut ns = NFABuilder::new();
    let id1 = ns.new_state();
    let id2 = ns.new_state();
    assert_eq!(id1, 0);
    assert_eq!(id2, 1);

    assert!(ns.check_id(id1));
    assert!(ns.check_id(id2));
    assert!(!ns.check_id(100));
}

#[test]
fn add_transition() {
    let mut ns = NFABuilder::new();
    let id1 = ns.new_state();
    let id2 = ns.new_state();
    let id3 = ns.new_state();
    assert!(ns.add_transition(id1, id2, Label::Epsilon));
    assert!(ns.add_transition(id2, id3, Label::Symbol('a')));

    assert!(!ns.add_transition(id1, 1200, Label::Epsilon));
    assert!(!ns.add_transition(1020, id2, Label::Epsilon));
    assert!(!ns.add_transition(1320, 1200, Label::Epsilon));
}

#[test]
fn transitions() {
    let mut ns = NFABuilder::new();
    let id1 = ns.new_state();
    let id2 = ns.new_state();
    let id3 = ns.new_state();
    assert!(ns.add_transition(id1, id2, Label::Epsilon));
    assert!(ns.add_transition(id1, id3, Label::Epsilon));
    assert!(ns.add_transition(id2, id3, Label::Symbol('a')));

    let st1 = ns.get_state(id1).unwrap();
    let t0 = st1.find_transition(Label::Symbol('b'));
    assert_eq!(t0.len(), 0);
    let t1 = st1.find_transition(Label::Epsilon);
    assert_eq!(t1.len(), 2);

    let st2 = ns.get_state(t1[0].target).unwrap();
    let t2 = st2.find_transition(Label::Symbol('a'));
    assert_eq!(t2.len(), 1);

    assert_eq!(t2[0].target, id3);
    assert_eq!(t1[1].target, id3);
}

struct NFA {
    start: StateID,
    accept: StateID,
    states: Vec<State>
}

impl NFA {
    pub fn get_state(&self, sid: StateID) -> Option<&State> {
        self.states.get(sid)
    }

    fn epsilon_closure(&self, states: Vec<StateID>) -> Vec<StateID> {
        let mut stack : Vec<StateID> = Vec::with_capacity(states.len());

        stack.extend(states.clone());

        while !stack.is_empty() {
            let s = stack.pop().unwrap();
            let st = self.get_state(s).unwrap();
            let ets = st.find_transition(Label::Epsilon);
        }

        states
    }

    pub fn simulate(&self, word: &str) -> bool {
        false
    }
}

// specification for a NFA built by translation from a regexp
enum Spec {
    Single(Label),
    Union(Box<Spec>, Box<Spec>),
    Concat(Box<Spec>, Box<Spec>),
    Star(Box<Spec>)
}

impl Spec {
    // helper methods for building specs
    fn single(l: Label) -> Box<Spec> {
        Box::new(Spec::Single(l))
    }

    fn union(s1: Box<Spec>, s2: Box<Spec>) -> Box<Spec> {
        Box::new(Spec::Union(s1, s2))
    }

    fn concat(s1: Box<Spec>, s2: Box<Spec>) -> Box<Spec> {
        Box::new(Spec::Concat(s1, s2))
    }

    fn star(s: Box<Spec>) -> Box<Spec> {
        Box::new(Spec::Star(s))
    }
}

struct NFAid {
    start: StateID,
    accept: StateID
}

struct NFABuilder {
    states: Vec<State>
}

impl NFABuilder {
    fn new() -> NFABuilder {
        let st : Vec<State> = Vec::with_capacity(10);
        NFABuilder { states: st }
    }

    pub fn build_from_spec(s: Spec) -> NFA {
        let st : Vec<State> = Vec::with_capacity(10);
        let mut builder = NFABuilder { states: st };

        let nid = builder.build(s);

        NFA { states: builder.states, start: nid.start, accept: nid.accept }
    }

    fn build(&mut self, s: Spec) -> NFAid {
        match s {
            Spec::Single(l) => self.single(l),
            Spec::Union(s1, s2) => {
                let n1 = self.build(*s1);
                let n2 = self.build(*s2);
                self.union(n1, n2)
            },
            Spec::Concat(s1, s2) => {
                let n1 = self.build(*s1);
                let n2 = self.build(*s2);
                self.concat(n1, n2)
            },
            Spec::Star(s) => {
                let n = self.build(*s);
                self.star(n)
            }
        }
    }

    fn new_state(&mut self) -> StateID {
        let res = self.states.len();
        let trs : Vec<Transition> = Vec::with_capacity(2);
        let st = State { id: res, trans: trs };

        self.states.push(st);
        res
    }

    pub fn check_id(&self, id: StateID) -> bool {
        id < self.states.len()
    }

    fn get_state_mut(&mut self, id: StateID) -> &mut State {
        // TODO: change to safe, checked access
        unsafe {
            let res : &mut State = self.states.get_unchecked_mut(id);
            res
        }
    }

    // TODO: check for deletion
    fn get_state(&self, id: StateID) -> Option<&State> {
        self.states.get(id)
    }

    fn add_transition(&mut self, src_id: StateID, dst_id: StateID, label: Label) -> bool {
        if self.check_id(src_id) && self.check_id(dst_id) {
            let src_st = self.get_state_mut(src_id);
            let trans = Transition { label: label, target: dst_id };
            src_st.trans.push(trans);
            true
        }
        else {
            false
        }
    }

    fn single(&mut self, l: Label) -> NFAid {
        let st = self.new_state();
        let acc = self.new_state();

        self.add_transition(st, acc, l);

        NFAid { start: st, accept: acc }
    }

    fn union(&mut self, n1: NFAid, n2: NFAid) -> NFAid {
        let start = self.new_state();
        self.add_transition(start, n1.start, Label::Epsilon);
        self.add_transition(start, n2.start, Label::Epsilon);

        let acc = self.new_state();
        self.add_transition(n1.accept, acc, Label::Epsilon);
        self.add_transition(n2.accept, acc, Label::Epsilon);

        NFAid { start: start, accept: acc }
    }

    fn concat(&mut self, n1: NFAid, n2: NFAid) -> NFAid {
        self.add_transition(n1.accept, n2.start, Label::Epsilon);
        NFAid { start: n1.start, accept: n2.accept }
    }

    fn star(&mut self, n: NFAid) -> NFAid {
        let start = self.new_state();
        let acc = self.new_state();

        // transitions connecting old and new start/accept states
        self.add_transition(start, n.start, Label::Epsilon);
        self.add_transition(n.accept, acc, Label::Epsilon);

        // transition connecting start and accept for 0 occurrences
        self.add_transition(start, acc, Label::Epsilon);

        // loop transition for any number of occurrences
        self.add_transition(n.accept, n.start, Label::Epsilon);

        NFAid { start: start, accept: acc }
    }

}

#[test]
fn test_single() {
    let n1 = NFABuilder::build_from_spec(Spec::Single(Label::Epsilon));

    let s0 = n1.get_state(n1.start).unwrap();
    assert_eq!(s0.trans.len(), 1);
    assert_eq!(s0.trans[0].label, Label::Epsilon);

    let ts = s0.find_transition(Label::Epsilon);
    assert_eq!(ts.len(), 1);
    assert_eq!(ts[0].target, n1.accept);

    let s1 = n1.get_state(ts[0].target).unwrap();
    assert_eq!(s1.trans.len(), 0);
    let t1 = s1.find_transition(Label::Epsilon);
    assert_eq!(t1.len(), 0);
}

#[test]
fn test_union() {
    use nfa::Label::{Epsilon, Any};

    let spec = Spec::union(Spec::single(Epsilon), Spec::single(Any));
    let nfa = NFABuilder::build_from_spec(*spec);

    let s0 = nfa.get_state(nfa.start).unwrap();
    assert_eq!(s0.trans.len(), 2);
    assert_eq!(s0.trans[0].label, Epsilon);
    assert_eq!(s0.trans[1].label, Epsilon);

    let t0 = s0.find_transition(Epsilon);
    assert_eq!(t0.len(), 2);

    let s1 = nfa.get_state(t0[0].target).unwrap();
    assert_eq!(s1.trans.len(), 1);
    let s2 = nfa.get_state(t0[1].target).unwrap();
    assert_eq!(s2.trans.len(), 1);

    let s3 = nfa.get_state(s1.trans[0].target).unwrap();
    assert_eq!(s3.trans.len(), 1);
    assert_eq!(s3.trans[0].label, Epsilon);
    let s4 = nfa.get_state(s2.trans[0].target).unwrap();
    assert_eq!(s4.trans.len(), 1);
    assert_eq!(s4.trans[0].label, Epsilon);

    assert_eq!(s3.trans[0].target, s4.trans[0].target);
    assert_eq!(s3.trans[0].target, nfa.accept);

    let acc = nfa.get_state(s4.trans[0].target).unwrap();
    assert_eq!(acc.trans.len(), 0);
}
<commit_msg>epsilon closure<commit_after>//
// nfa.rs
// Nondeterministic Finite Automata
//

type StateID = usize;

struct State {
    id: StateID,
    trans: Vec<Transition>
}

impl State {
    // finds the outgoing transitions for a given label
    pub fn find_transition(&self, label: Label) -> Vec<&Transition> {
        let mut res : Vec<&Transition> = Vec::new();
        for t in self.trans.iter() {
            if t.label == label {
                res.push(&t);
            }
        }

        res
    }
}

#[derive(PartialEq, Eq, Debug)]
enum Label {
    Epsilon,
    Any,
    Symbol(char)
}

struct Transition {
    label: Label,
    target: StateID
}

#[test]
fn states() {
    let mut ns = NFABuilder::new();
    let id1 = ns.new_state();
    let id2 = ns.new_state();
    assert_eq!(id1, 0);
    assert_eq!(id2, 1);

    assert!(ns.check_id(id1));
    assert!(ns.check_id(id2));
    assert!(!ns.check_id(100));
}

#[test]
fn add_transition() {
    let mut ns = NFABuilder::new();
    let id1 = ns.new_state();
    let id2 = ns.new_state();
    let id3 = ns.new_state();
    assert!(ns.add_transition(id1, id2, Label::Epsilon));
    assert!(ns.add_transition(id2, id3, Label::Symbol('a')));

    assert!(!ns.add_transition(id1, 1200, Label::Epsilon));
    assert!(!ns.add_transition(1020, id2, Label::Epsilon));
    assert!(!ns.add_transition(1320, 1200, Label::Epsilon));
}

#[test]
fn transitions() {
    let mut ns = NFABuilder::new();
    let id1 = ns.new_state();
    let id2 = ns.new_state();
    let id3 = ns.new_state();
    assert!(ns.add_transition(id1, id2, Label::Epsilon));
    assert!(ns.add_transition(id1, id3, Label::Epsilon));
    assert!(ns.add_transition(id2, id3, Label::Symbol('a')));

    let st1 = ns.get_state(id1).unwrap();
    let t0 = st1.find_transition(Label::Symbol('b'));
    assert_eq!(t0.len(), 0);
    let t1 = st1.find_transition(Label::Epsilon);
    assert_eq!(t1.len(), 2);

    let st2 = ns.get_state(t1[0].target).unwrap();
    let t2 = st2.find_transition(Label::Symbol('a'));
    assert_eq!(t2.len(), 1);

    assert_eq!(t2[0].target, id3);
    assert_eq!(t1[1].target, id3);
}

struct NFA {
    start: StateID,
    accept: StateID,
    states: Vec<State>
}

impl NFA {
    pub fn get_state(&self, sid: StateID) -> Option<&State> {
        self.states.get(sid)
    }

    fn epsilon_closure(&self, states: Vec<StateID>) -> Vec<StateID> {
        let mut stack : Vec<StateID> = Vec::with_capacity(states.len());
        let mut clos : Vec<StateID> = Vec::with_capacity(states.len());

        stack.extend(states.clone());
        clos.extend(states.clone());

        while !stack.is_empty() {
            let s = stack.pop().unwrap();         // safe to unwrap because stack is not empty
            let st = self.get_state(s).unwrap();  // safe to unwrap because states on the stack must exist
            for t in st.find_transition(Label::Epsilon).iter() {
                if !clos.contains(&t.target) {
                    clos.push(t.target);
                    stack.push(t.target);
                }
            }
        }

        clos
    }

    pub fn simulate(&self, word: &str) -> bool {
        false
    }
}

// specification for a NFA built by translation from a regexp
enum Spec {
    Single(Label),
    Union(Box<Spec>, Box<Spec>),
    Concat(Box<Spec>, Box<Spec>),
    Star(Box<Spec>)
}

impl Spec {
    // helper methods for building specs
    fn single(l: Label) -> Box<Spec> {
        Box::new(Spec::Single(l))
    }

    fn union(s1: Box<Spec>, s2: Box<Spec>) -> Box<Spec> {
        Box::new(Spec::Union(s1, s2))
    }

    fn concat(s1: Box<Spec>, s2: Box<Spec>) -> Box<Spec> {
        Box::new(Spec::Concat(s1, s2))
    }

    fn star(s: Box<Spec>) -> Box<Spec> {
        Box::new(Spec::Star(s))
    }
}

struct NFAid {
    start: StateID,
    accept: StateID
}

struct NFABuilder {
    states: Vec<State>
}

impl NFABuilder {
    fn new() -> NFABuilder {
        let st : Vec<State> = Vec::with_capacity(10);
        NFABuilder { states: st }
    }

    pub fn build_from_spec(s: Spec) -> NFA {
        let st : Vec<State> = Vec::with_capacity(10);
        let mut builder = NFABuilder { states: st };

        let nid = builder.build(s);

        NFA { states: builder.states, start: nid.start, accept: nid.accept }
    }

    fn build(&mut self, s: Spec) -> NFAid {
        match s {
            Spec::Single(l) => self.single(l),
            Spec::Union(s1, s2) => {
                let n1 = self.build(*s1);
                let n2 = self.build(*s2);
                self.union(n1, n2)
            },
            Spec::Concat(s1, s2) => {
                let n1 = self.build(*s1);
                let n2 = self.build(*s2);
                self.concat(n1, n2)
            },
            Spec::Star(s) => {
                let n = self.build(*s);
                self.star(n)
            }
        }
    }

    fn new_state(&mut self) -> StateID {
        let res = self.states.len();
        let trs : Vec<Transition> = Vec::with_capacity(2);
        let st = State { id: res, trans: trs };

        self.states.push(st);
        res
    }

    pub fn check_id(&self, id: StateID) -> bool {
        id < self.states.len()
    }

    fn get_state_mut(&mut self, id: StateID) -> &mut State {
        // TODO: change to safe, checked access
        unsafe {
            let res : &mut State = self.states.get_unchecked_mut(id);
            res
        }
    }

    // TODO: check for deletion
    fn get_state(&self, id: StateID) -> Option<&State> {
        self.states.get(id)
    }

    fn add_transition(&mut self, src_id: StateID, dst_id: StateID, label: Label) -> bool {
        if self.check_id(src_id) && self.check_id(dst_id) {
            let src_st = self.get_state_mut(src_id);
            let trans = Transition { label: label, target: dst_id };
            src_st.trans.push(trans);
            true
        }
        else {
            false
        }
    }

    fn single(&mut self, l: Label) -> NFAid {
        let st = self.new_state();
        let acc = self.new_state();

        self.add_transition(st, acc, l);

        NFAid { start: st, accept: acc }
    }

    fn union(&mut self, n1: NFAid, n2: NFAid) -> NFAid {
        let start = self.new_state();
        self.add_transition(start, n1.start, Label::Epsilon);
        self.add_transition(start, n2.start, Label::Epsilon);

        let acc = self.new_state();
        self.add_transition(n1.accept, acc, Label::Epsilon);
        self.add_transition(n2.accept, acc, Label::Epsilon);

        NFAid { start: start, accept: acc }
    }

    fn concat(&mut self, n1: NFAid, n2: NFAid) -> NFAid {
        self.add_transition(n1.accept, n2.start, Label::Epsilon);
        NFAid { start: n1.start, accept: n2.accept }
    }

    fn star(&mut self, n: NFAid) -> NFAid {
        let start = self.new_state();
        let acc = self.new_state();

        // transitions connecting old and new start/accept states
        self.add_transition(start, n.start, Label::Epsilon);
        self.add_transition(n.accept, acc, Label::Epsilon);

        // transition connecting start and accept for 0 occurrences
        self.add_transition(start, acc, Label::Epsilon);

        // loop transition for any number of occurrences
        self.add_transition(n.accept, n.start, Label::Epsilon);

        NFAid { start: start, accept: acc }
    }

}

#[test]
fn test_single() {
    let n1 = NFABuilder::build_from_spec(Spec::Single(Label::Epsilon));

    let s0 = n1.get_state(n1.start).unwrap();
    assert_eq!(s0.trans.len(), 1);
    assert_eq!(s0.trans[0].label, Label::Epsilon);

    let ts = s0.find_transition(Label::Epsilon);
    assert_eq!(ts.len(), 1);
    assert_eq!(ts[0].target, n1.accept);

    let s1 = n1.get_state(ts[0].target).unwrap();
    assert_eq!(s1.trans.len(), 0);
    let t1 = s1.find_transition(Label::Epsilon);
    assert_eq!(t1.len(), 0);
}

#[test]
fn test_union() {
    use nfa::Label::{Epsilon, Any};

    let spec = Spec::union(Spec::single(Epsilon), Spec::single(Any));
    let nfa = NFABuilder::build_from_spec(*spec);

    let s0 = nfa.get_state(nfa.start).unwrap();
    assert_eq!(s0.trans.len(), 2);
    assert_eq!(s0.trans[0].label, Epsilon);
    assert_eq!(s0.trans[1].label, Epsilon);

    let t0 = s0.find_transition(Epsilon);
    assert_eq!(t0.len(), 2);

    let s1 = nfa.get_state(t0[0].target).unwrap();
    assert_eq!(s1.trans.len(), 1);
    let s2 = nfa.get_state(t0[1].target).unwrap();
    assert_eq!(s2.trans.len(), 1);

    let s3 = nfa.get_state(s1.trans[0].target).unwrap();
    assert_eq!(s3.trans.len(), 1);
    assert_eq!(s3.trans[0].label, Epsilon);
    let s4 = nfa.get_state(s2.trans[0].target).unwrap();
    assert_eq!(s4.trans.len(), 1);
    assert_eq!(s4.trans[0].label, Epsilon);

    assert_eq!(s3.trans[0].target, s4.trans[0].target);
    assert_eq!(s3.trans[0].target, nfa.accept);

    let acc = nfa.get_state(s4.trans[0].target).unwrap();
    assert_eq!(acc.trans.len(), 0);
}

#[test]
fn test_eps_clos() {
    use nfa::Label::{Epsilon,Any};

    let n1 = NFABuilder::build_from_spec(Spec::Single(Any));
    let cls1 = n1.epsilon_closure(vec![n1.start]);
    assert_eq!(cls1.len(), 1);
    assert_eq!(cls1[0], n1.start);

    let n2 = NFABuilder::build_from_spec(Spec::Single(Epsilon));
    let cls2 = n2.epsilon_closure(vec![n2.start]);
    assert_eq!(cls2.len(), 2);
    assert_eq!(cls2[0], n1.start);
    assert_eq!(cls2[1], n1.accept);
}
<|endoftext|>


<commit_before>#![feature(rustc_private, i128_type)]
extern crate miri;
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate syntax;

use std::path::{PathBuf, Path};
use std::io::Write;
use std::sync::{Mutex, Arc};
use std::io;

use rustc::session::Session;
use rustc::middle::cstore::CrateStore;
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_driver::driver::{CompileState, CompileController};
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use syntax::ast;

struct MiriCompilerCalls {
    default: RustcDefaultCalls,
    /// whether we are building for the host
    host_target: bool,
}

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType
    ) -> Compilation {
        self.default.early_callback(matches, sopts, cfg, descriptions, output)
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions)
    }
    fn late_callback(
        &mut self,
        matches: &getopts::Matches,
        sess: &Session,
        cstore: &CrateStore,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>
    ) -> Compilation {
        self.default.late_callback(matches, sess, cstore, input, odir, ofile)
    }
    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> {
        let mut control = self.default.build_controller(sess, matches);
        control.after_hir_lowering.callback = Box::new(after_hir_lowering);
        control.after_analysis.callback = Box::new(after_analysis);
        if !self.host_target {
            // only fully compile targets on the host
            control.after_analysis.stop = Compilation::Stop;
        }
        control
    }
}

fn after_hir_lowering(state: &mut CompileState) {
    let attr = (String::from("miri"), syntax::feature_gate::AttributeType::Whitelisted);
    state.session.plugin_attributes.borrow_mut().push(attr);
}

fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
    state.session.abort_if_errors();

    let tcx = state.tcx.unwrap();
    let limits = Default::default();

    if std::env::args().any(|arg| arg == "--test") {
        struct Visitor<'a, 'tcx: 'a>(miri::ResourceLimits, TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>);
        impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
            fn visit_item(&mut self, i: &'hir hir::Item) {
                if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node {
                    if i.attrs.iter().any(|attr| attr.name().map_or(false, |n| n == "test")) {
                        let did = self.1.hir.body_owner_def_id(body_id);
                        println!("running test: {}", self.1.hir.def_path(did).to_string(self.1));
                        miri::eval_main(self.1, did, None, self.0);
                        self.2.session.abort_if_errors();
                    }
                }
            }
            fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
            fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
        }
        state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(limits, tcx, state));
    } else if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() {
        let entry_def_id = tcx.hir.local_def_id(entry_node_id);
        let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn|
                                if tcx.is_mir_available(start_fn) { Some(start_fn) } else { None });
        miri::eval_main(tcx, entry_def_id, start_wrapper, limits);

        state.session.abort_if_errors();
    } else {
        println!("no main function found, assuming auxiliary build");
    }
}

fn main() {
    let path = option_env!("MIRI_RUSTC_TEST")
        .map(String::from)
        .unwrap_or_else(|| {
            std::env::var("MIRI_RUSTC_TEST")
                .expect("need to set MIRI_RUSTC_TEST to path of rustc tests")
        });

    let mut mir_not_found = Vec::new();
    let mut crate_not_found = Vec::new();
    let mut success = 0;
    let mut failed = Vec::new();
    let mut c_abi_fns = Vec::new();
    let mut abi = Vec::new();
    let mut unsupported = Vec::new();
    let mut unimplemented_intrinsic = Vec::new();
    let mut limits = Vec::new();
    let mut files: Vec<_> = std::fs::read_dir(path).unwrap().collect();
    while let Some(file) = files.pop() {
        let file = file.unwrap();
        let path = file.path();
        if file.metadata().unwrap().is_dir() {
            if !path.to_str().unwrap().ends_with("auxiliary") {
                // add subdirs recursively
                files.extend(std::fs::read_dir(path).unwrap());
            }
            continue;
        }
        if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") {
            continue;
        }
        let stderr = std::io::stderr();
        write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap();
        let mut host_target = false;
        let mut args: Vec<String> = std::env::args().filter(|arg| {
            if arg == "--miri_host_target" {
                host_target = true;
                false // remove the flag, rustc doesn't know it
            } else {
                true
            }
        }).collect();
        // file to process
        args.push(path.display().to_string());

        let sysroot_flag = String::from("--sysroot");
        if !args.contains(&sysroot_flag) {
            args.push(sysroot_flag);
            args.push(Path::new(&std::env::var("HOME").unwrap()).join(".xargo").join("HOST").display().to_string());
        }

        args.push("-Zmir-opt-level=3".to_owned());
        // for auxilary builds in unit tests
        args.push("-Zalways-encode-mir".to_owned());

        // A threadsafe buffer for writing.
        #[derive(Default, Clone)]
        struct BufWriter(Arc<Mutex<Vec<u8>>>);

        impl Write for BufWriter {
            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
                self.0.lock().unwrap().write(buf)
            }
            fn flush(&mut self) -> io::Result<()> {
                self.0.lock().unwrap().flush()
            }
        }
        let buf = BufWriter::default();
        let output = buf.clone();
        let result = std::panic::catch_unwind(|| {
            rustc_driver::run_compiler(&args, &mut MiriCompilerCalls {
                default: RustcDefaultCalls,
                host_target,
            }, None, Some(Box::new(buf)));
        });

        match result {
            Ok(()) => {
                success += 1;
                writeln!(stderr.lock(), "ok").unwrap()
            },
            Err(_) => {
                let output = output.0.lock().unwrap();
                let output_err = std::str::from_utf8(&output).unwrap();
                if let Some(text) = output_err.splitn(2, "no mir for `").nth(1) {
                    let end = text.find('`').unwrap();
                    mir_not_found.push(text[..end].to_string());
                    writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap();
                } else if let Some(text) = output_err.splitn(2, "can't find crate for `").nth(1) {
                    let end = text.find('`').unwrap();
                    crate_not_found.push(text[..end].to_string());
                    writeln!(stderr.lock(), "CAN'T FIND CRATE FOR `{}`", &text[..end]).unwrap();
                } else {
                    for text in output_err.split("error: ").skip(1) {
                        let end = text.find('\n').unwrap_or(text.len());
                        let c_abi = "can't call C ABI function: ";
                        let unimplemented_intrinsic_s = "unimplemented intrinsic: ";
                        let unsupported_s = "miri does not support ";
                        let abi_s = "can't handle function with ";
                        let limit_s = "reached the configured maximum ";
                        if text.starts_with(c_abi) {
                            c_abi_fns.push(text[c_abi.len()..end].to_string());
                        } else if text.starts_with(unimplemented_intrinsic_s) {
                            unimplemented_intrinsic.push(text[unimplemented_intrinsic_s.len()..end].to_string());
                        } else if text.starts_with(unsupported_s) {
                            unsupported.push(text[unsupported_s.len()..end].to_string());
                        } else if text.starts_with(abi_s) {
                            abi.push(text[abi_s.len()..end].to_string());
                        } else if text.starts_with(limit_s) {
                            limits.push(text[limit_s.len()..end].to_string());
                        } else if text.find("aborting").is_none() {
                            failed.push(text[..end].to_string());
                        }
                    }
                    writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap();
                }
            }
        }
    }
    let stderr = std::io::stderr();
    let mut stderr = stderr.lock();
    writeln!(stderr, "{} success, {} no mir, {} crate not found, {} failed, \
                        {} C fn, {} ABI, {} unsupported, {} intrinsic",
                        success, mir_not_found.len(), crate_not_found.len(), failed.len(),
                        c_abi_fns.len(), abi.len(), unsupported.len(), unimplemented_intrinsic.len()).unwrap();
    writeln!(stderr, "# The \"other reasons\" errors").unwrap();
    writeln!(stderr, "(sorted, deduplicated)").unwrap();
    print_vec(&mut stderr, failed);

    writeln!(stderr, "# can't call C ABI function").unwrap();
    print_vec(&mut stderr, c_abi_fns);

    writeln!(stderr, "# unsupported ABI").unwrap();
    print_vec(&mut stderr, abi);

    writeln!(stderr, "# unsupported").unwrap();
    print_vec(&mut stderr, unsupported);

    writeln!(stderr, "# unimplemented intrinsics").unwrap();
    print_vec(&mut stderr, unimplemented_intrinsic);

    writeln!(stderr, "# mir not found").unwrap();
    print_vec(&mut stderr, mir_not_found);

    writeln!(stderr, "# crate not found").unwrap();
    print_vec(&mut stderr, crate_not_found);
}

fn print_vec<W: std::io::Write>(stderr: &mut W, v: Vec<String>) {
    writeln!(stderr, "```").unwrap();
    for (n, s) in vec_to_hist(v).into_iter().rev() {
        writeln!(stderr, "{:4} {}", n, s).unwrap();
    }
    writeln!(stderr, "```").unwrap();
}

fn vec_to_hist<T: PartialEq + Ord>(mut v: Vec<T>) -> Vec<(usize, T)> {
    v.sort();
    let mut v = v.into_iter();
    let mut result = Vec::new();
    let mut current = v.next();
    'outer: while let Some(current_val) = current {
        let mut n = 1;
        for next in &mut v {
            if next == current_val {
                n += 1;
            } else {
                result.push((n, current_val));
                current = Some(next);
                continue 'outer;
            }
        }
        result.push((n, current_val));
        break;
    }
    result.sort();
    result
}
<commit_msg>Also update rustc_tests to unrelated rustc changes<commit_after>#![feature(rustc_private, i128_type)]
extern crate miri;
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate syntax;

use std::path::{PathBuf, Path};
use std::io::Write;
use std::sync::{Mutex, Arc};
use std::io;

use rustc::session::Session;
use rustc::middle::cstore::CrateStore;
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_driver::driver::{CompileState, CompileController};
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use syntax::ast;

struct MiriCompilerCalls {
    default: RustcDefaultCalls,
    /// whether we are building for the host
    host_target: bool,
}

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType
    ) -> Compilation {
        self.default.early_callback(matches, sopts, cfg, descriptions, output)
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions)
    }
    fn late_callback(
        &mut self,
        matches: &getopts::Matches,
        sess: &Session,
        cstore: &CrateStore,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>
    ) -> Compilation {
        self.default.late_callback(matches, sess, cstore, input, odir, ofile)
    }
    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> {
        let mut control = self.default.build_controller(sess, matches);
        control.after_hir_lowering.callback = Box::new(after_hir_lowering);
        control.after_analysis.callback = Box::new(after_analysis);
        if !self.host_target {
            // only fully compile targets on the host
            control.after_analysis.stop = Compilation::Stop;
        }
        control
    }
}

fn after_hir_lowering(state: &mut CompileState) {
    let attr = (String::from("miri"), syntax::feature_gate::AttributeType::Whitelisted);
    state.session.plugin_attributes.borrow_mut().push(attr);
}

fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
    state.session.abort_if_errors();

    let tcx = state.tcx.unwrap();
    let limits = Default::default();

    if std::env::args().any(|arg| arg == "--test") {
        struct Visitor<'a, 'tcx: 'a>(miri::ResourceLimits, TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>);
        impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
            fn visit_item(&mut self, i: &'hir hir::Item) {
                if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node {
                    if i.attrs.iter().any(|attr| attr.name().map_or(false, |n| n == "test")) {
                        let did = self.1.hir.body_owner_def_id(body_id);
                        println!("running test: {}", self.1.def_path_debug_str(did));
                        miri::eval_main(self.1, did, None, self.0);
                        self.2.session.abort_if_errors();
                    }
                }
            }
            fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
            fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
        }
        state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(limits, tcx, state));
    } else if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() {
        let entry_def_id = tcx.hir.local_def_id(entry_node_id);
        let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn|
                                if tcx.is_mir_available(start_fn) { Some(start_fn) } else { None });
        miri::eval_main(tcx, entry_def_id, start_wrapper, limits);

        state.session.abort_if_errors();
    } else {
        println!("no main function found, assuming auxiliary build");
    }
}

fn main() {
    let path = option_env!("MIRI_RUSTC_TEST")
        .map(String::from)
        .unwrap_or_else(|| {
            std::env::var("MIRI_RUSTC_TEST")
                .expect("need to set MIRI_RUSTC_TEST to path of rustc tests")
        });

    let mut mir_not_found = Vec::new();
    let mut crate_not_found = Vec::new();
    let mut success = 0;
    let mut failed = Vec::new();
    let mut c_abi_fns = Vec::new();
    let mut abi = Vec::new();
    let mut unsupported = Vec::new();
    let mut unimplemented_intrinsic = Vec::new();
    let mut limits = Vec::new();
    let mut files: Vec<_> = std::fs::read_dir(path).unwrap().collect();
    while let Some(file) = files.pop() {
        let file = file.unwrap();
        let path = file.path();
        if file.metadata().unwrap().is_dir() {
            if !path.to_str().unwrap().ends_with("auxiliary") {
                // add subdirs recursively
                files.extend(std::fs::read_dir(path).unwrap());
            }
            continue;
        }
        if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") {
            continue;
        }
        let stderr = std::io::stderr();
        write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap();
        let mut host_target = false;
        let mut args: Vec<String> = std::env::args().filter(|arg| {
            if arg == "--miri_host_target" {
                host_target = true;
                false // remove the flag, rustc doesn't know it
            } else {
                true
            }
        }).collect();
        // file to process
        args.push(path.display().to_string());

        let sysroot_flag = String::from("--sysroot");
        if !args.contains(&sysroot_flag) {
            args.push(sysroot_flag);
            args.push(Path::new(&std::env::var("HOME").unwrap()).join(".xargo").join("HOST").display().to_string());
        }

        args.push("-Zmir-opt-level=3".to_owned());
        // for auxilary builds in unit tests
        args.push("-Zalways-encode-mir".to_owned());

        // A threadsafe buffer for writing.
        #[derive(Default, Clone)]
        struct BufWriter(Arc<Mutex<Vec<u8>>>);

        impl Write for BufWriter {
            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
                self.0.lock().unwrap().write(buf)
            }
            fn flush(&mut self) -> io::Result<()> {
                self.0.lock().unwrap().flush()
            }
        }
        let buf = BufWriter::default();
        let output = buf.clone();
        let result = std::panic::catch_unwind(|| {
            rustc_driver::run_compiler(&args, &mut MiriCompilerCalls {
                default: RustcDefaultCalls,
                host_target,
            }, None, Some(Box::new(buf)));
        });

        match result {
            Ok(()) => {
                success += 1;
                writeln!(stderr.lock(), "ok").unwrap()
            },
            Err(_) => {
                let output = output.0.lock().unwrap();
                let output_err = std::str::from_utf8(&output).unwrap();
                if let Some(text) = output_err.splitn(2, "no mir for `").nth(1) {
                    let end = text.find('`').unwrap();
                    mir_not_found.push(text[..end].to_string());
                    writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap();
                } else if let Some(text) = output_err.splitn(2, "can't find crate for `").nth(1) {
                    let end = text.find('`').unwrap();
                    crate_not_found.push(text[..end].to_string());
                    writeln!(stderr.lock(), "CAN'T FIND CRATE FOR `{}`", &text[..end]).unwrap();
                } else {
                    for text in output_err.split("error: ").skip(1) {
                        let end = text.find('\n').unwrap_or(text.len());
                        let c_abi = "can't call C ABI function: ";
                        let unimplemented_intrinsic_s = "unimplemented intrinsic: ";
                        let unsupported_s = "miri does not support ";
                        let abi_s = "can't handle function with ";
                        let limit_s = "reached the configured maximum ";
                        if text.starts_with(c_abi) {
                            c_abi_fns.push(text[c_abi.len()..end].to_string());
                        } else if text.starts_with(unimplemented_intrinsic_s) {
                            unimplemented_intrinsic.push(text[unimplemented_intrinsic_s.len()..end].to_string());
                        } else if text.starts_with(unsupported_s) {
                            unsupported.push(text[unsupported_s.len()..end].to_string());
                        } else if text.starts_with(abi_s) {
                            abi.push(text[abi_s.len()..end].to_string());
                        } else if text.starts_with(limit_s) {
                            limits.push(text[limit_s.len()..end].to_string());
                        } else if text.find("aborting").is_none() {
                            failed.push(text[..end].to_string());
                        }
                    }
                    writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap();
                }
            }
        }
    }
    let stderr = std::io::stderr();
    let mut stderr = stderr.lock();
    writeln!(stderr, "{} success, {} no mir, {} crate not found, {} failed, \
                        {} C fn, {} ABI, {} unsupported, {} intrinsic",
                        success, mir_not_found.len(), crate_not_found.len(), failed.len(),
                        c_abi_fns.len(), abi.len(), unsupported.len(), unimplemented_intrinsic.len()).unwrap();
    writeln!(stderr, "# The \"other reasons\" errors").unwrap();
    writeln!(stderr, "(sorted, deduplicated)").unwrap();
    print_vec(&mut stderr, failed);

    writeln!(stderr, "# can't call C ABI function").unwrap();
    print_vec(&mut stderr, c_abi_fns);

    writeln!(stderr, "# unsupported ABI").unwrap();
    print_vec(&mut stderr, abi);

    writeln!(stderr, "# unsupported").unwrap();
    print_vec(&mut stderr, unsupported);

    writeln!(stderr, "# unimplemented intrinsics").unwrap();
    print_vec(&mut stderr, unimplemented_intrinsic);

    writeln!(stderr, "# mir not found").unwrap();
    print_vec(&mut stderr, mir_not_found);

    writeln!(stderr, "# crate not found").unwrap();
    print_vec(&mut stderr, crate_not_found);
}

fn print_vec<W: std::io::Write>(stderr: &mut W, v: Vec<String>) {
    writeln!(stderr, "```").unwrap();
    for (n, s) in vec_to_hist(v).into_iter().rev() {
        writeln!(stderr, "{:4} {}", n, s).unwrap();
    }
    writeln!(stderr, "```").unwrap();
}

fn vec_to_hist<T: PartialEq + Ord>(mut v: Vec<T>) -> Vec<(usize, T)> {
    v.sort();
    let mut v = v.into_iter();
    let mut result = Vec::new();
    let mut current = v.next();
    'outer: while let Some(current_val) = current {
        let mut n = 1;
        for next in &mut v {
            if next == current_val {
                n += 1;
            } else {
                result.push((n, current_val));
                current = Some(next);
                continue 'outer;
            }
        }
        result.push((n, current_val));
        break;
    }
    result.sort();
    result
}
<|endoftext|>


<commit_before>use criterion::Bencher;
use diesel::*;

#[cfg(feature = "postgres")]
type TestConnection = PgConnection;

#[cfg(feature = "mysql")]
type TestConnection = MysqlConnection;

#[cfg(feature = "sqlite")]
type TestConnection = SqliteConnection;

table! {
    users {
        id -> Integer,
        name -> Text,
        hair_color -> Nullable<Text>,
    }
}

table! {
    posts {
        id -> Integer,
        user_id -> Integer,
        title -> Text,
        body -> Nullable<Text>,
    }
}

table! {
    comments {
        id -> Integer,
        post_id -> Integer,
        text -> Text,
    }
}

joinable!(comments -> posts (post_id));
joinable!(posts -> users (user_id));
allow_tables_to_appear_in_same_query!(users, posts, comments);

#[derive(
    PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Insertable, AsChangeset, QueryableByName,
)]
#[table_name = "users"]
pub struct User {
    pub id: i32,
    pub name: String,
    pub hair_color: Option<String>,
}

#[derive(Debug, PartialEq, Eq, Queryable, Clone, Insertable, AsChangeset)]
#[table_name = "users"]
pub struct NewUser {
    pub name: String,
    pub hair_color: Option<String>,
}

impl NewUser {
    pub fn new(name: &str, hair_color: Option<&str>) -> Self {
        NewUser {
            name: name.to_string(),
            hair_color: hair_color.map(|s| s.to_string()),
        }
    }
}

#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, QueryableByName)]
#[belongs_to(User)]
#[table_name = "posts"]
pub struct Post {
    pub id: i32,
    pub user_id: i32,
    pub title: String,
    pub body: Option<String>,
}

#[derive(Insertable)]
#[table_name = "posts"]
pub struct NewPost {
    user_id: i32,
    title: String,
    body: Option<String>,
}

impl NewPost {
    pub fn new(user_id: i32, title: &str, body: Option<&str>) -> Self {
        NewPost {
            user_id,
            title: title.into(),
            body: body.map(|b| b.into()),
        }
    }
}

#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
#[belongs_to(Post)]
pub struct Comment {
    id: i32,
    post_id: i32,
    text: String,
}

#[derive(Debug, Clone, Copy, Insertable)]
#[table_name = "comments"]
pub struct NewComment<'a>(
    #[column_name = "post_id"] pub i32,
    #[column_name = "text"] pub &'a str,
);

#[cfg(feature = "mysql")]
fn connection() -> TestConnection {
    dotenv::dotenv().ok();
    let connection_url = dotenv::var("MYSQL_DATABASE_URL")
        .or_else(|_| dotenv::var("DATABASE_URL"))
        .expect("DATABASE_URL must be set in order to run tests");
    let mut conn = MysqlConnection::establish(&connection_url).unwrap();
    conn.execute("SET FOREIGN_KEY_CHECKS = 0;").unwrap();
    conn.execute("TRUNCATE TABLE comments").unwrap();
    conn.execute("TRUNCATE TABLE posts").unwrap();
    conn.execute("TRUNCATE TABLE users").unwrap();
    conn.execute("SET FOREIGN_KEY_CHECKS = 1;").unwrap();
    conn
}

#[cfg(feature = "postgres")]
fn connection() -> TestConnection {
    dotenv::dotenv().ok();
    let connection_url = dotenv::var("PG_DATABASE_URL")
        .or_else(|_| dotenv::var("DATABASE_URL"))
        .expect("DATABASE_URL must be set in order to run tests");
    let mut conn = PgConnection::establish(&connection_url).unwrap();
    conn.execute("TRUNCATE TABLE comments CASCADE").unwrap();
    conn.execute("TRUNCATE TABLE posts CASCADE").unwrap();
    conn.execute("TRUNCATE TABLE users CASCADE").unwrap();
    conn
}

#[cfg(feature = "sqlite")]
fn connection() -> TestConnection {
    dotenv::dotenv().ok();
    let mut conn = diesel::SqliteConnection::establish(":memory:").unwrap();
    for migration in super::SQLITE_MIGRATION_SQL {
        conn.execute(migration).unwrap();
    }
    conn.execute("DELETE FROM comments").unwrap();
    conn.execute("DELETE FROM posts").unwrap();
    conn.execute("DELETE FROM users").unwrap();
    conn
}

fn insert_users(
    size: usize,
    conn: &mut TestConnection,
    hair_color_init: impl Fn(usize) -> Option<&'static str>,
) {
    let data: Vec<_> = (0..size)
        .map(|i| NewUser::new(&format!("User {}", i), hair_color_init(i)))
        .collect();
    insert_into(users::table)
        .values(&data)
        .execute(conn)
        .unwrap();
}

pub fn bench_trivial_query(b: &mut Bencher, size: usize) {
    let mut conn = connection();
    insert_users(size, &mut conn, |_| None);

    b.iter(|| users::table.load::<User>(&mut conn).unwrap())
}

pub fn bench_trivial_query_boxed(b: &mut Bencher, size: usize) {
    let mut conn = connection();

    insert_users(size, &mut conn, |_| None);
    b.iter(|| users::table.into_boxed().load::<User>(&mut conn).unwrap())
}

pub fn bench_trivial_query_raw(b: &mut Bencher, size: usize) {
    let mut conn = connection();
    insert_users(size, &mut conn, |_| None);

    b.iter(|| {
        diesel::sql_query("SELECT id, name, hair_color FROM users")
            .load::<User>(&mut conn)
            .unwrap()
    })
}

pub fn bench_medium_complex_query(b: &mut Bencher, size: usize) {
    let mut conn = connection();

    insert_users(size, &mut conn, |i| {
        Some(if i % 2 == 0 { "black" } else { "brown" })
    });

    b.iter(|| {
        use self::users::dsl::*;
        let target = users
            .left_outer_join(posts::table)
            .filter(hair_color.eq("black"))
            .order(name.desc());
        target.load::<(User, Option<Post>)>(&mut conn).unwrap()
    })
}

pub fn bench_medium_complex_query_boxed(b: &mut Bencher, size: usize) {
    let mut conn = connection();
    insert_users(size, &mut conn, |i| {
        Some(if i % 2 == 0 { "black" } else { "brown" })
    });

    b.iter(|| {
        use self::users::dsl::*;
        let target = users
            .left_outer_join(posts::table)
            .filter(hair_color.eq("black"))
            .order(name.desc())
            .into_boxed();
        target.load::<(User, Option<Post>)>(&mut conn).unwrap()
    })
}

pub fn bench_medium_complex_query_queryable_by_name(b: &mut Bencher, size: usize) {
    let mut conn = connection();
    insert_users(size, &mut conn, |i| {
        Some(if i % 2 == 0 { "black" } else { "brown" })
    });

    b.iter(|| {
        diesel::sql_query(
            "SELECT u.id, u.name, u.hair_color, p.id, p.user_id, p.title, p.body \
             FROM users as u LEFT JOIN posts as p on u.id = p.user_id",
        )
        .load::<(User, Option<Post>)>(&mut conn)
        .unwrap()
    })
}

pub fn bench_insert(b: &mut Bencher, size: usize) {
    let mut conn = connection();

    b.iter(|| insert_users(size, &mut conn, |_| Some("hair_color")))
}

pub fn loading_associations_sequentially(b: &mut Bencher) {
    #[cfg(feature = "sqlite")]
    const USER_NUMBER: usize = 9;

    #[cfg(not(feature = "sqlite"))]
    const USER_NUMBER: usize = 100;

    // SETUP A TON OF DATA
    let mut conn = connection();
    insert_users(USER_NUMBER, &mut conn, |i| {
        Some(if i % 2 == 0 { "black" } else { "brown" })
    });

    let all_users = users::table.load::<User>(&mut conn).unwrap();
    let data: Vec<_> = all_users
        .iter()
        .flat_map(|user| {
            let user_id = user.id;
            (0..10).map(move |i| {
                let title = format!("Post {} by user {}", i, user_id);
                NewPost::new(user_id, &title, None)
            })
        })
        .collect();
    insert_into(posts::table)
        .values(&data)
        .execute(&mut conn)
        .unwrap();
    let all_posts = posts::table.load::<Post>(&mut conn).unwrap();
    let data: Vec<_> = all_posts
        .iter()
        .flat_map(|post| {
            let post_id = post.id;
            (0..10).map(move |i| {
                let title = format!("Comment {} on post {}", i, post_id);
                (title, post_id)
            })
        })
        .collect();
    let comment_data: Vec<_> = data
        .iter()
        .map(|&(ref title, post_id)| NewComment(post_id, &title))
        .collect();
    insert_into(comments::table)
        .values(&comment_data)
        .execute(&mut conn)
        .unwrap();

    // ACTUAL BENCHMARK
    b.iter(|| {
        let users = users::table.load::<User>(&mut conn).unwrap();
        let posts = Post::belonging_to(&users).load::<Post>(&mut conn).unwrap();
        let comments = Comment::belonging_to(&posts)
            .load::<Comment>(&mut conn)
            .unwrap()
            .grouped_by(&posts);
        let posts_and_comments = posts.into_iter().zip(comments).grouped_by(&users);
        users
            .into_iter()
            .zip(posts_and_comments)
            .collect::<Vec<(User, Vec<(Post, Vec<Comment>)>)>>()
    })
}
<commit_msg>Remove the order clause from diesels medium complex query benches<commit_after>use criterion::Bencher;
use diesel::*;

#[cfg(feature = "postgres")]
type TestConnection = PgConnection;

#[cfg(feature = "mysql")]
type TestConnection = MysqlConnection;

#[cfg(feature = "sqlite")]
type TestConnection = SqliteConnection;

table! {
    users {
        id -> Integer,
        name -> Text,
        hair_color -> Nullable<Text>,
    }
}

table! {
    posts {
        id -> Integer,
        user_id -> Integer,
        title -> Text,
        body -> Nullable<Text>,
    }
}

table! {
    comments {
        id -> Integer,
        post_id -> Integer,
        text -> Text,
    }
}

joinable!(comments -> posts (post_id));
joinable!(posts -> users (user_id));
allow_tables_to_appear_in_same_query!(users, posts, comments);

#[derive(
    PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Insertable, AsChangeset, QueryableByName,
)]
#[table_name = "users"]
pub struct User {
    pub id: i32,
    pub name: String,
    pub hair_color: Option<String>,
}

#[derive(Debug, PartialEq, Eq, Queryable, Clone, Insertable, AsChangeset)]
#[table_name = "users"]
pub struct NewUser {
    pub name: String,
    pub hair_color: Option<String>,
}

impl NewUser {
    pub fn new(name: &str, hair_color: Option<&str>) -> Self {
        NewUser {
            name: name.to_string(),
            hair_color: hair_color.map(|s| s.to_string()),
        }
    }
}

#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, QueryableByName)]
#[belongs_to(User)]
#[table_name = "posts"]
pub struct Post {
    pub id: i32,
    pub user_id: i32,
    pub title: String,
    pub body: Option<String>,
}

#[derive(Insertable)]
#[table_name = "posts"]
pub struct NewPost {
    user_id: i32,
    title: String,
    body: Option<String>,
}

impl NewPost {
    pub fn new(user_id: i32, title: &str, body: Option<&str>) -> Self {
        NewPost {
            user_id,
            title: title.into(),
            body: body.map(|b| b.into()),
        }
    }
}

#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
#[belongs_to(Post)]
pub struct Comment {
    id: i32,
    post_id: i32,
    text: String,
}

#[derive(Debug, Clone, Copy, Insertable)]
#[table_name = "comments"]
pub struct NewComment<'a>(
    #[column_name = "post_id"] pub i32,
    #[column_name = "text"] pub &'a str,
);

#[cfg(feature = "mysql")]
fn connection() -> TestConnection {
    dotenv::dotenv().ok();
    let connection_url = dotenv::var("MYSQL_DATABASE_URL")
        .or_else(|_| dotenv::var("DATABASE_URL"))
        .expect("DATABASE_URL must be set in order to run tests");
    let mut conn = MysqlConnection::establish(&connection_url).unwrap();
    conn.execute("SET FOREIGN_KEY_CHECKS = 0;").unwrap();
    conn.execute("TRUNCATE TABLE comments").unwrap();
    conn.execute("TRUNCATE TABLE posts").unwrap();
    conn.execute("TRUNCATE TABLE users").unwrap();
    conn.execute("SET FOREIGN_KEY_CHECKS = 1;").unwrap();
    conn
}

#[cfg(feature = "postgres")]
fn connection() -> TestConnection {
    dotenv::dotenv().ok();
    let connection_url = dotenv::var("PG_DATABASE_URL")
        .or_else(|_| dotenv::var("DATABASE_URL"))
        .expect("DATABASE_URL must be set in order to run tests");
    let mut conn = PgConnection::establish(&connection_url).unwrap();
    conn.execute("TRUNCATE TABLE comments CASCADE").unwrap();
    conn.execute("TRUNCATE TABLE posts CASCADE").unwrap();
    conn.execute("TRUNCATE TABLE users CASCADE").unwrap();
    conn
}

#[cfg(feature = "sqlite")]
fn connection() -> TestConnection {
    dotenv::dotenv().ok();
    let mut conn = diesel::SqliteConnection::establish(":memory:").unwrap();
    for migration in super::SQLITE_MIGRATION_SQL {
        conn.execute(migration).unwrap();
    }
    conn.execute("DELETE FROM comments").unwrap();
    conn.execute("DELETE FROM posts").unwrap();
    conn.execute("DELETE FROM users").unwrap();
    conn
}

fn insert_users(
    size: usize,
    conn: &mut TestConnection,
    hair_color_init: impl Fn(usize) -> Option<&'static str>,
) {
    let data: Vec<_> = (0..size)
        .map(|i| NewUser::new(&format!("User {}", i), hair_color_init(i)))
        .collect();
    insert_into(users::table)
        .values(&data)
        .execute(conn)
        .unwrap();
}

pub fn bench_trivial_query(b: &mut Bencher, size: usize) {
    let mut conn = connection();
    insert_users(size, &mut conn, |_| None);

    b.iter(|| users::table.load::<User>(&mut conn).unwrap())
}

pub fn bench_trivial_query_boxed(b: &mut Bencher, size: usize) {
    let mut conn = connection();

    insert_users(size, &mut conn, |_| None);
    b.iter(|| users::table.into_boxed().load::<User>(&mut conn).unwrap())
}

pub fn bench_trivial_query_raw(b: &mut Bencher, size: usize) {
    let mut conn = connection();
    insert_users(size, &mut conn, |_| None);

    b.iter(|| {
        diesel::sql_query("SELECT id, name, hair_color FROM users")
            .load::<User>(&mut conn)
            .unwrap()
    })
}

pub fn bench_medium_complex_query(b: &mut Bencher, size: usize) {
    let mut conn = connection();

    insert_users(size, &mut conn, |i| {
        Some(if i % 2 == 0 { "black" } else { "brown" })
    });

    b.iter(|| {
        use self::users::dsl::*;
        let target = users
            .left_outer_join(posts::table)
            .filter(hair_color.eq("black"));
        target.load::<(User, Option<Post>)>(&mut conn).unwrap()
    })
}

pub fn bench_medium_complex_query_boxed(b: &mut Bencher, size: usize) {
    let mut conn = connection();
    insert_users(size, &mut conn, |i| {
        Some(if i % 2 == 0 { "black" } else { "brown" })
    });

    b.iter(|| {
        use self::users::dsl::*;
        let target = users
            .left_outer_join(posts::table)
            .filter(hair_color.eq("black"))
            .into_boxed();
        target.load::<(User, Option<Post>)>(&mut conn).unwrap()
    })
}

pub fn bench_medium_complex_query_queryable_by_name(b: &mut Bencher, size: usize) {
    let mut conn = connection();
    insert_users(size, &mut conn, |i| {
        Some(if i % 2 == 0 { "black" } else { "brown" })
    });

    b.iter(|| {
        diesel::sql_query(
            "SELECT u.id, u.name, u.hair_color, p.id, p.user_id, p.title, p.body \
             FROM users as u LEFT JOIN posts as p on u.id = p.user_id",
        )
        .load::<(User, Option<Post>)>(&mut conn)
        .unwrap()
    })
}

pub fn bench_insert(b: &mut Bencher, size: usize) {
    let mut conn = connection();

    b.iter(|| insert_users(size, &mut conn, |_| Some("hair_color")))
}

pub fn loading_associations_sequentially(b: &mut Bencher) {
    #[cfg(feature = "sqlite")]
    const USER_NUMBER: usize = 9;

    #[cfg(not(feature = "sqlite"))]
    const USER_NUMBER: usize = 100;

    // SETUP A TON OF DATA
    let mut conn = connection();
    insert_users(USER_NUMBER, &mut conn, |i| {
        Some(if i % 2 == 0 { "black" } else { "brown" })
    });

    let all_users = users::table.load::<User>(&mut conn).unwrap();
    let data: Vec<_> = all_users
        .iter()
        .flat_map(|user| {
            let user_id = user.id;
            (0..10).map(move |i| {
                let title = format!("Post {} by user {}", i, user_id);
                NewPost::new(user_id, &title, None)
            })
        })
        .collect();
    insert_into(posts::table)
        .values(&data)
        .execute(&mut conn)
        .unwrap();
    let all_posts = posts::table.load::<Post>(&mut conn).unwrap();
    let data: Vec<_> = all_posts
        .iter()
        .flat_map(|post| {
            let post_id = post.id;
            (0..10).map(move |i| {
                let title = format!("Comment {} on post {}", i, post_id);
                (title, post_id)
            })
        })
        .collect();
    let comment_data: Vec<_> = data
        .iter()
        .map(|&(ref title, post_id)| NewComment(post_id, &title))
        .collect();
    insert_into(comments::table)
        .values(&comment_data)
        .execute(&mut conn)
        .unwrap();

    // ACTUAL BENCHMARK
    b.iter(|| {
        let users = users::table.load::<User>(&mut conn).unwrap();
        let posts = Post::belonging_to(&users).load::<Post>(&mut conn).unwrap();
        let comments = Comment::belonging_to(&posts)
            .load::<Comment>(&mut conn)
            .unwrap()
            .grouped_by(&posts);
        let posts_and_comments = posts.into_iter().zip(comments).grouped_by(&users);
        users
            .into_iter()
            .zip(posts_and_comments)
            .collect::<Vec<(User, Vec<(Post, Vec<Comment>)>)>>()
    })
}
<|endoftext|>


<commit_before>// Uncomment the following line to disable unstable warnings:
// #![allow(unstable)]

extern crate regex;
use regex::Regex;
use std::ascii::AsciiExt;
// use std::collections;
use std::io;
use std::io::{BufferedReader, File, IoResult};

pub mod config;
pub mod btree_map;

fn do_work(cfg: &config::Config) -> IoResult<()> {
    // Open input and output files
    let mut readers = vec![];
    if cfg.input.is_empty() {
        readers.push(BufferedReader::new(Box::new(io::stdin()) as Box<Reader>));
    } else {
        for name in cfg.input.iter() {
            let file = try!(File::open(&Path::new(name.as_slice())));
            readers.push(BufferedReader::new(Box::new(file) as Box<Reader>));
        }
    }
    let mut writer = match cfg.output {
        Some(ref x) => { Box::new(try!(File::create(&Path::new(x.as_slice())))) as Box<Writer> }
        None => { Box::new(io::stdout()) as Box<Writer> }
    };

    // Parse words
    // let mut map = collections::BTreeMap::<String, u32>::new();
    let mut map = btree_map::BTreeMap::<String, u32>::new();
    let re = Regex::new(r"\w+").unwrap();
    for reader in readers.iter_mut() {
        for line in reader.lines() {
            for caps in re.captures_iter(line.unwrap().as_slice()) {
                if let Some(cap) = caps.at(0) {
                    let word = match cfg.ignore_case {
                        true  => cap.to_ascii_lowercase(),
                        false => cap.to_string(),
                    };
                    let found = match map.get_mut(&word) {
                        Some(count) => { *count = *count + 1; true }
                        None => false,
                    };
                    if !found {
                        map.insert(word, 1);
                    }
                }
            }
        }
    }

    // Write counts
    for (k, v) in map.iter() {
        let line = format!("{}\t{}\n", v, k);
        try!(writer.write(line.as_bytes()));
    }
    Ok(())
}

#[cfg(not(test))]
fn main() {
    let cfg = match config::get_config(std::os::args()) {
        Ok(c) => c,
        Err(usage) => {
            println!("{}", usage);
            return;
        }
    };
    do_work(&cfg).unwrap();
}

#[test]
fn test_do_work() {
    let bad_filename = "/..no-such-file..";
    let cfg = config::Config {
        input: vec![bad_filename.to_string()],
        output: None,
        ignore_case: false,
    };
    match do_work(&cfg) {
        // should fail for bad input file (couldn't open file ... path=/..no-such-file..; ...)
        Err(e) => assert!(format!("{}", e).as_slice().contains(bad_filename), format!("{}", e)),
        _ => panic!()
    }
}

<commit_msg>Fix comments<commit_after>// Uncomment the following line to disable unstable warnings:
// #![allow(unstable)]

extern crate regex;
use regex::Regex;
use std::ascii::AsciiExt;
// use std::collections;
use std::io;
use std::io::{BufferedReader, File, IoResult};

pub mod config;
pub mod btree_map;

fn do_work(cfg: &config::Config) -> IoResult<()> {
    // Open input and output files
    let mut readers = vec![];
    if cfg.input.is_empty() {
        readers.push(BufferedReader::new(Box::new(io::stdin()) as Box<Reader>));
    } else {
        for name in cfg.input.iter() {
            let file = try!(File::open(&Path::new(name.as_slice())));
            readers.push(BufferedReader::new(Box::new(file) as Box<Reader>));
        }
    }
    let mut writer = match cfg.output {
        Some(ref x) => { Box::new(try!(File::create(&Path::new(x.as_slice())))) as Box<Writer> }
        None => { Box::new(io::stdout()) as Box<Writer> }
    };

    // Parse words
    let mut map = btree_map::BTreeMap::<String, u32>::new();
    // let mut map = collections::BTreeMap::<String, u32>::new();
    let re = Regex::new(r"\w+").unwrap();
    for reader in readers.iter_mut() {
        for line in reader.lines() {
            for caps in re.captures_iter(line.unwrap().as_slice()) {
                if let Some(cap) = caps.at(0) {
                    let word = match cfg.ignore_case {
                        true  => cap.to_ascii_lowercase(),
                        false => cap.to_string(),
                    };
                    let found = match map.get_mut(&word) {
                        Some(count) => { *count = *count + 1; true }
                        None => false,
                    };
                    if !found {
                        map.insert(word, 1);
                    }
                }
            }
        }
    }

    // Write counts
    for (k, v) in map.iter() {
        let line = format!("{}\t{}\n", v, k);
        try!(writer.write(line.as_bytes()));
    }
    Ok(())
}

#[cfg(not(test))]
fn main() {
    let cfg = match config::get_config(std::os::args()) {
        Ok(c) => c,
        Err(usage) => {
            println!("{}", usage);
            return;
        }
    };
    do_work(&cfg).unwrap();
}

#[test]
fn test_do_work() {
    let bad_filename = "/..no-such-file..";
    let cfg = config::Config {
        input: vec![bad_filename.to_string()],
        output: None,
        ignore_case: false,
    };
    match do_work(&cfg) {
        // should fail for bad input file (couldn't open file ... path=/..no-such-file..; ...)
        Err(e) => assert!(format!("{}", e).as_slice().contains(bad_filename), format!("{}", e)),
        _ => panic!()
    }
}

<|endoftext|>


<commit_before>use super::ToTokens;

use std::iter;

use proc_macro2::{TokenStream, TokenTree};

/// TokenStream extension trait with methods for appending tokens.
///
/// This trait is sealed and cannot be implemented outside of the `quote` crate.
pub trait TokenStreamExt: private::Sealed {
    /// For use by `ToTokens` implementations.
    ///
    /// Appends the token specified to this list of tokens.
    fn append<U>(&mut self, token: U)
    where
        U: Into<TokenTree>;

    /// For use by `ToTokens` implementations.
    ///
    /// ```
    /// # use quote::{quote, TokenStreamExt, ToTokens};
    /// # use proc_macro2::TokenStream;
    /// #
    /// struct X;
    ///
    /// impl ToTokens for X {
    ///     fn to_tokens(&self, tokens: &mut TokenStream) {
    ///         tokens.append_all(&[true, false]);
    ///     }
    /// }
    ///
    /// let tokens = quote!(#X);
    /// assert_eq!(tokens.to_string(), "true false");
    /// ```
    fn append_all<T, I>(&mut self, iter: I)
    where
        T: ToTokens,
        I: IntoIterator<Item = T>;

    /// For use by `ToTokens` implementations.
    ///
    /// Appends all of the items in the iterator `I`, separated by the tokens
    /// `U`.
    fn append_separated<T, I, U>(&mut self, iter: I, op: U)
    where
        T: ToTokens,
        I: IntoIterator<Item = T>,
        U: ToTokens;

    /// For use by `ToTokens` implementations.
    ///
    /// Appends all tokens in the iterator `I`, appending `U` after each
    /// element, including after the last element of the iterator.
    fn append_terminated<T, I, U>(&mut self, iter: I, term: U)
    where
        T: ToTokens,
        I: IntoIterator<Item = T>,
        U: ToTokens;
}

impl TokenStreamExt for TokenStream {
    fn append<U>(&mut self, token: U)
    where
        U: Into<TokenTree>,
    {
        self.extend(iter::once(token.into()));
    }

    fn append_all<T, I>(&mut self, iter: I)
    where
        T: ToTokens,
        I: IntoIterator<Item = T>,
    {
        for token in iter {
            token.to_tokens(self);
        }
    }

    fn append_separated<T, I, U>(&mut self, iter: I, op: U)
    where
        T: ToTokens,
        I: IntoIterator<Item = T>,
        U: ToTokens,
    {
        for (i, token) in iter.into_iter().enumerate() {
            if i > 0 {
                op.to_tokens(self);
            }
            token.to_tokens(self);
        }
    }

    fn append_terminated<T, I, U>(&mut self, iter: I, term: U)
    where
        T: ToTokens,
        I: IntoIterator<Item = T>,
        U: ToTokens,
    {
        for token in iter {
            token.to_tokens(self);
            term.to_tokens(self);
        }
    }
}

mod private {
    use proc_macro2::TokenStream;

    pub trait Sealed {}

    impl Sealed for TokenStream {}
}
<commit_msg>Remove unneeded type parameters from TokenStreamExt<commit_after>use super::ToTokens;

use std::iter;

use proc_macro2::{TokenStream, TokenTree};

/// TokenStream extension trait with methods for appending tokens.
///
/// This trait is sealed and cannot be implemented outside of the `quote` crate.
pub trait TokenStreamExt: private::Sealed {
    /// For use by `ToTokens` implementations.
    ///
    /// Appends the token specified to this list of tokens.
    fn append<U>(&mut self, token: U)
    where
        U: Into<TokenTree>;

    /// For use by `ToTokens` implementations.
    ///
    /// ```
    /// # use quote::{quote, TokenStreamExt, ToTokens};
    /// # use proc_macro2::TokenStream;
    /// #
    /// struct X;
    ///
    /// impl ToTokens for X {
    ///     fn to_tokens(&self, tokens: &mut TokenStream) {
    ///         tokens.append_all(&[true, false]);
    ///     }
    /// }
    ///
    /// let tokens = quote!(#X);
    /// assert_eq!(tokens.to_string(), "true false");
    /// ```
    fn append_all<I>(&mut self, iter: I)
    where
        I: IntoIterator,
        I::Item: ToTokens;

    /// For use by `ToTokens` implementations.
    ///
    /// Appends all of the items in the iterator `I`, separated by the tokens
    /// `U`.
    fn append_separated<I, U>(&mut self, iter: I, op: U)
    where
        I: IntoIterator,
        I::Item: ToTokens,
        U: ToTokens;

    /// For use by `ToTokens` implementations.
    ///
    /// Appends all tokens in the iterator `I`, appending `U` after each
    /// element, including after the last element of the iterator.
    fn append_terminated<I, U>(&mut self, iter: I, term: U)
    where
        I: IntoIterator,
        I::Item: ToTokens,
        U: ToTokens;
}

impl TokenStreamExt for TokenStream {
    fn append<U>(&mut self, token: U)
    where
        U: Into<TokenTree>,
    {
        self.extend(iter::once(token.into()));
    }

    fn append_all<I>(&mut self, iter: I)
    where
        I: IntoIterator,
        I::Item: ToTokens,
    {
        for token in iter {
            token.to_tokens(self);
        }
    }

    fn append_separated<I, U>(&mut self, iter: I, op: U)
    where
        I: IntoIterator,
        I::Item: ToTokens,
        U: ToTokens,
    {
        for (i, token) in iter.into_iter().enumerate() {
            if i > 0 {
                op.to_tokens(self);
            }
            token.to_tokens(self);
        }
    }

    fn append_terminated<I, U>(&mut self, iter: I, term: U)
    where
        I: IntoIterator,
        I::Item: ToTokens,
        U: ToTokens,
    {
        for token in iter {
            token.to_tokens(self);
            term.to_tokens(self);
        }
    }
}

mod private {
    use proc_macro2::TokenStream;

    pub trait Sealed {}

    impl Sealed for TokenStream {}
}
<|endoftext|>