<commit_before>use std::default::Default;
use std::env::temp_dir;
use std::path::{Path, PathBuf};

use diesel::{Connection, RunQueryDsl, SqliteConnection};
use juniper::FieldResult;
use structopt::StructOpt;

use auth::JwtData;
use contest::{ContestView, UserToken};

use formats::{import, ImportInput};
use problem::ProblemName;
use user::UserId;
use user::UserInput;

use crate::api::award::AwardOutcome;
use crate::api::contest::{Contest, ContestUpdateInput};
use crate::api::contest_evaluation::Evaluation;
use crate::api::contest_problem::{Problem, ProblemInput};
use crate::api::user::{User, UserUpdateInput};

use super::*;

embed_migrations!();

pub struct MutationOk;

#[juniper::object]
impl MutationOk {
    fn ok() -> bool {
        true
    }
}

pub type RootNode<'a> = juniper::RootNode<'static, Query<'a>, Mutation<'a>>;

#[derive(StructOpt, Debug)]
pub struct ContestArgs {
    /// url of the database
    #[structopt(long, env = "DATABASE_URL", default_value = "./database.sqlite3")]
    pub database_url: PathBuf,
}

#[derive(Debug, Clone)]
pub struct ApiConfig {
    /// Skip all authentication
    skip_auth: bool,

    /// Secret code to use for authenticating a JWT token.
    pub secret: Option<Vec<u8>>,

    /// Path of the database on the filesystem
    pub database_url: PathBuf,
}

pub struct ApiContext<'a> {
    pub config: &'a ApiConfig,
    /// JWT data of the token submitted to the server (if any)
    pub jwt_data: Option<JwtData>,
    pub database: SqliteConnection,
    pub workspace_path: PathBuf,
}

impl Default for ApiConfig {
    fn default() -> ApiConfig {
        ApiConfig {
            skip_auth: false,
            secret: None,
            database_url: PathBuf::default(),
        }
    }
}

impl ApiConfig {
    pub fn create_context(&self, jwt_data: Option<JwtData>) -> ApiContext {
        // FIXME: should not create directory here
        let workspace_path = temp_dir().join("turingarena");
        std::fs::create_dir_all(&workspace_path).expect("Unable to create workspace dir");

        ApiContext {
            config: &self,
            database: self.connect_db(),
            jwt_data,
            workspace_path,
        }
    }

    fn connect_db(&self) -> SqliteConnection {
        let conn = SqliteConnection::establish(self.database_url.to_str().unwrap())
            .expect("Unable to establish connection");
        conn.execute("PRAGMA busy_timeout = 5000;")
            .expect("Unable to set `busy_timeout`");
        conn
    }

    pub fn with_args(self, args: ContestArgs) -> ApiConfig {
        self.with_database_url(args.database_url)
    }

    /// Set the database URL
    pub fn with_database_url(self, database_url: PathBuf) -> ApiConfig {
        ApiConfig {
            database_url,
            ..self
        }
    }

    /// Sets a secret
    pub fn with_secret(self, secret: Option<Vec<u8>>) -> ApiConfig {
        ApiConfig { secret, ..self }
    }

    /// Sets if to skip authentication
    pub fn with_skip_auth(self, skip_auth: bool) -> ApiConfig {
        ApiConfig { skip_auth, ..self }
    }
}

impl ApiContext<'_> {
    pub fn root_node(&self) -> RootNode {
        RootNode::new(Query { context: &self }, Mutation { context: &self })
    }

    pub fn workspace_path(&self) -> &Path {
        &self.workspace_path
    }

    pub fn unpack_archive<T: AsRef<[u8]>>(&self, content: T, prefix: &str) -> PathBuf {
        let workspace_path = &self.workspace_path().to_owned();

        archive::unpack_archive(workspace_path, content, prefix)
    }

    pub fn default_contest(&self) -> Contest {
        Contest::new(&self)
    }

    /// Authorize admin operations
    #[must_use = "Error means forbidden"]
    pub fn authorize_admin(&self) -> juniper::FieldResult<()> {
        if self.config.skip_auth {
            return Ok(());
        }
        return Err(juniper::FieldError::from("Forbidden"));
    }

    /// Authenticate user
    #[must_use = "Error means forbidden"]
    pub fn authorize_user(&self, user_id: &Option<UserId>) -> juniper::FieldResult<()> {
        if self.config.skip_auth {
            return Ok(());
        }

        if let Some(id) = user_id {
            if self.config.secret != None {
                if let Some(data) = &self.jwt_data {
                    if data.user != id.0 {
                        return Err(juniper::FieldError::from("Forbidden for the given user id"));
                    }
                } else {
                    return Err(juniper::FieldError::from("Authentication required"));
                }
            }
        }
        Ok(())
    }
}

pub struct Query<'a> {
    pub context: &'a ApiContext<'a>,
}

#[juniper_ext::graphql]
#[allow(dead_code)]
impl Query<'_> {
    /// Get the view of a contest
    fn contest_view(&self, user_id: Option<UserId>) -> FieldResult<ContestView> {
        self.context.authorize_user(&user_id)?;
        ContestView::new(&self.context, user_id)
    }

    fn users(&self) -> FieldResult<Vec<User>> {
        self.context.authorize_admin()?;
        User::list(&self.context)
    }

    fn problems(&self) -> FieldResult<Vec<Problem>> {
        self.context.authorize_admin()?;
        Problem::all(&self.context)
    }

    fn awards(&self) -> FieldResult<Vec<AwardOutcome>> {
        self.context.authorize_admin()?;
        AwardOutcome::list_by_user_and_problem(&self.context)
    }

    fn submissions(&self) -> FieldResult<Vec<contest_submission::Submission>> {
        self.context.authorize_admin()?;
        contest_submission::Submission::list(&self.context)
    }

    /// Get the submission with the specified id
    fn submission(&self, submission_id: String) -> FieldResult<contest_submission::Submission> {
        let submission = contest_submission::Submission::by_id(&self.context, &submission_id)?;
        self.context.authorize_user(&Some(submission.user_id()))?;
        Ok(submission)
    }

    /// Current time on the server as RFC3339 date
    fn server_time(&self) -> String {
        chrono::Local::now().to_rfc3339()
    }
}

pub struct Mutation<'a> {
    pub context: &'a ApiContext<'a>,
}

#[juniper_ext::graphql]
#[allow(dead_code)]
impl Mutation<'_> {
    /// Reset database
    fn init_db(&self) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;

        embedded_migrations::run_with_output(&self.context.database, &mut std::io::stdout())?;
        self.context.default_contest().init()?;

        Ok(MutationOk)
    }

    /// Authenticate a user, generating a JWT authentication token
    fn auth(&self, token: String) -> FieldResult<Option<UserToken>> {
        Ok(auth::auth(&self.context, &token)?)
    }

    /// Current time on the server as RFC3339 date
    fn server_time() -> String {
        chrono::Local::now().to_rfc3339()
    }

    /// Add a user to the current contest
    pub fn update_contest(&self, input: ContestUpdateInput) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;
        self.context.default_contest().update(input);

        Ok(MutationOk)
    }

    /// Add a user to the current contest
    pub fn add_users(&self, inputs: Vec<UserInput>) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;
        User::insert(&self.context, inputs)?;
        Ok(MutationOk)
    }

    pub fn update_users(&self, inputs: Vec<UserUpdateInput>) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;
        User::update(&self.context, inputs)?;
        Ok(MutationOk)
    }

    /// Delete a user from the current contest
    pub fn delete_users(&self, ids: Vec<String>) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;
        User::delete(&self.context, ids)?;
        Ok(MutationOk)
    }

    /// Add a problem to the current contest
    pub fn add_problems(&self, inputs: Vec<ProblemInput>) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;
        Problem::insert(&self.context, inputs)?;
        Ok(MutationOk)
    }

    /// Delete a problem from the current contest
    pub fn delete_problem(&self, name: String) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;
        Problem::delete(&self.context, ProblemName(name))?;
        Ok(MutationOk)
    }

    /// Import a file
    pub fn import(&self, input: ImportInput) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;
        import(&self.context, &input)?;
        Ok(MutationOk)
    }

    /// Submit a solution to the problem
    fn submit(
        &self,
        user_id: UserId,
        problem_name: ProblemName,
        files: Vec<contest_submission::FileInput>,
    ) -> FieldResult<contest_submission::Submission> {
        let submission = contest_submission::Submission::insert(
            &self.context,
            &user_id.0,
            &problem_name.0,
            files,
        )?;
        Evaluation::evaluate(&submission, &self.context.config)?;
        Ok(submission)
    }
}
<commit_msg>Fix missing `?` in `Mutation::init_db`<commit_after>use std::default::Default;
use std::env::temp_dir;
use std::path::{Path, PathBuf};

use diesel::{Connection, RunQueryDsl, SqliteConnection};
use juniper::FieldResult;
use structopt::StructOpt;

use auth::JwtData;
use contest::{ContestView, UserToken};

use formats::{import, ImportInput};
use problem::ProblemName;
use user::UserId;
use user::UserInput;

use crate::api::award::AwardOutcome;
use crate::api::contest::{Contest, ContestUpdateInput};
use crate::api::contest_evaluation::Evaluation;
use crate::api::contest_problem::{Problem, ProblemInput};
use crate::api::user::{User, UserUpdateInput};

use super::*;

embed_migrations!();

pub struct MutationOk;

#[juniper::object]
impl MutationOk {
    fn ok() -> bool {
        true
    }
}

pub type RootNode<'a> = juniper::RootNode<'static, Query<'a>, Mutation<'a>>;

#[derive(StructOpt, Debug)]
pub struct ContestArgs {
    /// url of the database
    #[structopt(long, env = "DATABASE_URL", default_value = "./database.sqlite3")]
    pub database_url: PathBuf,
}

#[derive(Debug, Clone)]
pub struct ApiConfig {
    /// Skip all authentication
    skip_auth: bool,

    /// Secret code to use for authenticating a JWT token.
    pub secret: Option<Vec<u8>>,

    /// Path of the database on the filesystem
    pub database_url: PathBuf,
}

pub struct ApiContext<'a> {
    pub config: &'a ApiConfig,
    /// JWT data of the token submitted to the server (if any)
    pub jwt_data: Option<JwtData>,
    pub database: SqliteConnection,
    pub workspace_path: PathBuf,
}

impl Default for ApiConfig {
    fn default() -> ApiConfig {
        ApiConfig {
            skip_auth: false,
            secret: None,
            database_url: PathBuf::default(),
        }
    }
}

impl ApiConfig {
    pub fn create_context(&self, jwt_data: Option<JwtData>) -> ApiContext {
        // FIXME: should not create directory here
        let workspace_path = temp_dir().join("turingarena");
        std::fs::create_dir_all(&workspace_path).expect("Unable to create workspace dir");

        ApiContext {
            config: &self,
            database: self.connect_db(),
            jwt_data,
            workspace_path,
        }
    }

    fn connect_db(&self) -> SqliteConnection {
        let conn = SqliteConnection::establish(self.database_url.to_str().unwrap())
            .expect("Unable to establish connection");
        conn.execute("PRAGMA busy_timeout = 5000;")
            .expect("Unable to set `busy_timeout`");
        conn
    }

    pub fn with_args(self, args: ContestArgs) -> ApiConfig {
        self.with_database_url(args.database_url)
    }

    /// Set the database URL
    pub fn with_database_url(self, database_url: PathBuf) -> ApiConfig {
        ApiConfig {
            database_url,
            ..self
        }
    }

    /// Sets a secret
    pub fn with_secret(self, secret: Option<Vec<u8>>) -> ApiConfig {
        ApiConfig { secret, ..self }
    }

    /// Sets if to skip authentication
    pub fn with_skip_auth(self, skip_auth: bool) -> ApiConfig {
        ApiConfig { skip_auth, ..self }
    }
}

impl ApiContext<'_> {
    pub fn root_node(&self) -> RootNode {
        RootNode::new(Query { context: &self }, Mutation { context: &self })
    }

    pub fn workspace_path(&self) -> &Path {
        &self.workspace_path
    }

    pub fn unpack_archive<T: AsRef<[u8]>>(&self, content: T, prefix: &str) -> PathBuf {
        let workspace_path = &self.workspace_path().to_owned();

        archive::unpack_archive(workspace_path, content, prefix)
    }

    pub fn default_contest(&self) -> Contest {
        Contest::new(&self)
    }

    /// Authorize admin operations
    #[must_use = "Error means forbidden"]
    pub fn authorize_admin(&self) -> juniper::FieldResult<()> {
        if self.config.skip_auth {
            return Ok(());
        }
        return Err(juniper::FieldError::from("Forbidden"));
    }

    /// Authenticate user
    #[must_use = "Error means forbidden"]
    pub fn authorize_user(&self, user_id: &Option<UserId>) -> juniper::FieldResult<()> {
        if self.config.skip_auth {
            return Ok(());
        }

        if let Some(id) = user_id {
            if self.config.secret != None {
                if let Some(data) = &self.jwt_data {
                    if data.user != id.0 {
                        return Err(juniper::FieldError::from("Forbidden for the given user id"));
                    }
                } else {
                    return Err(juniper::FieldError::from("Authentication required"));
                }
            }
        }
        Ok(())
    }
}

pub struct Query<'a> {
    context: &'a ApiContext<'a>,
}

#[juniper_ext::graphql]
#[allow(dead_code)]
impl Query<'_> {
    /// Get the view of a contest
    fn contest_view(&self, user_id: Option<UserId>) -> FieldResult<ContestView> {
        self.context.authorize_user(&user_id)?;
        ContestView::new(&self.context, user_id)
    }

    fn users(&self) -> FieldResult<Vec<User>> {
        self.context.authorize_admin()?;
        User::list(&self.context)
    }

    fn problems(&self) -> FieldResult<Vec<Problem>> {
        self.context.authorize_admin()?;
        Problem::all(&self.context)
    }

    fn awards(&self) -> FieldResult<Vec<AwardOutcome>> {
        self.context.authorize_admin()?;
        AwardOutcome::list_by_user_and_problem(&self.context)
    }

    fn submissions(&self) -> FieldResult<Vec<contest_submission::Submission>> {
        self.context.authorize_admin()?;
        contest_submission::Submission::list(&self.context)
    }

    /// Get the submission with the specified id
    fn submission(&self, submission_id: String) -> FieldResult<contest_submission::Submission> {
        let submission = contest_submission::Submission::by_id(&self.context, &submission_id)?;
        self.context.authorize_user(&Some(submission.user_id()))?;
        Ok(submission)
    }

    /// Current time on the server as RFC3339 date
    fn server_time(&self) -> String {
        chrono::Local::now().to_rfc3339()
    }
}

pub struct Mutation<'a> {
    context: &'a ApiContext<'a>,
}

#[juniper_ext::graphql]
#[allow(dead_code)]
impl Mutation<'_> {
    /// Reset database
    fn init_db(&self) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;

        embedded_migrations::run_with_output(&self.context.database, &mut std::io::stdout())?;
        self.context.default_contest().init()?;

        Ok(MutationOk)
    }

    /// Authenticate a user, generating a JWT authentication token
    fn auth(&self, token: String) -> FieldResult<Option<UserToken>> {
        Ok(auth::auth(&self.context, &token)?)
    }

    /// Current time on the server as RFC3339 date
    fn server_time() -> String {
        chrono::Local::now().to_rfc3339()
    }

    /// Add a user to the current contest
    pub fn update_contest(&self, input: ContestUpdateInput) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;
        self.context.default_contest().update(input)?;

        Ok(MutationOk)
    }

    /// Add a user to the current contest
    pub fn add_users(&self, inputs: Vec<UserInput>) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;
        User::insert(&self.context, inputs)?;
        Ok(MutationOk)
    }

    pub fn update_users(&self, inputs: Vec<UserUpdateInput>) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;
        User::update(&self.context, inputs)?;
        Ok(MutationOk)
    }

    /// Delete a user from the current contest
    pub fn delete_users(&self, ids: Vec<String>) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;
        User::delete(&self.context, ids)?;
        Ok(MutationOk)
    }

    /// Add a problem to the current contest
    pub fn add_problems(&self, inputs: Vec<ProblemInput>) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;
        Problem::insert(&self.context, inputs)?;
        Ok(MutationOk)
    }

    /// Delete a problem from the current contest
    pub fn delete_problem(&self, name: String) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;
        Problem::delete(&self.context, ProblemName(name))?;
        Ok(MutationOk)
    }

    /// Import a file
    pub fn import(&self, input: ImportInput) -> FieldResult<MutationOk> {
        self.context.authorize_admin()?;
        import(&self.context, &input)?;
        Ok(MutationOk)
    }

    /// Submit a solution to the problem
    fn submit(
        &self,
        user_id: UserId,
        problem_name: ProblemName,
        files: Vec<contest_submission::FileInput>,
    ) -> FieldResult<contest_submission::Submission> {
        let submission = contest_submission::Submission::insert(
            &self.context,
            &user_id.0,
            &problem_name.0,
            files,
        )?;
        Evaluation::evaluate(&submission, &self.context.config)?;
        Ok(submission)
    }
}
<|endoftext|>


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

// Code to handle a single block device.

use std::fs::OpenOptions;
use std::path::PathBuf;

use devicemapper::Device;
use devicemapper::Segment;
use devicemapper::Sectors;
use time::Timespec;

use super::super::errors::EngineResult;
use super::super::types::{DevUuid, PoolUuid};

use super::metadata::BDA;
use super::range_alloc::RangeAllocator;
use super::serde_structs::{BlockDevSave, Recordable};

#[derive(Debug)]
pub struct BlockDev {
    dev: Device,
    pub devnode: PathBuf,
    bda: BDA,
    used: RangeAllocator,
}

impl BlockDev {
    pub fn new(dev: Device, devnode: PathBuf, bda: BDA, allocator: RangeAllocator) -> BlockDev {
        BlockDev {
            dev: dev,
            devnode: devnode,
            bda: bda,
            used: allocator,
        }
    }

    /// Returns the blockdev's Device
    pub fn device(&self) -> &Device {
        &self.dev
    }

    pub fn wipe_metadata(self) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        BDA::wipe(&mut f)
    }

    pub fn save_state(&mut self, time: &Timespec, metadata: &[u8]) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        self.bda.save_state(time, metadata, &mut f)
    }

    /// List the available-for-upper-layer-use range in this blockdev.
    pub fn avail_range(&self) -> Segment {
        let start = self.bda.size();
        let size = self.size();
        // Blockdev size is at least MIN_DEV_SIZE, so this can fail only if
        // size of metadata area exceeds 1 GiB. Initial metadata area size
        // is 4 MiB.
        assert!(start <= size);
        Segment::new(self.dev, start, size - start)
    }

    /// The device's UUID.
    pub fn uuid(&self) -> &DevUuid {
        self.bda.dev_uuid()
    }

    /// The device's pool's UUID.
    pub fn pool_uuid(&self) -> &PoolUuid {
        self.bda.pool_uuid()
    }

    /// The device's size.
    pub fn size(&self) -> Sectors {
        self.bda.dev_size()
    }

    /// Last time metadata was written to this device.
    pub fn last_update_time(&self) -> Option<&Timespec> {
        self.bda.last_update_time()
    }

    pub fn available(&self) -> Sectors {
        self.used.available()
    }

    // Find some sector ranges that could be allocated. If more
    // sectors are needed than our capacity, return partial results.
    pub fn request_space(&mut self, size: Sectors) -> (Sectors, Vec<Segment>) {
        let (size, segs) = self.used.request(size);
        (size,
         segs.iter()
             .map(|&(start, len)| Segment::new(self.dev, start, len))
             .collect())
    }
}

impl Recordable<BlockDevSave> for BlockDev {
    fn record(&self) -> EngineResult<BlockDevSave> {
        Ok(BlockDevSave { devnode: self.devnode.clone() })
    }
}
<commit_msg>Distinguish between a BlockDev's current and recorded size<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Code to handle a single block device.

use std::fs::OpenOptions;
use std::path::PathBuf;

use devicemapper::Device;
use devicemapper::Segment;
use devicemapper::Sectors;
use time::Timespec;

use super::super::errors::EngineResult;
use super::super::types::{DevUuid, PoolUuid};

use super::metadata::BDA;
use super::range_alloc::RangeAllocator;
use super::serde_structs::{BlockDevSave, Recordable};

#[derive(Debug)]
pub struct BlockDev {
    dev: Device,
    pub devnode: PathBuf,
    bda: BDA,
    used: RangeAllocator,
}

impl BlockDev {
    pub fn new(dev: Device, devnode: PathBuf, bda: BDA, allocator: RangeAllocator) -> BlockDev {
        BlockDev {
            dev: dev,
            devnode: devnode,
            bda: bda,
            used: allocator,
        }
    }

    /// Returns the blockdev's Device
    pub fn device(&self) -> &Device {
        &self.dev
    }

    pub fn wipe_metadata(self) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        BDA::wipe(&mut f)
    }

    pub fn save_state(&mut self, time: &Timespec, metadata: &[u8]) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        self.bda.save_state(time, metadata, &mut f)
    }

    /// List the available-for-upper-layer-use range in this blockdev.
    pub fn avail_range(&self) -> Segment {
        let start = self.bda.size();
        let size = self.current_capacity();
        // Blockdev size is at least MIN_DEV_SIZE, so this can fail only if
        // size of metadata area exceeds 1 GiB. Initial metadata area size
        // is 4 MiB.
        assert!(start <= size);
        Segment::new(self.dev, start, size - start)
    }

    /// The device's UUID.
    pub fn uuid(&self) -> &DevUuid {
        self.bda.dev_uuid()
    }

    /// The device's pool's UUID.
    pub fn pool_uuid(&self) -> &PoolUuid {
        self.bda.pool_uuid()
    }

    /// The size of the device as recorded in the metadata.
    pub fn recorded_size(&self) -> Sectors {
        self.bda.dev_size()
    }

    /// The actual size of the device now.
    pub fn current_capacity(&self) -> Sectors {
        self.used.capacity()
    }

    /// Last time metadata was written to this device.
    pub fn last_update_time(&self) -> Option<&Timespec> {
        self.bda.last_update_time()
    }

    pub fn available(&self) -> Sectors {
        self.used.available()
    }

    // Find some sector ranges that could be allocated. If more
    // sectors are needed than our capacity, return partial results.
    pub fn request_space(&mut self, size: Sectors) -> (Sectors, Vec<Segment>) {
        let (size, segs) = self.used.request(size);
        (size,
         segs.iter()
             .map(|&(start, len)| Segment::new(self.dev, start, len))
             .collect())
    }
}

impl Recordable<BlockDevSave> for BlockDev {
    fn record(&self) -> EngineResult<BlockDevSave> {
        Ok(BlockDevSave { devnode: self.devnode.clone() })
    }
}
<|endoftext|>


<commit_before>use proc_macro2::Span;
use quote::Tokens;
use syn::*;

pub use diagnostic_shim::*;
use meta::*;

pub fn wrap_in_dummy_mod(const_name: Ident, item: Tokens) -> Tokens {
    let call_site = root_span(Span::call_site());
    let use_everything = quote_spanned!(call_site=> __diesel_use_everything!());
    quote! {
        #[allow(non_snake_case)]
        mod #const_name {
            // https://github.com/rust-lang/rust/issues/47314
            extern crate std;

            mod diesel {
                #use_everything;
            }
            #item
        }
    }
}

pub fn inner_of_option_ty(ty: &Type) -> &Type {
    option_ty_arg(ty).unwrap_or(ty)
}

pub fn is_option_ty(ty: &Type) -> bool {
    option_ty_arg(ty).is_some()
}

fn option_ty_arg(ty: &Type) -> Option<&Type> {
    use syn::PathArguments::AngleBracketed;

    match *ty {
        Type::Path(ref ty) => {
            let last_segment = ty.path.segments.iter().last().unwrap();
            match last_segment.arguments {
                AngleBracketed(ref args) if last_segment.ident == "Option" => {
                    match args.args.iter().last() {
                        Some(&GenericArgument::Type(ref ty)) => Some(ty),
                        _ => None,
                    }
                }
                _ => None,
            }
        }
        _ => None,
    }
}

pub fn ty_for_foreign_derive(item: &DeriveInput, flags: &MetaItem) -> Result<Type, Diagnostic> {
    if flags.has_flag("foreign_derive") {
        match item.data {
            Data::Struct(ref body) => match body.fields.iter().nth(0) {
                Some(field) => Ok(field.ty.clone()),
                None => Err(flags
                    .span()
                    .error("foreign_derive requires at least one field")),
            },
            _ => Err(flags
                .span()
                .error("foreign_derive can only be used with structs")),
        }
    } else {
        let ident = item.ident;
        let (_, ty_generics, ..) = item.generics.split_for_impl();
        Ok(parse_quote!(#ident #ty_generics))
    }
}

pub fn fix_span(maybe_bad_span: Span, fallback: Span) -> Span {
    let bad_span_debug = "Span(Span { lo: BytePos(0), hi: BytePos(0), ctxt: #0 })";
    if format!("{:?}", maybe_bad_span) == bad_span_debug {
        fallback
    } else {
        maybe_bad_span
    }
}

#[cfg(not(feature = "nightly"))]
fn root_span(span: Span) -> Span {
    span
}

#[cfg(feature = "nightly")]
/// There's an issue with the resolution of `__diesel_use_everything` if the
/// derive itself was generated from within a macro. This is a shitty workaround
/// until we figure out the expected behavior.
fn root_span(span: Span) -> Span {
    span.unstable().source().into()
}
<commit_msg>Allow Unused External Crates in diesel_derives<commit_after>use proc_macro2::Span;
use quote::Tokens;
use syn::*;

pub use diagnostic_shim::*;
use meta::*;

pub fn wrap_in_dummy_mod(const_name: Ident, item: Tokens) -> Tokens {
    let call_site = root_span(Span::call_site());
    let use_everything = quote_spanned!(call_site=> __diesel_use_everything!());
    quote! {
        #[allow(non_snake_case, unused_extern_crates)]
        mod #const_name {
            // https://github.com/rust-lang/rust/issues/47314
            extern crate std;

            mod diesel {
                #use_everything;
            }
            #item
        }
    }
}

pub fn inner_of_option_ty(ty: &Type) -> &Type {
    option_ty_arg(ty).unwrap_or(ty)
}

pub fn is_option_ty(ty: &Type) -> bool {
    option_ty_arg(ty).is_some()
}

fn option_ty_arg(ty: &Type) -> Option<&Type> {
    use syn::PathArguments::AngleBracketed;

    match *ty {
        Type::Path(ref ty) => {
            let last_segment = ty.path.segments.iter().last().unwrap();
            match last_segment.arguments {
                AngleBracketed(ref args) if last_segment.ident == "Option" => {
                    match args.args.iter().last() {
                        Some(&GenericArgument::Type(ref ty)) => Some(ty),
                        _ => None,
                    }
                }
                _ => None,
            }
        }
        _ => None,
    }
}

pub fn ty_for_foreign_derive(item: &DeriveInput, flags: &MetaItem) -> Result<Type, Diagnostic> {
    if flags.has_flag("foreign_derive") {
        match item.data {
            Data::Struct(ref body) => match body.fields.iter().nth(0) {
                Some(field) => Ok(field.ty.clone()),
                None => Err(flags
                    .span()
                    .error("foreign_derive requires at least one field")),
            },
            _ => Err(flags
                .span()
                .error("foreign_derive can only be used with structs")),
        }
    } else {
        let ident = item.ident;
        let (_, ty_generics, ..) = item.generics.split_for_impl();
        Ok(parse_quote!(#ident #ty_generics))
    }
}

pub fn fix_span(maybe_bad_span: Span, fallback: Span) -> Span {
    let bad_span_debug = "Span(Span { lo: BytePos(0), hi: BytePos(0), ctxt: #0 })";
    if format!("{:?}", maybe_bad_span) == bad_span_debug {
        fallback
    } else {
        maybe_bad_span
    }
}

#[cfg(not(feature = "nightly"))]
fn root_span(span: Span) -> Span {
    span
}

#[cfg(feature = "nightly")]
/// There's an issue with the resolution of `__diesel_use_everything` if the
/// derive itself was generated from within a macro. This is a shitty workaround
/// until we figure out the expected behavior.
fn root_span(span: Span) -> Span {
    span.unstable().source().into()
}
<|endoftext|>


<commit_before>use position::Position;
use cppn::{Cppn, CppnNodeType};
use acyclic_network::NodeType;
use std::fmt::Debug;

/// Represents a node in the substrate. `T` stores  additional information about that node.

pub struct Node<P: Position, T: NodeType> {
    pub position: P,
    pub node_type: T,
}

pub struct Substrate<P: Position, T: NodeType> {
    nodes: Vec<Node<P, T>>,
}

pub struct LinkIterator<'a,
                        N: CppnNodeType + 'a,
                        L: Copy + Debug + Send + Sized + Into<f64> + 'a,
                        EXTID: Copy + Debug + Send + Sized + Ord + 'a,
                        P: Position + 'a,
                        T: NodeType + 'a>
{
    nodes: &'a [Node<P, T>],
    cppn: &'a mut Cppn<'a, N, L, EXTID>,
    inner: usize,
    outer: usize,
    max_distance: Option<f64>,
}

#[derive(Copy, Clone)]
pub struct Link<'a, P: Position + 'a, T: NodeType + 'a> {
    pub source: &'a Node<P, T>,
    pub target: &'a Node<P, T>,
    pub source_idx: usize,
    pub target_idx: usize,
    pub weight: f64,
    pub distance: f64,
}

impl<'a, N: CppnNodeType + 'a,
   L: Copy + Debug + Send + Sized + Into<f64> + 'a,
    EXTID: Copy + Debug + Send + Sized + Ord + 'a,
P: Position + 'a, T: NodeType + 'a> Iterator for LinkIterator<'a, N, L, EXTID, P, T> {
    type Item = Link<'a, P, T>;
    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.inner >= self.nodes.len() {
                self.inner = 0;
                self.outer += 1;
            }
            if self.outer >= self.nodes.len() {
                return None;
            }
            if self.inner == self.outer {
                self.inner += 1;
                continue;
            }

            assert!(self.inner < self.nodes.len() && self.outer < self.nodes.len() &&
                    self.inner != self.outer);
            let source = &self.nodes[self.inner];
            let target = &self.nodes[self.outer];

            // Reject invalid connections.
            if !source.node_type.accept_outgoing_links() || !target.node_type.accept_incoming_links() {
                    self.inner += 1;
                    continue;
            }

            let distance = source.position.distance(&target.position);

// reject a pair of nodes based on `max_distance`.
            if let Some(max_d) = self.max_distance {
                if distance > max_d {
                    self.inner += 1;
                    continue;
                }
            }

// Calculate the weight between source and target using the CPPN.
            let inputs_to_cppn = [source.position.coords(), target.position.coords()];
            let outputs_from_cppn = self.cppn.calculate(&inputs_to_cppn);
            assert!(outputs_from_cppn.len() == 1);
            let weight = outputs_from_cppn[0];

            let link = Link {
                source: source,
                target: target,
                source_idx: self.inner,
                target_idx: self.outer,
                weight: weight,
                distance: distance,
            };
            self.inner += 1;
            return Some(link);
        }
    }
}

impl<P: Position, T: NodeType> Substrate<P, T> {
    pub fn new() -> Substrate<P, T> {
        Substrate { nodes: Vec::new() }
    }

    pub fn nodes(&self) -> &[Node<P, T>] {
        &self.nodes
    }

    pub fn add_node(&mut self, position: P, node_type: T) {
        self.nodes.push(Node {
            position: position,
            node_type: node_type,
        });
    }

    /// Iterate over all produced links of Cppn.
    pub fn iter_links<'a, N, L, EXTID>(&'a self,
                                       cppn: &'a mut Cppn<'a, N, L, EXTID>,
                                       max_distance: Option<f64>)
                                       -> LinkIterator<'a, N, L, EXTID, P, T>
        where N: CppnNodeType,
              L: Copy + Debug + Send + Sized + Into<f64> + 'a,
              EXTID: Copy + Debug + Send + Sized + Ord + 'a
    {
        LinkIterator {
            nodes: &self.nodes,
            cppn: cppn,
            inner: 0,
            outer: 0,
            max_distance: max_distance,
        }
    }
}
<commit_msg>Include the distance between source and target neuron as input<commit_after>use position::Position;
use cppn::{Cppn, CppnNodeType};
use acyclic_network::NodeType;
use std::fmt::Debug;

/// Represents a node in the substrate. `T` stores  additional information about that node.

pub struct Node<P: Position, T: NodeType> {
    pub position: P,
    pub node_type: T,
}

pub struct Substrate<P: Position, T: NodeType> {
    nodes: Vec<Node<P, T>>,
}

pub struct LinkIterator<'a,
                        N: CppnNodeType + 'a,
                        L: Copy + Debug + Send + Sized + Into<f64> + 'a,
                        EXTID: Copy + Debug + Send + Sized + Ord + 'a,
                        P: Position + 'a,
                        T: NodeType + 'a>
{
    nodes: &'a [Node<P, T>],
    cppn: &'a mut Cppn<'a, N, L, EXTID>,
    inner: usize,
    outer: usize,
    max_distance: Option<f64>,
}

#[derive(Copy, Clone)]
pub struct Link<'a, P: Position + 'a, T: NodeType + 'a> {
    pub source: &'a Node<P, T>,
    pub target: &'a Node<P, T>,
    pub source_idx: usize,
    pub target_idx: usize,
    pub weight: f64,
    pub distance: f64,
}

impl<'a, N: CppnNodeType + 'a,
   L: Copy + Debug + Send + Sized + Into<f64> + 'a,
    EXTID: Copy + Debug + Send + Sized + Ord + 'a,
P: Position + 'a, T: NodeType + 'a> Iterator for LinkIterator<'a, N, L, EXTID, P, T> {
    type Item = Link<'a, P, T>;
    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.inner >= self.nodes.len() {
                self.inner = 0;
                self.outer += 1;
            }
            if self.outer >= self.nodes.len() {
                return None;
            }
            if self.inner == self.outer {
                self.inner += 1;
                continue;
            }

            assert!(self.inner < self.nodes.len() && self.outer < self.nodes.len() &&
                    self.inner != self.outer);
            let source = &self.nodes[self.inner];
            let target = &self.nodes[self.outer];

// Reject invalid connections.

            if !source.node_type.accept_outgoing_links() || !target.node_type.accept_incoming_links() {
                    self.inner += 1;
                    continue;
            }

            let distance = source.position.distance(&target.position);

// reject a pair of nodes based on `max_distance`.

            if let Some(max_d) = self.max_distance {
                if distance > max_d {
                    self.inner += 1;
                    continue;
                }
            }

// Calculate the weight between source and target using the CPPN.

            let distance_between: &[_] = &[distance];
            let inputs_to_cppn = [source.position.coords(), target.position.coords(), distance_between];
            let outputs_from_cppn = self.cppn.calculate(&inputs_to_cppn);
            assert!(outputs_from_cppn.len() == 1);
            let weight = outputs_from_cppn[0];

            let link = Link {
                source: source,
                target: target,
                source_idx: self.inner,
                target_idx: self.outer,
                weight: weight,
                distance: distance,
            };
            self.inner += 1;
            return Some(link);
        }
    }
}

impl<P: Position, T: NodeType> Substrate<P, T> {
    pub fn new() -> Substrate<P, T> {
        Substrate { nodes: Vec::new() }
    }

    pub fn nodes(&self) -> &[Node<P, T>] {
        &self.nodes
    }

    pub fn add_node(&mut self, position: P, node_type: T) {
        self.nodes.push(Node {
            position: position,
            node_type: node_type,
        });
    }

    /// Iterate over all produced links of Cppn.
    pub fn iter_links<'a, N, L, EXTID>(&'a self,
                                       cppn: &'a mut Cppn<'a, N, L, EXTID>,
                                       max_distance: Option<f64>)
                                       -> LinkIterator<'a, N, L, EXTID, P, T>
        where N: CppnNodeType,
              L: Copy + Debug + Send + Sized + Into<f64> + 'a,
              EXTID: Copy + Debug + Send + Sized + Ord + 'a
    {
        LinkIterator {
            nodes: &self.nodes,
            cppn: cppn,
            inner: 0,
            outer: 0,
            max_distance: max_distance,
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "sync"]
#![allow(unstable)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Alexander Fomin <xander.fomin@ya.ru>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

 /* Last synced with: sync (GNU coreutils) 8.13 */

extern crate getopts;
extern crate libc;

use getopts::{optflag, getopts, usage};

#[path = "../common/util.rs"] #[macro_use] mod util;

static NAME: &'static str = "sync";
static VERSION: &'static str = "1.0.0";

#[cfg(unix)]
mod platform {
    use super::libc;

    extern {
        fn sync() -> libc::c_void;
    }

    pub unsafe fn do_sync() -> isize {
        sync();
        0
    }
}

#[cfg(windows)]
mod platform {
    pub use super::libc;
    use std::{mem, string};
    use std::ptr::null;

    extern "system" {
        fn CreateFileA(lpFileName: *const libc::c_char,
                      dwDesiredAccess: libc::uint32_t,
                      dwShareMode: libc::uint32_t,
                      lpSecurityAttributes: *const libc::c_void, // *LPSECURITY_ATTRIBUTES
                      dwCreationDisposition: libc::uint32_t,
                      dwFlagsAndAttributes: libc::uint32_t,
                      hTemplateFile: *const libc::c_void) -> *const libc::c_void;
        fn GetDriveTypeA(lpRootPathName: *const libc::c_char) -> libc::c_uint;
        fn GetLastError() -> libc::uint32_t;
        fn FindFirstVolumeA(lpszVolumeName: *mut libc::c_char,
                            cchBufferLength: libc::uint32_t) -> *const libc::c_void;
        fn FindNextVolumeA(hFindVolume: *const libc::c_void,
                           lpszVolumeName: *mut libc::c_char,
                           cchBufferLength: libc::uint32_t) -> libc::c_int;
        fn FindVolumeClose(hFindVolume: *const libc::c_void) -> libc::c_int;
        fn FlushFileBuffers(hFile: *const libc::c_void) -> libc::c_int;
    }

    #[allow(unused_unsafe)]
    unsafe fn flush_volume(name: &str) {
        let name_buffer = name.to_c_str().as_ptr();
        if 0x00000003 == GetDriveTypeA(name_buffer) { // DRIVE_FIXED
            let sliced_name = name.slice_to(name.len() - 1); // eliminate trailing backslash
            let sliced_name_buffer = sliced_name.to_c_str().as_ptr();
            match CreateFileA(sliced_name_buffer,
                              0xC0000000, // GENERIC_WRITE
                              0x00000003, // FILE_SHARE_WRITE,
                              null(),
                              0x00000003, // OPEN_EXISTING
                              0,
                              null()) {
                _x if _x == -1 as *const libc::c_void => { // INVALID_HANDLE_VALUE
                    crash!(GetLastError(), "failed to create volume handle");
                }
                handle @ _ => {
                    if FlushFileBuffers(handle) == 0 {
                        crash!(GetLastError(), "failed to flush file buffer");
                    }
                }
            }
        }
    }

    #[allow(unused_unsafe)]
    unsafe fn find_first_volume() -> (String, *const libc::c_void) {
        let mut name: [libc::c_char; 260] = mem::uninitialized(); // MAX_PATH
        match FindFirstVolumeA(name.as_mut_ptr(),
                               name.len() as libc::uint32_t) {
            _x if _x == -1 as *const libc::c_void => { // INVALID_HANDLE_VALUE
                crash!(GetLastError(), "failed to find first volume");
            }
            handle @ _ => {
                (string::raw::from_buf(name.as_ptr() as *const u8), handle)
            }
        }
    }

    #[allow(unused_unsafe)]
    unsafe fn find_all_volumes() -> Vec<String> {
        match find_first_volume() {
            (first_volume, next_volume_handle) => {
                let mut volumes = vec![first_volume];
                loop {
                    let mut name: [libc::c_char; 260] = mem::uninitialized(); // MAX_PATH
                    match FindNextVolumeA(next_volume_handle,
                                          name.as_mut_ptr(),
                                          name.len() as libc::uint32_t) {
                        0 => {
                            match GetLastError() {
                                0x12 => { // ERROR_NO_MORE_FILES
                                    FindVolumeClose(next_volume_handle); // ignore FindVolumeClose() failures
                                    break;
                                }
                                err @ _ => {
                                    crash!(err, "failed to find next volume");
                                }
                            }
                        }
                        _ => {
                            volumes.push(string::raw::from_buf(name.as_ptr() as *const u8));
                        }
                    }
                }
                volumes
            }
        }
    }

    pub unsafe fn do_sync() -> int {
        let volumes = find_all_volumes();
        for vol in volumes.iter() {
            flush_volume(vol.as_slice());
        }
        0
    }
}

pub fn uumain(args: Vec<String>) -> isize {
    let program = &args[0];

    let options = [
        optflag("h", "help", "display this help and exit"),
        optflag("V", "version", "output version information and exit")
    ];

    let matches = match getopts(args.tail(), &options) {
        Ok(m) => { m }
        _ => { help(program.as_slice(), &options); return 1 }
    };

    if matches.opt_present("h") {
        help(program.as_slice(), &options);
        return 0
    }

    if matches.opt_present("V") {
        version();
        return 0
    }

    sync();
    0
}

fn version() {
    println!("{} (uutils) {}", NAME, VERSION);
    println!("The MIT License");
    println!("");
    println!("Author -- Alexander Fomin.");
}

fn help(program: &str, options: &[getopts::OptGroup]) {
    println!("Usage: {} [OPTION]", program);
    print!("{}", usage("Force changed blocks to disk, update the super block.", options));
}

fn sync() -> isize {
    unsafe {
        platform::do_sync()
    }
}
<commit_msg>Cleanup sync.<commit_after>#![crate_name = "sync"]
#![allow(unstable)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Alexander Fomin <xander.fomin@ya.ru>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

 /* Last synced with: sync (GNU coreutils) 8.13 */

extern crate getopts;
extern crate libc;

use getopts::{optflag, getopts, usage};

#[path = "../common/util.rs"] #[macro_use] mod util;

static NAME: &'static str = "sync";
static VERSION: &'static str = "1.0.0";

#[cfg(unix)]
mod platform {
    use super::libc;

    extern {
        fn sync() -> libc::c_void;
    }

    pub unsafe fn do_sync() -> isize {
        sync();
        0
    }
}

#[cfg(windows)]
mod platform {
    pub use super::libc;
    use std::{mem, string};
    use std::ptr::null;

    extern "system" {
        fn CreateFileA(lpFileName: *const libc::c_char,
                      dwDesiredAccess: libc::uint32_t,
                      dwShareMode: libc::uint32_t,
                      lpSecurityAttributes: *const libc::c_void, // *LPSECURITY_ATTRIBUTES
                      dwCreationDisposition: libc::uint32_t,
                      dwFlagsAndAttributes: libc::uint32_t,
                      hTemplateFile: *const libc::c_void) -> *const libc::c_void;
        fn GetDriveTypeA(lpRootPathName: *const libc::c_char) -> libc::c_uint;
        fn GetLastError() -> libc::uint32_t;
        fn FindFirstVolumeA(lpszVolumeName: *mut libc::c_char,
                            cchBufferLength: libc::uint32_t) -> *const libc::c_void;
        fn FindNextVolumeA(hFindVolume: *const libc::c_void,
                           lpszVolumeName: *mut libc::c_char,
                           cchBufferLength: libc::uint32_t) -> libc::c_int;
        fn FindVolumeClose(hFindVolume: *const libc::c_void) -> libc::c_int;
        fn FlushFileBuffers(hFile: *const libc::c_void) -> libc::c_int;
    }

    #[allow(unused_unsafe)]
    unsafe fn flush_volume(name: &str) {
        let name_buffer = name.to_c_str().as_ptr();
        if 0x00000003 == GetDriveTypeA(name_buffer) { // DRIVE_FIXED
            let sliced_name = &name[..name.len() - 1]; // eliminate trailing backslash
            let sliced_name_buffer = sliced_name.to_c_str().as_ptr();
            match CreateFileA(sliced_name_buffer,
                              0xC0000000, // GENERIC_WRITE
                              0x00000003, // FILE_SHARE_WRITE,
                              null(),
                              0x00000003, // OPEN_EXISTING
                              0,
                              null()) {
                -1 => { // INVALID_HANDLE_VALUE
                    crash!(GetLastError(), "failed to create volume handle");
                }
                handle => {
                    if FlushFileBuffers(handle) == 0 {
                        crash!(GetLastError(), "failed to flush file buffer");
                    }
                }
            }
        }
    }

    #[allow(unused_unsafe)]
    unsafe fn find_first_volume() -> (String, *const libc::c_void) {
        let mut name: [libc::c_char; 260] = mem::uninitialized(); // MAX_PATH
        match FindFirstVolumeA(name.as_mut_ptr(),
                               name.len() as libc::uint32_t) {
            -1 => { // INVALID_HANDLE_VALUE
                crash!(GetLastError(), "failed to find first volume");
            }
            handle => {
                (string::raw::from_buf(name.as_ptr() as *const u8), handle)
            }
        }
    }

    #[allow(unused_unsafe)]
    unsafe fn find_all_volumes() -> Vec<String> {
        match find_first_volume() {
            (first_volume, next_volume_handle) => {
                let mut volumes = vec![first_volume];
                loop {
                    let mut name: [libc::c_char; 260] = mem::uninitialized(); // MAX_PATH
                    match FindNextVolumeA(next_volume_handle,
                                          name.as_mut_ptr(),
                                          name.len() as libc::uint32_t) {
                        0 => {
                            match GetLastError() {
                                0x12 => { // ERROR_NO_MORE_FILES
                                    FindVolumeClose(next_volume_handle); // ignore FindVolumeClose() failures
                                    break;
                                }
                                err => {
                                    crash!(err, "failed to find next volume");
                                }
                            }
                        }
                        _ => {
                            volumes.push(string::raw::from_buf(name.as_ptr() as *const u8));
                        }
                    }
                }
                volumes
            }
        }
    }

    pub unsafe fn do_sync() -> int {
        let volumes = find_all_volumes();
        for vol in volumes.iter() {
            flush_volume(&vol);
        }
        0
    }
}

pub fn uumain(args: Vec<String>) -> isize {
    let program = &args[0][];

    let options = [
        optflag("h", "help", "display this help and exit"),
        optflag("V", "version", "output version information and exit")
    ];

    let matches = match getopts(args.tail(), &options) {
        Ok(m) => { m }
        _ => { help(program, &options); return 1 }
    };

    if matches.opt_present("h") {
        help(program, &options);
        return 0
    }

    if matches.opt_present("V") {
        version();
        return 0
    }

    sync();
    0
}

fn version() {
    println!("{} (uutils) {}", NAME, VERSION);
    println!("The MIT License");
    println!("");
    println!("Author -- Alexander Fomin.");
}

fn help(program: &str, options: &[getopts::OptGroup]) {
    println!("Usage: {} [OPTION]", program);
    print!("{}", usage("Force changed blocks to disk, update the super block.", options));
}

fn sync() -> isize {
    unsafe {
        platform::do_sync()
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 by Stacy Prowell.  All rights reserved.
//
// Licensed under the BSD 2-Clause license.  See the file LICENSE
// that is part of this distribution.  This file may not be copied,
// modified, or distributed except according to those terms.extern

//! Provide basic definitions of terms.

use std::collections::BitVec;
//use std::tuple::Tuple1;

/// Represents root terms.
struct Root ( () );
struct Any ( () );
struct ENone ( () );
#[derive(Debug)]
struct EString( String ) ;
struct Symbol( String );
#[derive(Debug)]
struct Integer( isize );
struct Float( f64 );
struct BitString( BitVec );
struct Boolean( bool );

trait Termable<T>{
    fn new(value: T) -> Self;
    fn native(&self) -> &T;
}

impl Termable<String> for EString{
    fn new(value: String) -> EString{
        EString(value)
    }
    fn native(&self) -> &String {
        &self.0
    }
}

impl Termable<isize> for Integer{
    fn new(value: isize) -> Integer{
        Integer(value)
    }
    fn native(&self) -> &isize {
        &self.0
    }
}

#[derive(Debug)]
struct Term<T> {
    value: T,
}

impl<T> Term<T>
{
    pub fn new<U>(t: U) -> Term<U> where U: Termable<T> {
        Term { value: t }
    }
    pub fn unwrap(&self) -> &T {
        &self.value
    }
}

#[test]
fn term_type_check_test() -> (){
    let termable = EString::new("Test".to_string());
    let mut stringterm = Term::new(termable);
    let integerterm = Term::new(Integer(3));
    // Uncomment the following line to see the type checker assist in action
    // stringterm = integerterm;

    //Nested terms don't work right now
    // let nestedterm = Term::new(Term::new(Integer(3)));
    let stringval = &stringterm.unwrap().native();
    panic!("Intentionial panic. {:?}", stringval);
}

<commit_msg>Got nested terms working.<commit_after>// Copyright (c) 2015 by Stacy Prowell.  All rights reserved.
//
// Licensed under the BSD 2-Clause license.  See the file LICENSE
// that is part of this distribution.  This file may not be copied,
// modified, or distributed except according to those terms.extern

//! Provide basic definitions of terms.

use std::collections::BitVec;
//use std::tuple::Tuple1;

/// Represents root terms.
struct Root ( () );
struct Any ( () );
struct ENone ( () );
#[derive(Debug)]
struct EString( String ) ;
struct Symbol( String );
#[derive(Debug)]
struct Integer( isize );
struct Float( f64 );
struct BitString( BitVec );
struct Boolean( bool );

trait Termable<T>{
    fn new(value: T) -> Self;
    fn native(&self) -> &T;
}

impl Termable<String> for EString{
    fn new(value: String) -> EString{
        EString(value)
    }
    fn native(&self) -> &String {
        &self.0
    }
}

impl Termable<isize> for Integer{
    fn new(value: isize) -> Integer{
        Integer(value)
    }
    fn native(&self) -> &isize {
        &self.0
    }
}

#[derive(Debug)]
struct Term<T> {
    value: T,
}

impl<T> Termable<T> for Term<T>{
    fn new(t: T) -> Term<T> {
        Term { value: t }
    }
    fn native(&self) -> &T { &self.value }
}

impl<T> Term<T>
{
    pub fn new<U>(t: U) -> Term<U> where U: Termable<T> {
        Term { value: t }
    }
    pub fn unwrap(&self) -> &T {
        &self.value
    }
}

#[test]
fn term_type_check_test() -> (){
    let termable = EString::new("Test".to_string());
    let mut stringterm = Term::new(termable);
    let integerterm = Term::new(Integer(3));
    // Uncomment the following line to see the type checker assist in action
    // stringterm = integerterm;
    // The following line shoudl fail to compile
    // let failterm = Term::new(3);

    //Nested terms don't work right now
    let nestedterm = Term::new(Term::new(Integer(3)));
    let stringval = &stringterm.unwrap().native();
    panic!("Intentionial panic. {:?}", stringval);
}

<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{Read, Seek, Cursor};
use std::io::{SeekFrom, Error, ErrorKind};
use std::mem::transmute;

extern crate uuid;
extern crate byteorder;
use self::byteorder::{LittleEndian, ReadBytesExt, BigEndian};
use self::uuid::Uuid;

#[derive(Debug)]
pub struct Header {
    pub signature: String, // EFI PART
    pub revision: u32, // 00 00 01 00
    pub header_size_le: u32, // little endian
    pub crc32: u32,
    pub reserved: u32, // must be 0
    pub current_lba: u64,
    pub backup_lba: u64,
    pub first_usable: u64,
    pub last_usable: u64,
    pub disk_guid: uuid::Uuid,
    pub start_lba: u64,
    pub num_parts: u32,
    pub part_size: u32, // usually 128
    pub crc32_parts: u32,
}

fn parse_uuid(rdr: &mut Cursor<&[u8]>) -> Result<Uuid, Error> {
    //let mut rdr = Cursor::new(bytes);
    let d1: u32 = rdr.read_u32::<LittleEndian>()?;
    let d2: u16 = rdr.read_u16::<LittleEndian>()?;
    let d3: u16 = rdr.read_u16::<LittleEndian>()?;
    let mut d4: [u8; 8] = [0; 8];
    let _ = rdr.read_exact(&mut d4);
    let thing = Uuid::from_fields(d1, d2, d3, &d4);
    println!("{:?}", thing);
    match thing {
        Ok(uuid) => Ok(uuid),
        Err(_) => Err(Error::new(ErrorKind::Other, "Invalid Disk UUID?")),
    }
}

pub fn read_header2(path: &String) -> Result<Header, Error> {
    let mut file = File::open(path)?;
    let _ = file.seek(SeekFrom::Start(512));

    let mut hdr: [u8; 92] = [0; 92];

    let _ = file.read_exact(&mut hdr);
    let mut reader = Cursor::new(&hdr[..]);

    let sig = reader.read_u64::<LittleEndian>()?;
    let b: [u8; 8] = unsafe { transmute(sig) };
    let sigstr = String::from_utf8_lossy(&b);

    if sigstr != "EFI PART" {
        return Err(Error::new(ErrorKind::Other, "Invalid GPT Signature."));
    };

    let h = Header {
        signature:      sigstr.to_string(),
        revision:       reader.read_u32::<LittleEndian>()?,
        header_size_le: reader.read_u32::<LittleEndian>()?,
        crc32:          reader.read_u32::<LittleEndian>()?,
        reserved:       reader.read_u32::<LittleEndian>()?,
        current_lba:    reader.read_u64::<LittleEndian>()?,
        backup_lba:     reader.read_u64::<LittleEndian>()?,
        first_usable:   reader.read_u64::<LittleEndian>()?,
        last_usable:    reader.read_u64::<LittleEndian>()?,
        disk_guid:      parse_uuid(&mut reader)?,
        start_lba:      reader.read_u64::<LittleEndian>()?,
        num_parts:      reader.read_u32::<LittleEndian>()?,
        part_size:      reader.read_u32::<LittleEndian>()?,
        crc32_parts:    reader.read_u32::<LittleEndian>()?,
    };

    Ok(h)
}
/*
pub fn read_header(path:&String) -> Result<Header, Error>
{
	let mut file = File::open(path)?;
	let _ = file.seek(SeekFrom::Start(512))?;

	let mut signature: [u8;8] = [0;8];
	let _ = file.read_exact(&mut signature);
	let sigstr = String::from_utf8_lossy(&signature);
	if sigstr.as_ref() != "EFI PART" { return Err(Error::new(ErrorKind::Other,
	"Invalid GPT Signature")) };

	let mut revision: [u8; 4] = [0; 4];
	let mut header_size_le: [u8;4] = [0; 4];
	let mut crc32: [u8;4] = [0; 4];
	let mut reserved: [u8;4] = [0; 4];
	let mut current_lba: [u8;8] = [0; 8];
	let mut backup_lba: [u8;8] = [0; 8];
	let mut first_usable: [u8;8] = [0; 8];
	let mut last_usable: [u8;8] = [0; 8];
	let mut disk_guid: [u8;16] = [0; 16];
	let mut start_lba: [u8; 8] = [0; 8];
	let mut num_parts: [u8; 4] = [0; 4];
	let mut part_size: [u8; 4]= [0; 4];
	let mut crc32_parts: [u8; 4] = [0; 4];

	let _ = file.read_exact(&mut revision);
	let _ = file.read_exact(&mut header_size_le);
	let _ = file.read_exact(&mut crc32);
	let _ = file.read_exact(&mut reserved);
	let _ = file.read_exact(&mut current_lba);
	let _ = file.read_exact(&mut backup_lba);
	let _ = file.read_exact(&mut first_usable);
	let _ = file.read_exact(&mut last_usable);
	let _ = file.read_exact(&mut disk_guid);
	let _ = file.read_exact(&mut start_lba);
	let _ = file.read_exact(&mut num_parts);
	let _ = file.read_exact(&mut part_size);
	let _ = file.read_exact(&mut crc32_parts);

	return Ok(Header{
		signature: signature,
		revision: revision,
		header_size_le: header_size_le,
		crc32: crc32,
		reserved: reserved,
		current_lba: current_lba,
		backup_lba: backup_lba,
		first_usable: first_usable,
		last_usable: last_usable,
		disk_guid: parse_uuid(&disk_guid)?,
		start_lba: start_lba,
		num_parts: num_parts,
		part_size: part_size,
		crc32_parts: crc32_parts
	});
}
*/
<commit_msg>fixed signature. fixed uuid.<commit_after>use std::fs::File;
use std::io::{Read, Seek, Cursor};
use std::io::{SeekFrom, Error, ErrorKind};
use std::mem::transmute;

extern crate uuid;
extern crate byteorder;
use self::byteorder::{LittleEndian, ReadBytesExt, BigEndian};
use self::uuid::Uuid;

#[derive(Debug)]
pub struct Header {
    pub signature: String, // EFI PART
    pub revision: u32, // 00 00 01 00
    pub header_size_le: u32, // little endian
    pub crc32: u32,
    pub reserved: u32, // must be 0
    pub current_lba: u64,
    pub backup_lba: u64,
    pub first_usable: u64,
    pub last_usable: u64,
    pub disk_guid: uuid::Uuid,
    pub start_lba: u64,
    pub num_parts: u32,
    pub part_size: u32, // usually 128
    pub crc32_parts: u32,
}

fn parse_uuid(rdr: &mut Cursor<&[u8]>) -> Result<Uuid, Error> {
    //let mut rdr = Cursor::new(bytes);
    let d1: u32 = rdr.read_u32::<LittleEndian>()?;
    let d2: u16 = rdr.read_u16::<LittleEndian>()?;
    let d3: u16 = rdr.read_u16::<LittleEndian>()?;
    let mut d4: [u8; 8] = [0; 8];
    let _ = rdr.read_exact(&mut d4);
    let thing = Uuid::from_fields(d1, d2, d3, &d4);

    match thing {
        Ok(uuid) => Ok(uuid),
        Err(_) => Err(Error::new(ErrorKind::Other, "Invalid Disk UUID?")),
    }
}

pub fn read_header2(path: &String) -> Result<Header, Error> {
    let mut file = File::open(path)?;
    let _ = file.seek(SeekFrom::Start(512));

    let mut hdr: [u8; 92] = [0; 92];

    let _ = file.read_exact(&mut hdr);
    let mut reader = Cursor::new(&hdr[..]);

    // let sigstr = reader.read_u64::<LittleEndian>()?.to_string();
    let sig = reader.read_u64::<LittleEndian>()?;
    let b: [u8; 8] = unsafe { transmute(sig) };
    let sigstr = String::from_utf8_lossy(&b);

    if sigstr != "EFI PART" {
        return Err(Error::new(ErrorKind::Other, "Invalid GPT Signature."));
    };

    let h = Header {
        signature:      sigstr.to_string(),
        revision:       reader.read_u32::<LittleEndian>()?,
        header_size_le: reader.read_u32::<LittleEndian>()?,
        crc32:          reader.read_u32::<LittleEndian>()?,
        reserved:       reader.read_u32::<LittleEndian>()?,
        current_lba:    reader.read_u64::<LittleEndian>()?,
        backup_lba:     reader.read_u64::<LittleEndian>()?,
        first_usable:   reader.read_u64::<LittleEndian>()?,
        last_usable:    reader.read_u64::<LittleEndian>()?,
        disk_guid:      parse_uuid(&mut reader)?,
        start_lba:      reader.read_u64::<LittleEndian>()?,
        num_parts:      reader.read_u32::<LittleEndian>()?,
        part_size:      reader.read_u32::<LittleEndian>()?,
        crc32_parts:    reader.read_u32::<LittleEndian>()?,
    };

    Ok(h)
}
/*
pub fn read_header(path:&String) -> Result<Header, Error>
{
	let mut file = File::open(path)?;
	let _ = file.seek(SeekFrom::Start(512))?;

	let mut signature: [u8;8] = [0;8];
	let _ = file.read_exact(&mut signature);
	let sigstr = String::from_utf8_lossy(&signature);
	if sigstr.as_ref() != "EFI PART" { return Err(Error::new(ErrorKind::Other,
	"Invalid GPT Signature")) };

	let mut revision: [u8; 4] = [0; 4];
	let mut header_size_le: [u8;4] = [0; 4];
	let mut crc32: [u8;4] = [0; 4];
	let mut reserved: [u8;4] = [0; 4];
	let mut current_lba: [u8;8] = [0; 8];
	let mut backup_lba: [u8;8] = [0; 8];
	let mut first_usable: [u8;8] = [0; 8];
	let mut last_usable: [u8;8] = [0; 8];
	let mut disk_guid: [u8;16] = [0; 16];
	let mut start_lba: [u8; 8] = [0; 8];
	let mut num_parts: [u8; 4] = [0; 4];
	let mut part_size: [u8; 4]= [0; 4];
	let mut crc32_parts: [u8; 4] = [0; 4];

	let _ = file.read_exact(&mut revision);
	let _ = file.read_exact(&mut header_size_le);
	let _ = file.read_exact(&mut crc32);
	let _ = file.read_exact(&mut reserved);
	let _ = file.read_exact(&mut current_lba);
	let _ = file.read_exact(&mut backup_lba);
	let _ = file.read_exact(&mut first_usable);
	let _ = file.read_exact(&mut last_usable);
	let _ = file.read_exact(&mut disk_guid);
	let _ = file.read_exact(&mut start_lba);
	let _ = file.read_exact(&mut num_parts);
	let _ = file.read_exact(&mut part_size);
	let _ = file.read_exact(&mut crc32_parts);

	return Ok(Header{
		signature: signature,
		revision: revision,
		header_size_le: header_size_le,
		crc32: crc32,
		reserved: reserved,
		current_lba: current_lba,
		backup_lba: backup_lba,
		first_usable: first_usable,
		last_usable: last_usable,
		disk_guid: parse_uuid(&disk_guid)?,
		start_lba: start_lba,
		num_parts: num_parts,
		part_size: part_size,
		crc32_parts: crc32_parts
	});
}
*/
<|endoftext|>


<commit_before>// tokenizer.rs
// The tokenizer takes an incoming string and constructs a list of tokens
// for the string. The tokens are used to give logical structure so that
// we can parse a bit better.

// A Token is any character in the regular expression that may have a special
// meaning. If it doesn't, then it gets parsed as a char.
#[derive(Debug, PartialEq, Clone)]
pub enum Token {
    Char(char),
    Wildcard,
    NoneOrMore,
    OneOrMore,
    NoneOrOne,
    NumeralRange,
    LowercaseRange,
    UppercaseRange,
    OpenBracket,
    ClosedBracket,
    BracketInversion,
    OpenParen,
    ClosedParen,
}

pub fn parse(s: String) -> Result<Vec<Token>, &'static str> {
    let mut iter = s.chars();
    let mut tokens : Vec<Token> = Vec::new();
    loop {
        let next_char = iter.next();
        if next_char.is_none() {
            break;
        }

        let token = match next_char.unwrap() {
            '.' => Token::Wildcard,
            '*' => Token::NoneOrMore,
            '+' => Token::OneOrMore,
            '?' => Token::NoneOrOne,
            '\\' => {
                if let Some(c) = iter.next() {
                    Token::Char(c)
                } else {
                    return Err("Parse error: Escaped character escapes nothing");
                }
            },
            '[' => Token::OpenBracket,
            ']' => Token::ClosedBracket,
            '(' => Token::OpenParen,
            ')' => Token::ClosedParen,
            '0' => {
                let next_chars: Vec<char> = iter.clone().take(2).collect();
                if next_chars == vec!['-', '9'] {
                    iter.next();
                    iter.next();
                    Token::NumeralRange
                } else {
                    Token::Char('0')
                }
            }

            'a' => {
                let next_chars: Vec<char> = iter.clone().take(2).collect();
                if next_chars == vec!['-', 'z'] {
                    iter.next();
                    iter.next();
                    Token::LowercaseRange
                } else {
                    Token::Char('a')
                }
            }

            'A' => {
                let next_chars: Vec<char> = iter.clone().take(2).collect();
                if next_chars == vec!['-', 'Z'] {
                    iter.next();
                    iter.next();
                    Token::UppercaseRange
                } else {
                    Token::Char('A')
                }
            }

            c => {
                tokens.last().map_or_else(|| Token::Char(c), |last_token| {
                    if *last_token == Token::OpenBracket && c == '^' {
                        Token::BracketInversion
                    } else {
                        Token::Char(c)
                    }
                })
            }
        };

        tokens.push(token);
    }

    // Return the tokens
    Ok(tokens)
}

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

    #[test]
    fn it_can_parse_empty_strings() {
        assert_eq!(parse(String::from("")), Ok(vec![]));
    }

    #[test]
    fn it_can_parse_simple_strings() {
        assert_eq!(parse(String::from("hello")),
                   Ok(vec![Token::Char('h'),
                           Token::Char('e'),
                           Token::Char('l'),
                           Token::Char('l'),
                           Token::Char('o')]));
    }

    #[test]
    fn it_can_recognize_wildcards() {
        assert_eq!(parse(String::from("he.lo")),
                   Ok(vec![Token::Char('h'),
                           Token::Char('e'),
                           Token::Wildcard,
                           Token::Char('l'),
                           Token::Char('o')]));

        assert_eq!(parse(String::from(".e.lo")),
                   Ok(vec![Token::Wildcard,
                           Token::Char('e'),
                           Token::Wildcard,
                           Token::Char('l'),
                           Token::Char('o')]));

        assert_eq!(parse(String::from(".")), Ok(vec![Token::Wildcard]));
    }

    #[test]
    fn it_can_recognize_stars() {
        assert_eq!(parse(String::from("he*lo")),
                   Ok(vec![Token::Char('h'),
                           Token::Char('e'),
                           Token::NoneOrMore,
                           Token::Char('l'),
                           Token::Char('o')]));

        assert_eq!(parse(String::from(".e*lo")),
                   Ok(vec![Token::Wildcard,
                           Token::Char('e'),
                           Token::NoneOrMore,
                           Token::Char('l'),
                           Token::Char('o')]));

        assert_eq!(parse(String::from(".*")), Ok(vec![Token::Wildcard,
                                                      Token::NoneOrMore]));
    }

    #[test]
    fn it_can_recognize_pluses() {
        assert_eq!(parse(String::from("he+lo")),
                   Ok(vec![Token::Char('h'),
                           Token::Char('e'),
                           Token::OneOrMore,
                           Token::Char('l'),
                           Token::Char('o')]));

        assert_eq!(parse(String::from("*e+lo")),
                   Ok(vec![Token::NoneOrMore,
                           Token::Char('e'),
                           Token::OneOrMore,
                           Token::Char('l'),
                           Token::Char('o')]));

        assert_eq!(parse(String::from(".+")), Ok(vec![Token::Wildcard,
                                                      Token::OneOrMore]));

        // These aren't valid expressions, but they are valid syntax...
        assert_eq!(parse(String::from("*+*")), Ok(vec![Token::NoneOrMore,
                                                       Token::OneOrMore,
                                                       Token::NoneOrMore]));
    }

    #[test]
    fn it_can_recognize_qmarks() {
        assert_eq!(parse(String::from("?????")),
                   Ok(vec![Token::NoneOrOne,
                           Token::NoneOrOne,
                           Token::NoneOrOne,
                           Token::NoneOrOne,
                           Token::NoneOrOne]));

        assert_eq!(parse(String::from("-?")),
                   Ok(vec![Token::Char('-'),
                           Token::NoneOrOne]));

        assert_eq!(parse(String::from("hello? it's me.")),
                   Ok(vec![Token::Char('h'),
                           Token::Char('e'),
                           Token::Char('l'),
                           Token::Char('l'),
                           Token::Char('o'),
                           Token::NoneOrOne,
                           Token::Char(' '),
                           Token::Char('i'),
                           Token::Char('t'),
                           Token::Char('\''),
                           Token::Char('s'),
                           Token::Char(' '),
                           Token::Char('m'),
                           Token::Char('e'),
                           Token::Wildcard]));
    }

    #[test]
    fn it_can_escape_characters() {
        assert_eq!(parse(String::from("\\?\\.\\+\\*\\a")),
                   Ok(vec![Token::Char('?'),
                           Token::Char('.'),
                           Token::Char('+'),
                           Token::Char('*'),
                           Token::Char('a')]));

        assert_eq!(parse(String::from("\\\"")),
                   Ok(vec![Token::Char('\"')]));
    }

    #[test]
    fn it_fails_if_escape_is_at_end_of_string() {
        assert!(parse(String::from("\\")).is_err());
        assert!(parse(String::from("hello\\")).is_err());
        assert!(!parse(String::from("hel\\lo")).is_err());
    }

    #[test]
    fn it_recognizes_numeral_ranges() {
        assert_eq!(parse(String::from("0123456789")),
                   Ok(vec![Token::Char('0'),
                           Token::Char('1'),
                           Token::Char('2'),
                           Token::Char('3'),
                           Token::Char('4'),
                           Token::Char('5'),
                           Token::Char('6'),
                           Token::Char('7'),
                           Token::Char('8'),
                           Token::Char('9')]));

        assert_eq!(parse(String::from("0-10-20-9")),
                   Ok(vec![Token::Char('0'),
                           Token::Char('-'),
                           Token::Char('1'),
                           Token::Char('0'),
                           Token::Char('-'),
                           Token::Char('2'),
                           Token::NumeralRange]));

        assert_eq!(parse(String::from("9-0-9")),
                   Ok(vec![Token::Char('9'),
                           Token::Char('-'),
                           Token::NumeralRange]));
    }

    #[test]
    fn it_recognizes_lowercase_ranges() {
        assert_eq!(parse(String::from("az")),
                   Ok(vec![Token::Char('a'),
                           Token::Char('z')]));

        assert_eq!(parse(String::from("0-9a-z")),
                   Ok(vec![Token::NumeralRange,
                           Token::LowercaseRange]));

        assert_eq!(parse(String::from("a-z0-9")),
                   Ok(vec![Token::LowercaseRange,
                           Token::NumeralRange]));

        assert_eq!(parse(String::from("z-a-z")),
                   Ok(vec![Token::Char('z'),
                           Token::Char('-'),
                           Token::LowercaseRange]));
    }

    #[test]
    fn it_recognizes_uppercase_ranges() {
        assert_eq!(parse(String::from("AZ")),
                   Ok(vec![Token::Char('A'),
                           Token::Char('Z')]));

        assert_eq!(parse(String::from("0-9a-Z")),
                   Ok(vec![Token::NumeralRange,
                           Token::Char('a'),
                           Token::Char('-'),
                           Token::Char('Z')]));

        assert_eq!(parse(String::from("A-Za-z0-9")),
                   Ok(vec![Token::UppercaseRange,
                           Token::LowercaseRange,
                           Token::NumeralRange]));

        assert_eq!(parse(String::from("z-A\\-Z")),
                   Ok(vec![Token::Char('z'),
                           Token::Char('-'),
                           Token::Char('A'),
                           Token::Char('-'),
                           Token::Char('Z')]));

        assert_eq!(parse(String::from("z-A-Z")),
                   Ok(vec![Token::Char('z'),
                           Token::Char('-'),
                           Token::UppercaseRange]));
    }

    #[test]
    fn it_recognizes_brackets() {
        assert_eq!(parse(String::from("[")),
                   Ok(vec![Token::OpenBracket]));

        assert_eq!(parse(String::from("][")),
                   Ok(vec![Token::ClosedBracket,
                           Token::OpenBracket]));

        assert_eq!(parse(String::from("[]")),
                   Ok(vec![Token::OpenBracket,
                           Token::ClosedBracket]));

        assert_eq!(parse(String::from("[0-9]")),
                   Ok(vec![Token::OpenBracket,
                           Token::NumeralRange,
                           Token::ClosedBracket]));
    }

    #[test]
    fn it_properly_handles_bracket_inversion() {
        assert_eq!(parse(String::from("[^")),
                   Ok(vec![Token::OpenBracket,
                           Token::BracketInversion]));

        assert_eq!(parse(String::from("]^[")),
                   Ok(vec![Token::ClosedBracket,
                           Token::Char('^'),
                           Token::OpenBracket]));

        assert_eq!(parse(String::from("^[^]^")),
                   Ok(vec![Token::Char('^'),
                           Token::OpenBracket,
                           Token::BracketInversion,
                           Token::ClosedBracket,
                           Token::Char('^')]));

        assert_eq!(parse(String::from("[^0-9]")),
                   Ok(vec![Token::OpenBracket,
                           Token::BracketInversion,
                           Token::NumeralRange,
                           Token::ClosedBracket]));

        assert_eq!(parse(String::from("[0^-9]")),
                   Ok(vec![Token::OpenBracket,
                           Token::Char('0'),
                           Token::Char('^'),
                           Token::Char('-'),
                           Token::Char('9'),
                           Token::ClosedBracket]));

        assert_eq!(parse(String::from("[0-9^]")),
                   Ok(vec![Token::OpenBracket,
                           Token::NumeralRange,
                           Token::Char('^'),
                           Token::ClosedBracket]));

        assert_eq!(parse(String::from("[\\^-9]")),
                   Ok(vec![Token::OpenBracket,
                           Token::Char('^'),
                           Token::Char('-'),
                           Token::Char('9'),
                           Token::ClosedBracket]));

        assert_eq!(parse(String::from("^[-9]")),
                   Ok(vec![Token::Char('^'),
                           Token::OpenBracket,
                           Token::Char('-'),
                           Token::Char('9'),
                           Token::ClosedBracket]));
    }

    #[test]
    fn it_recognizes_parentheses() {
        assert_eq!(parse(String::from("(")),
                   Ok(vec!(Token::OpenParen)));

        assert_eq!(parse(String::from(")(")),
                   Ok(vec!(Token::ClosedParen,
                           Token::OpenParen)));

        assert_eq!(parse(String::from("()")),
                   Ok(vec!(Token::OpenParen,
                           Token::ClosedParen)));

        assert_eq!(parse(String::from("(0-9)")),
                   Ok(vec!(Token::OpenParen,
                           Token::NumeralRange,
                           Token::ClosedParen)));
    }
}
<commit_msg>Allow parsing of static strings<commit_after>// tokenizer.rs
// The tokenizer takes an incoming string and constructs a list of tokens
// for the string. The tokens are used to give logical structure so that
// we can parse a bit better.

// A Token is any character in the regular expression that may have a special
// meaning. If it doesn't, then it gets parsed as a char.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Token {
    Char(char),
    Wildcard,
    NoneOrMore,
    OneOrMore,
    NoneOrOne,
    NumeralRange,
    LowercaseRange,
    UppercaseRange,
    OpenBracket,
    ClosedBracket,
    BracketInversion,
    OpenParen,
    ClosedParen,
}

pub fn parse_string(s: String) -> Result<Vec<Token>, &'static str> {
    let mut iter = s.chars();
    let mut tokens : Vec<Token> = Vec::new();
    loop {
        let next_char = iter.next();
        if next_char.is_none() {
            break;
        }

        let token = match next_char.unwrap() {
            '.' => Token::Wildcard,
            '*' => Token::NoneOrMore,
            '+' => Token::OneOrMore,
            '?' => Token::NoneOrOne,
            '\\' => {
                if let Some(c) = iter.next() {
                    Token::Char(c)
                } else {
                    return Err("Parse error: Escaped character escapes nothing");
                }
            },
            '[' => Token::OpenBracket,
            ']' => Token::ClosedBracket,
            '(' => Token::OpenParen,
            ')' => Token::ClosedParen,
            '0' => {
                let next_chars: Vec<char> = iter.clone().take(2).collect();
                if next_chars == vec!['-', '9'] {
                    iter.next();
                    iter.next();
                    Token::NumeralRange
                } else {
                    Token::Char('0')
                }
            }

            'a' => {
                let next_chars: Vec<char> = iter.clone().take(2).collect();
                if next_chars == vec!['-', 'z'] {
                    iter.next();
                    iter.next();
                    Token::LowercaseRange
                } else {
                    Token::Char('a')
                }
            }

            'A' => {
                let next_chars: Vec<char> = iter.clone().take(2).collect();
                if next_chars == vec!['-', 'Z'] {
                    iter.next();
                    iter.next();
                    Token::UppercaseRange
                } else {
                    Token::Char('A')
                }
            }

            c => {
                tokens.last().map_or_else(|| Token::Char(c), |last_token| {
                    if *last_token == Token::OpenBracket && c == '^' {
                        Token::BracketInversion
                    } else {
                        Token::Char(c)
                    }
                })
            }
        };

        tokens.push(token);
    }

    // Return the tokens
    Ok(tokens)
}

pub fn parse(s: &str) -> Result<Vec<Token>, &'static str> {
    parse_string(s.to_string())
}

pub fn unsafe_parse(s: &str) -> Vec<Token> {
    match parse(s) {
        Err(s) => panic!(s),
        Ok(t) => t
    }
}

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

    #[test]
    fn it_can_parse_empty_strings() {
        assert_eq!(parse(""), Ok(vec![]));
    }

    #[test]
    fn it_can_parse_simple_strings() {
        assert_eq!(parse("hello"),
                   Ok(vec![Token::Char('h'),
                           Token::Char('e'),
                           Token::Char('l'),
                           Token::Char('l'),
                           Token::Char('o')]));
    }

    #[test]
    fn it_can_recognize_wildcards() {
        assert_eq!(parse("he.lo"),
                   Ok(vec![Token::Char('h'),
                           Token::Char('e'),
                           Token::Wildcard,
                           Token::Char('l'),
                           Token::Char('o')]));

        assert_eq!(parse(".e.lo"),
                   Ok(vec![Token::Wildcard,
                           Token::Char('e'),
                           Token::Wildcard,
                           Token::Char('l'),
                           Token::Char('o')]));

        assert_eq!(parse("."), Ok(vec![Token::Wildcard]));
    }

    #[test]
    fn it_can_recognize_stars() {
        assert_eq!(parse("he*lo"),
                   Ok(vec![Token::Char('h'),
                           Token::Char('e'),
                           Token::NoneOrMore,
                           Token::Char('l'),
                           Token::Char('o')]));

        assert_eq!(parse(".e*lo"),
                   Ok(vec![Token::Wildcard,
                           Token::Char('e'),
                           Token::NoneOrMore,
                           Token::Char('l'),
                           Token::Char('o')]));

        assert_eq!(parse(".*"), Ok(vec![Token::Wildcard,
                                                      Token::NoneOrMore]));
    }

    #[test]
    fn it_can_recognize_pluses() {
        assert_eq!(parse("he+lo"),
                   Ok(vec![Token::Char('h'),
                           Token::Char('e'),
                           Token::OneOrMore,
                           Token::Char('l'),
                           Token::Char('o')]));

        assert_eq!(parse("*e+lo"),
                   Ok(vec![Token::NoneOrMore,
                           Token::Char('e'),
                           Token::OneOrMore,
                           Token::Char('l'),
                           Token::Char('o')]));

        assert_eq!(parse(".+"), Ok(vec![Token::Wildcard,
                                                      Token::OneOrMore]));

        // These aren't valid expressions, but they are valid syntax...
        assert_eq!(parse("*+*"), Ok(vec![Token::NoneOrMore,
                                                       Token::OneOrMore,
                                                       Token::NoneOrMore]));
    }

    #[test]
    fn it_can_recognize_qmarks() {
        assert_eq!(parse("?????"),
                   Ok(vec![Token::NoneOrOne,
                           Token::NoneOrOne,
                           Token::NoneOrOne,
                           Token::NoneOrOne,
                           Token::NoneOrOne]));

        assert_eq!(parse("-?"),
                   Ok(vec![Token::Char('-'),
                           Token::NoneOrOne]));

        assert_eq!(parse("hello? it's me."),
                   Ok(vec![Token::Char('h'),
                           Token::Char('e'),
                           Token::Char('l'),
                           Token::Char('l'),
                           Token::Char('o'),
                           Token::NoneOrOne,
                           Token::Char(' '),
                           Token::Char('i'),
                           Token::Char('t'),
                           Token::Char('\''),
                           Token::Char('s'),
                           Token::Char(' '),
                           Token::Char('m'),
                           Token::Char('e'),
                           Token::Wildcard]));
    }

    #[test]
    fn it_can_escape_characters() {
        assert_eq!(parse("\\?\\.\\+\\*\\a"),
                   Ok(vec![Token::Char('?'),
                           Token::Char('.'),
                           Token::Char('+'),
                           Token::Char('*'),
                           Token::Char('a')]));

        assert_eq!(parse("\\\""),
                   Ok(vec![Token::Char('\"')]));
    }

    #[test]
    fn it_fails_if_escape_is_at_end_of_string() {
        assert!(parse("\\").is_err());
        assert!(parse("hello\\").is_err());
        assert!(!parse("hel\\lo").is_err());
    }

    #[test]
    fn it_recognizes_numeral_ranges() {
        assert_eq!(parse("0123456789"),
                   Ok(vec![Token::Char('0'),
                           Token::Char('1'),
                           Token::Char('2'),
                           Token::Char('3'),
                           Token::Char('4'),
                           Token::Char('5'),
                           Token::Char('6'),
                           Token::Char('7'),
                           Token::Char('8'),
                           Token::Char('9')]));

        assert_eq!(parse("0-10-20-9"),
                   Ok(vec![Token::Char('0'),
                           Token::Char('-'),
                           Token::Char('1'),
                           Token::Char('0'),
                           Token::Char('-'),
                           Token::Char('2'),
                           Token::NumeralRange]));

        assert_eq!(parse("9-0-9"),
                   Ok(vec![Token::Char('9'),
                           Token::Char('-'),
                           Token::NumeralRange]));
    }

    #[test]
    fn it_recognizes_lowercase_ranges() {
        assert_eq!(parse("az"),
                   Ok(vec![Token::Char('a'),
                           Token::Char('z')]));

        assert_eq!(parse("0-9a-z"),
                   Ok(vec![Token::NumeralRange,
                           Token::LowercaseRange]));

        assert_eq!(parse("a-z0-9"),
                   Ok(vec![Token::LowercaseRange,
                           Token::NumeralRange]));

        assert_eq!(parse("z-a-z"),
                   Ok(vec![Token::Char('z'),
                           Token::Char('-'),
                           Token::LowercaseRange]));
    }

    #[test]
    fn it_recognizes_uppercase_ranges() {
        assert_eq!(parse("AZ"),
                   Ok(vec![Token::Char('A'),
                           Token::Char('Z')]));

        assert_eq!(parse("0-9a-Z"),
                   Ok(vec![Token::NumeralRange,
                           Token::Char('a'),
                           Token::Char('-'),
                           Token::Char('Z')]));

        assert_eq!(parse("A-Za-z0-9"),
                   Ok(vec![Token::UppercaseRange,
                           Token::LowercaseRange,
                           Token::NumeralRange]));

        assert_eq!(parse("z-A\\-Z"),
                   Ok(vec![Token::Char('z'),
                           Token::Char('-'),
                           Token::Char('A'),
                           Token::Char('-'),
                           Token::Char('Z')]));

        assert_eq!(parse("z-A-Z"),
                   Ok(vec![Token::Char('z'),
                           Token::Char('-'),
                           Token::UppercaseRange]));
    }

    #[test]
    fn it_recognizes_brackets() {
        assert_eq!(parse("["),
                   Ok(vec![Token::OpenBracket]));

        assert_eq!(parse("]["),
                   Ok(vec![Token::ClosedBracket,
                           Token::OpenBracket]));

        assert_eq!(parse("[]"),
                   Ok(vec![Token::OpenBracket,
                           Token::ClosedBracket]));

        assert_eq!(parse("[0-9]"),
                   Ok(vec![Token::OpenBracket,
                           Token::NumeralRange,
                           Token::ClosedBracket]));
    }

    #[test]
    fn it_properly_handles_bracket_inversion() {
        assert_eq!(parse("[^"),
                   Ok(vec![Token::OpenBracket,
                           Token::BracketInversion]));

        assert_eq!(parse("]^["),
                   Ok(vec![Token::ClosedBracket,
                           Token::Char('^'),
                           Token::OpenBracket]));

        assert_eq!(parse("^[^]^"),
                   Ok(vec![Token::Char('^'),
                           Token::OpenBracket,
                           Token::BracketInversion,
                           Token::ClosedBracket,
                           Token::Char('^')]));

        assert_eq!(parse("[^0-9]"),
                   Ok(vec![Token::OpenBracket,
                           Token::BracketInversion,
                           Token::NumeralRange,
                           Token::ClosedBracket]));

        assert_eq!(parse("[0^-9]"),
                   Ok(vec![Token::OpenBracket,
                           Token::Char('0'),
                           Token::Char('^'),
                           Token::Char('-'),
                           Token::Char('9'),
                           Token::ClosedBracket]));

        assert_eq!(parse("[0-9^]"),
                   Ok(vec![Token::OpenBracket,
                           Token::NumeralRange,
                           Token::Char('^'),
                           Token::ClosedBracket]));

        assert_eq!(parse("[\\^-9]"),
                   Ok(vec![Token::OpenBracket,
                           Token::Char('^'),
                           Token::Char('-'),
                           Token::Char('9'),
                           Token::ClosedBracket]));

        assert_eq!(parse("^[-9]"),
                   Ok(vec![Token::Char('^'),
                           Token::OpenBracket,
                           Token::Char('-'),
                           Token::Char('9'),
                           Token::ClosedBracket]));
    }

    #[test]
    fn it_recognizes_parentheses() {
        assert_eq!(parse("("),
                   Ok(vec!(Token::OpenParen)));

        assert_eq!(parse(")("),
                   Ok(vec!(Token::ClosedParen,
                           Token::OpenParen)));

        assert_eq!(parse("()"),
                   Ok(vec!(Token::OpenParen,
                           Token::ClosedParen)));

        assert_eq!(parse("(0-9)"),
                   Ok(vec!(Token::OpenParen,
                           Token::NumeralRange,
                           Token::ClosedParen)));
    }
}
<|endoftext|>