<commit_before>// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use crate::exec;
use crate::exit_codes::ExitCode;
use crate::fshelper;
use crate::internal::{opts::FdOptions, MAX_BUFFER_LENGTH};
use crate::output;

use std::error::Error;
use std::io;
use std::path::PathBuf;
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time;

use ignore::overrides::OverrideBuilder;
use ignore::{self, WalkBuilder};
use regex::Regex;

/// The receiver thread can either be buffering results or directly streaming to the console.
enum ReceiverMode {
    /// Receiver is still buffering in order to sort the results, if the search finishes fast
    /// enough.
    Buffering,

    /// Receiver is directly printing results to the output.
    Streaming,
}

/// The Worker threads can result in a valid entry having PathBuf or an error.
pub enum WorkerResult {
    Entry(PathBuf),
    Error(ignore::Error),
}

/// Recursively scan the given search path for files / pathnames matching the pattern.
///
/// If the `--exec` argument was supplied, this will create a thread pool for executing
/// jobs in parallel from a given command line and the discovered paths. Otherwise, each
/// path will simply be written to standard output.
pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<FdOptions>) -> ExitCode {
    let mut path_iter = path_vec.iter();
    let first_path_buf = path_iter
        .next()
        .expect("Error: Path vector can not be empty");
    let (tx, rx) = channel();

    let mut override_builder = OverrideBuilder::new(first_path_buf.as_path());

    for pattern in &config.exclude_patterns {
        let res = override_builder.add(pattern);
        if res.is_err() {
            print_error_and_exit!("Malformed exclude pattern '{}'", pattern);
        }
    }
    let overrides = override_builder.build().unwrap_or_else(|_| {
        print_error_and_exit!("Mismatch in exclude patterns");
    });

    let mut walker = WalkBuilder::new(first_path_buf.as_path());
    walker
        .hidden(config.ignore_hidden)
        .ignore(config.read_fdignore)
        .parents(config.read_fdignore || config.read_vcsignore)
        .git_ignore(config.read_vcsignore)
        .git_global(config.read_vcsignore)
        .git_exclude(config.read_vcsignore)
        .overrides(overrides)
        .follow_links(config.follow_links)
        .max_depth(config.max_depth);

    if config.read_fdignore {
        walker.add_custom_ignore_filename(".fdignore");
    }

    for ignore_file in &config.ignore_files {
        let result = walker.add_ignore(ignore_file);
        match result {
            Some(ignore::Error::Partial(_)) => (),
            Some(err) => {
                print_error!(
                    "{}",
                    format!(
                        "Malformed pattern in custom ignore file '{}': {}.",
                        ignore_file.to_string_lossy(),
                        err.description()
                    )
                );
            }
            None => (),
        }
    }

    for path_entry in path_iter {
        walker.add(path_entry.as_path());
    }

    let parallel_walker = walker.threads(config.threads).build_parallel();

    let wants_to_quit = Arc::new(AtomicBool::new(false));
    if config.ls_colors.is_some() && config.command.is_none() {
        let wq = Arc::clone(&wants_to_quit);
        ctrlc::set_handler(move || {
            wq.store(true, Ordering::Relaxed);
        })
        .unwrap();
    }

    // Spawn the thread that receives all results through the channel.
    let receiver_thread = spawn_receiver(&config, &wants_to_quit, rx);

    // Spawn the sender threads.
    spawn_senders(&config, &wants_to_quit, pattern, parallel_walker, tx);

    // Wait for the receiver thread to print out all results.
    let exit_code = receiver_thread.join().unwrap();

    if wants_to_quit.load(Ordering::Relaxed) {
        process::exit(ExitCode::KilledBySigint.into());
    }

    exit_code
}

fn spawn_receiver(
    config: &Arc<FdOptions>,
    wants_to_quit: &Arc<AtomicBool>,
    rx: Receiver<WorkerResult>,
) -> thread::JoinHandle<ExitCode> {
    let config = Arc::clone(config);
    let wants_to_quit = Arc::clone(wants_to_quit);

    let show_filesystem_errors = config.show_filesystem_errors;
    let threads = config.threads;

    thread::spawn(move || {
        // This will be set to `Some` if the `--exec` argument was supplied.
        if let Some(ref cmd) = config.command {
            if cmd.in_batch_mode() {
                exec::batch(rx, cmd, show_filesystem_errors)
            } else {
                let shared_rx = Arc::new(Mutex::new(rx));

                let out_perm = Arc::new(Mutex::new(()));

                // Each spawned job will store it's thread handle in here.
                let mut handles = Vec::with_capacity(threads);
                for _ in 0..threads {
                    let rx = Arc::clone(&shared_rx);
                    let cmd = Arc::clone(cmd);
                    let out_perm = Arc::clone(&out_perm);

                    // Spawn a job thread that will listen for and execute inputs.
                    let handle =
                        thread::spawn(move || exec::job(rx, cmd, out_perm, show_filesystem_errors));

                    // Push the handle of the spawned thread into the vector for later joining.
                    handles.push(handle);
                }

                // Wait for all threads to exit before exiting the program.
                for h in handles {
                    h.join().unwrap();
                }

                ExitCode::Success
            }
        } else {
            let start = time::Instant::now();

            let mut buffer = vec![];

            // Start in buffering mode
            let mut mode = ReceiverMode::Buffering;

            // Maximum time to wait before we start streaming to the console.
            let max_buffer_time = config
                .max_buffer_time
                .unwrap_or_else(|| time::Duration::from_millis(100));

            let stdout = io::stdout();
            let mut stdout = stdout.lock();

            for worker_result in rx {
                match worker_result {
                    WorkerResult::Entry(value) => {
                        match mode {
                            ReceiverMode::Buffering => {
                                buffer.push(value);

                                // Have we reached the maximum buffer size or maximum buffering time?
                                if buffer.len() > MAX_BUFFER_LENGTH
                                    || time::Instant::now() - start > max_buffer_time
                                {
                                    // Flush the buffer
                                    for v in &buffer {
                                        output::print_entry(
                                            &mut stdout,
                                            v,
                                            &config,
                                            &wants_to_quit,
                                        );
                                    }
                                    buffer.clear();

                                    // Start streaming
                                    mode = ReceiverMode::Streaming;
                                }
                            }
                            ReceiverMode::Streaming => {
                                output::print_entry(&mut stdout, &value, &config, &wants_to_quit);
                            }
                        }
                    }
                    WorkerResult::Error(err) => {
                        if show_filesystem_errors {
                            print_error!("{}", err);
                        }
                    }
                }
            }

            // If we have finished fast enough (faster than max_buffer_time), we haven't streamed
            // anything to the console, yet. In this case, sort the results and print them:
            if !buffer.is_empty() {
                buffer.sort();
                for value in buffer {
                    output::print_entry(&mut stdout, &value, &config, &wants_to_quit);
                }
            }

            ExitCode::Success
        }
    })
}

fn spawn_senders(
    config: &Arc<FdOptions>,
    wants_to_quit: &Arc<AtomicBool>,
    pattern: Arc<Regex>,
    parallel_walker: ignore::WalkParallel,
    tx: Sender<WorkerResult>,
) {
    parallel_walker.run(|| {
        let config = Arc::clone(config);
        let pattern = Arc::clone(&pattern);
        let tx_thread = tx.clone();
        let wants_to_quit = Arc::clone(wants_to_quit);

        Box::new(move |entry_o| {
            if wants_to_quit.load(Ordering::Relaxed) {
                return ignore::WalkState::Quit;
            }

            let entry = match entry_o {
                Ok(e) => e,
                Err(err) => {
                    tx_thread.send(WorkerResult::Error(err)).unwrap();
                    return ignore::WalkState::Continue;
                }
            };

            if entry.depth() == 0 {
                return ignore::WalkState::Continue;
            }

            // Check the name first, since it doesn't require metadata

            let entry_path = entry.path();

            let search_str_o = if config.search_full_path {
                match fshelper::path_absolute_form(entry_path) {
                    Ok(path_abs_buf) => Some(path_abs_buf.to_string_lossy().into_owned().into()),
                    Err(_) => {
                        print_error_and_exit!("Unable to retrieve absolute path.");
                    }
                }
            } else {
                entry_path.file_name().map(|f| f.to_string_lossy())
            };

            if let Some(search_str) = search_str_o {
                if !pattern.is_match(&*search_str) {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted extensions.
            if let Some(ref exts_regex) = config.extensions {
                if let Some(path_str) = entry_path.file_name().and_then(|s| s.to_str()) {
                    if !exts_regex.is_match(path_str) {
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted file types.

            if let Some(ref file_types) = config.file_types {
                if let Some(ref entry_type) = entry.file_type() {
                    if (!file_types.files && entry_type.is_file())
                        || (!file_types.directories && entry_type.is_dir())
                        || (!file_types.symlinks && entry_type.is_symlink())
                        || (file_types.executables_only
                            && !entry
                                .metadata()
                                .map(|m| fshelper::is_executable(&m))
                                .unwrap_or(false))
                        || (file_types.empty_only && !fshelper::is_empty(&entry))
                    {
                        return ignore::WalkState::Continue;
                    } else if !(entry_type.is_file()
                        || entry_type.is_dir()
                        || entry_type.is_symlink())
                    {
                        // This is probably a block device, char device, fifo or socket. Skip it.
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted sizes if it is a file and we have been given size constraints.
            if !config.size_constraints.is_empty() {
                if entry_path.is_file() {
                    if let Ok(metadata) = entry_path.metadata() {
                        let file_size = metadata.len();
                        if config
                            .size_constraints
                            .iter()
                            .any(|sc| !sc.is_within(file_size))
                        {
                            return ignore::WalkState::Continue;
                        }
                    } else {
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted modification times
            if !config.time_constraints.is_empty() {
                let mut matched = false;
                if entry_path.is_file() {
                    if let Ok(metadata) = entry_path.metadata() {
                        if let Ok(modified) = metadata.modified() {
                            matched = config
                                .time_constraints
                                .iter()
                                .all(|tf| tf.applies_to(&modified));
                        }
                    }
                }
                if !matched {
                    return ignore::WalkState::Continue;
                }
            }

            // TODO: take care of the unwrap call
            tx_thread
                .send(WorkerResult::Entry(entry_path.to_owned()))
                .unwrap();

            ignore::WalkState::Continue
        })
    });
}
<commit_msg>Exit immediately when Ctrl-C has been pressed twice<commit_after>// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use crate::exec;
use crate::exit_codes::ExitCode;
use crate::fshelper;
use crate::internal::{opts::FdOptions, MAX_BUFFER_LENGTH};
use crate::output;

use std::error::Error;
use std::io;
use std::path::PathBuf;
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time;

use ignore::overrides::OverrideBuilder;
use ignore::{self, WalkBuilder};
use regex::Regex;

/// The receiver thread can either be buffering results or directly streaming to the console.
enum ReceiverMode {
    /// Receiver is still buffering in order to sort the results, if the search finishes fast
    /// enough.
    Buffering,

    /// Receiver is directly printing results to the output.
    Streaming,
}

/// The Worker threads can result in a valid entry having PathBuf or an error.
pub enum WorkerResult {
    Entry(PathBuf),
    Error(ignore::Error),
}

/// Recursively scan the given search path for files / pathnames matching the pattern.
///
/// If the `--exec` argument was supplied, this will create a thread pool for executing
/// jobs in parallel from a given command line and the discovered paths. Otherwise, each
/// path will simply be written to standard output.
pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<FdOptions>) -> ExitCode {
    let mut path_iter = path_vec.iter();
    let first_path_buf = path_iter
        .next()
        .expect("Error: Path vector can not be empty");
    let (tx, rx) = channel();

    let mut override_builder = OverrideBuilder::new(first_path_buf.as_path());

    for pattern in &config.exclude_patterns {
        let res = override_builder.add(pattern);
        if res.is_err() {
            print_error_and_exit!("Malformed exclude pattern '{}'", pattern);
        }
    }
    let overrides = override_builder.build().unwrap_or_else(|_| {
        print_error_and_exit!("Mismatch in exclude patterns");
    });

    let mut walker = WalkBuilder::new(first_path_buf.as_path());
    walker
        .hidden(config.ignore_hidden)
        .ignore(config.read_fdignore)
        .parents(config.read_fdignore || config.read_vcsignore)
        .git_ignore(config.read_vcsignore)
        .git_global(config.read_vcsignore)
        .git_exclude(config.read_vcsignore)
        .overrides(overrides)
        .follow_links(config.follow_links)
        .max_depth(config.max_depth);

    if config.read_fdignore {
        walker.add_custom_ignore_filename(".fdignore");
    }

    for ignore_file in &config.ignore_files {
        let result = walker.add_ignore(ignore_file);
        match result {
            Some(ignore::Error::Partial(_)) => (),
            Some(err) => {
                print_error!(
                    "{}",
                    format!(
                        "Malformed pattern in custom ignore file '{}': {}.",
                        ignore_file.to_string_lossy(),
                        err.description()
                    )
                );
            }
            None => (),
        }
    }

    for path_entry in path_iter {
        walker.add(path_entry.as_path());
    }

    let parallel_walker = walker.threads(config.threads).build_parallel();

    let wants_to_quit = Arc::new(AtomicBool::new(false));
    if config.ls_colors.is_some() && config.command.is_none() {
        let wq = Arc::clone(&wants_to_quit);
        ctrlc::set_handler(move || {
            if wq.load(Ordering::Relaxed) {
                // Ctrl-C has been pressed twice, exit NOW
                process::exit(ExitCode::KilledBySigint.into());
            } else {
                wq.store(true, Ordering::Relaxed);
            }
        })
        .unwrap();
    }

    // Spawn the thread that receives all results through the channel.
    let receiver_thread = spawn_receiver(&config, &wants_to_quit, rx);

    // Spawn the sender threads.
    spawn_senders(&config, &wants_to_quit, pattern, parallel_walker, tx);

    // Wait for the receiver thread to print out all results.
    let exit_code = receiver_thread.join().unwrap();

    if wants_to_quit.load(Ordering::Relaxed) {
        process::exit(ExitCode::KilledBySigint.into());
    }

    exit_code
}

fn spawn_receiver(
    config: &Arc<FdOptions>,
    wants_to_quit: &Arc<AtomicBool>,
    rx: Receiver<WorkerResult>,
) -> thread::JoinHandle<ExitCode> {
    let config = Arc::clone(config);
    let wants_to_quit = Arc::clone(wants_to_quit);

    let show_filesystem_errors = config.show_filesystem_errors;
    let threads = config.threads;

    thread::spawn(move || {
        // This will be set to `Some` if the `--exec` argument was supplied.
        if let Some(ref cmd) = config.command {
            if cmd.in_batch_mode() {
                exec::batch(rx, cmd, show_filesystem_errors)
            } else {
                let shared_rx = Arc::new(Mutex::new(rx));

                let out_perm = Arc::new(Mutex::new(()));

                // Each spawned job will store it's thread handle in here.
                let mut handles = Vec::with_capacity(threads);
                for _ in 0..threads {
                    let rx = Arc::clone(&shared_rx);
                    let cmd = Arc::clone(cmd);
                    let out_perm = Arc::clone(&out_perm);

                    // Spawn a job thread that will listen for and execute inputs.
                    let handle =
                        thread::spawn(move || exec::job(rx, cmd, out_perm, show_filesystem_errors));

                    // Push the handle of the spawned thread into the vector for later joining.
                    handles.push(handle);
                }

                // Wait for all threads to exit before exiting the program.
                for h in handles {
                    h.join().unwrap();
                }

                ExitCode::Success
            }
        } else {
            let start = time::Instant::now();

            let mut buffer = vec![];

            // Start in buffering mode
            let mut mode = ReceiverMode::Buffering;

            // Maximum time to wait before we start streaming to the console.
            let max_buffer_time = config
                .max_buffer_time
                .unwrap_or_else(|| time::Duration::from_millis(100));

            let stdout = io::stdout();
            let mut stdout = stdout.lock();

            for worker_result in rx {
                match worker_result {
                    WorkerResult::Entry(value) => {
                        match mode {
                            ReceiverMode::Buffering => {
                                buffer.push(value);

                                // Have we reached the maximum buffer size or maximum buffering time?
                                if buffer.len() > MAX_BUFFER_LENGTH
                                    || time::Instant::now() - start > max_buffer_time
                                {
                                    // Flush the buffer
                                    for v in &buffer {
                                        output::print_entry(
                                            &mut stdout,
                                            v,
                                            &config,
                                            &wants_to_quit,
                                        );
                                    }
                                    buffer.clear();

                                    // Start streaming
                                    mode = ReceiverMode::Streaming;
                                }
                            }
                            ReceiverMode::Streaming => {
                                output::print_entry(&mut stdout, &value, &config, &wants_to_quit);
                            }
                        }
                    }
                    WorkerResult::Error(err) => {
                        if show_filesystem_errors {
                            print_error!("{}", err);
                        }
                    }
                }
            }

            // If we have finished fast enough (faster than max_buffer_time), we haven't streamed
            // anything to the console, yet. In this case, sort the results and print them:
            if !buffer.is_empty() {
                buffer.sort();
                for value in buffer {
                    output::print_entry(&mut stdout, &value, &config, &wants_to_quit);
                }
            }

            ExitCode::Success
        }
    })
}

fn spawn_senders(
    config: &Arc<FdOptions>,
    wants_to_quit: &Arc<AtomicBool>,
    pattern: Arc<Regex>,
    parallel_walker: ignore::WalkParallel,
    tx: Sender<WorkerResult>,
) {
    parallel_walker.run(|| {
        let config = Arc::clone(config);
        let pattern = Arc::clone(&pattern);
        let tx_thread = tx.clone();
        let wants_to_quit = Arc::clone(wants_to_quit);

        Box::new(move |entry_o| {
            if wants_to_quit.load(Ordering::Relaxed) {
                return ignore::WalkState::Quit;
            }

            let entry = match entry_o {
                Ok(e) => e,
                Err(err) => {
                    tx_thread.send(WorkerResult::Error(err)).unwrap();
                    return ignore::WalkState::Continue;
                }
            };

            if entry.depth() == 0 {
                return ignore::WalkState::Continue;
            }

            // Check the name first, since it doesn't require metadata

            let entry_path = entry.path();

            let search_str_o = if config.search_full_path {
                match fshelper::path_absolute_form(entry_path) {
                    Ok(path_abs_buf) => Some(path_abs_buf.to_string_lossy().into_owned().into()),
                    Err(_) => {
                        print_error_and_exit!("Unable to retrieve absolute path.");
                    }
                }
            } else {
                entry_path.file_name().map(|f| f.to_string_lossy())
            };

            if let Some(search_str) = search_str_o {
                if !pattern.is_match(&*search_str) {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted extensions.
            if let Some(ref exts_regex) = config.extensions {
                if let Some(path_str) = entry_path.file_name().and_then(|s| s.to_str()) {
                    if !exts_regex.is_match(path_str) {
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted file types.

            if let Some(ref file_types) = config.file_types {
                if let Some(ref entry_type) = entry.file_type() {
                    if (!file_types.files && entry_type.is_file())
                        || (!file_types.directories && entry_type.is_dir())
                        || (!file_types.symlinks && entry_type.is_symlink())
                        || (file_types.executables_only
                            && !entry
                                .metadata()
                                .map(|m| fshelper::is_executable(&m))
                                .unwrap_or(false))
                        || (file_types.empty_only && !fshelper::is_empty(&entry))
                    {
                        return ignore::WalkState::Continue;
                    } else if !(entry_type.is_file()
                        || entry_type.is_dir()
                        || entry_type.is_symlink())
                    {
                        // This is probably a block device, char device, fifo or socket. Skip it.
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted sizes if it is a file and we have been given size constraints.
            if !config.size_constraints.is_empty() {
                if entry_path.is_file() {
                    if let Ok(metadata) = entry_path.metadata() {
                        let file_size = metadata.len();
                        if config
                            .size_constraints
                            .iter()
                            .any(|sc| !sc.is_within(file_size))
                        {
                            return ignore::WalkState::Continue;
                        }
                    } else {
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted modification times
            if !config.time_constraints.is_empty() {
                let mut matched = false;
                if entry_path.is_file() {
                    if let Ok(metadata) = entry_path.metadata() {
                        if let Ok(modified) = metadata.modified() {
                            matched = config
                                .time_constraints
                                .iter()
                                .all(|tf| tf.applies_to(&modified));
                        }
                    }
                }
                if !matched {
                    return ignore::WalkState::Continue;
                }
            }

            // TODO: take care of the unwrap call
            tx_thread
                .send(WorkerResult::Entry(entry_path.to_owned()))
                .unwrap();

            ignore::WalkState::Continue
        })
    });
}
<|endoftext|>


<commit_before>use codemap::File;
use codemap::Spanned;
use self::Token::*;
use std::iter::Enumerate;
use std::iter::Peekable;
use std::str::Chars;

type LexIter<'a> = Peekable<Enumerate<Chars<'a>>>;

#[derive(Debug, Clone, PartialEq)]
pub enum Token {
  // Structure
  EOF,
  Enter,
  Exit,
  Space,
  End,
  Comment(String),

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  Str(String),
  Name(String),

  // Keywords
  Break,
  Catch,
  Continue,
  Else,
  For,
  Func,
  If,
  Import,
  In,
  Loop,
  Pass,
  Return,
  Save,
  Table,
  Var,
  While,

  // Symbols
  Arr,  // ->
  Ass,  // =
  Col,  // :
  Com,  // ,
  Dot,  // .
  Meta, // ::
  Semi, // ;

  // Braces
  Cul, // {
  Cur, // }
  Pal, // (
  Par, // )
  Sql, // [
  Sqr, // ]

  // Operators
  Add, // +
  And, // &
  At,  // @
  Car, // ^
  Div, // /
  Dol, // $
  Mul, // *
  Neg, // ~
  Not, // !
  Or,  // |
  Pct, // %
  Sub, // -

  // Comparisons
  Eql, // ==
  Ge,  // >=
  Gt,  // >
  Le,  // <=
  Lt,  // <
  Ne,  // !=
}

fn lex_number(it: &mut LexIter) -> Token {
  let mut digits = String::new();
  while let Some(&(_i, c)) = it.peek() {
    match c {
      '0'...'9' | '.' => {
        it.next();
        digits.push(c);
      }
      _ => break,
    }
  }

  match digits.contains(".") {
    true => Float(digits.parse::<f64>().unwrap()),
    false => Int(digits.parse::<i64>().unwrap()),
  }
}

fn lex_name(it: &mut LexIter) -> Token {
  let mut name = String::new();
  name.push(it.next().unwrap().1);

  while let Some(&(_i, c)) = it.peek() {
    match c {
      'a'...'z' | 'A'...'Z' | '0'...'9' | '_' => {
        it.next();
        name.push(c);
      }
      _ => break,
    }
  }

  match name.as_str() {
    "true" => Bool(true),
    "false" => Bool(false),
    "null" => Null,

    "break" => Break,
    "catch" => Catch,
    "continue" => Continue,
    "else" => Else,
    "for" => For,
    "func" => Func,
    "if" => If,
    "import" => Import,
    "in" => In,
    "loop" => Loop,
    "pass" => Pass,
    "return" => Return,
    "save" => Save,
    "table" => Table,
    "var" => Var,
    "while" => While,

    _ => Name(name),
  }
}

fn lex_comment(it: &mut LexIter) -> Token {
  let mut comment = String::new();
  it.next();

  while let Some(&(_i, c)) = it.peek() {
    match c {
      '\n' => break,
      _ => {
        it.next();
        comment.push(c);
      }
    }
  }

  println!("Comment: {:?}", comment);
  Comment(comment)
}

fn lex_indent(it: &mut LexIter) -> u64 {
  let mut indent: u64 = 0;
  it.next();

  while let Some(&(_i, c)) = it.peek() {
    match c {
      ' ' => {
        it.next();
        indent += 1;
      }
      _ => break,
    }
  }

  indent
}

fn lex_pair(next: char, solo: Token, pair: Token, it: &mut LexIter) -> Token {
  it.next();

  if let Some(&(_i, c)) = it.peek() {
    if c == next {
      it.next();
      return pair;
    }
  }

  // is this right? if peek() returns a None, we just return `solo`?
  // seems right. None should be the EOF, meaning `solo` is the last token
  solo
}

pub fn lex(input: &File) -> Vec<Spanned<Token>> {
  let mut tokens: Vec<Spanned<Token>> = Vec::new();
  let mut it: LexIter = input.source().chars().enumerate().peekable();
  let mut indent_stack: Vec<u64> = Vec::new();
  let mut current_indent: u64 = 0;

  // start at indentation 0
  indent_stack.push(current_indent);

  while let Some(&(i, c)) = it.peek() {
    let x = if current_indent < indent_stack[indent_stack.len() - 1] {
      indent_stack.pop();
      Exit
    } else {
      match c {
        '#' => lex_comment(&mut it),
        'a'...'z' | 'A'...'Z' | '_' => lex_name(&mut it),
        '0'...'9' => lex_number(&mut it),
        '\n' => {
          let indent = lex_indent(&mut it);

          if let Some(&(_, c)) = it.peek() {
            match c {
              '\n' => Space,
              _ => {
                current_indent = indent;
                // if this panics, there's a bug - indent_stack should always have a 0
                if indent > indent_stack[indent_stack.len() - 1] {
                  indent_stack.push(indent);
                  Enter
                } else {
                  End
                }
              }
            }
          } else {
            End
          }
        }

        // Compound
        '-' => lex_pair('>', Sub, Arr, &mut it),
        '<' => lex_pair('=', Lt, Le, &mut it),
        '>' => lex_pair('=', Gt, Ge, &mut it),
        '=' => lex_pair('=', Ass, Eql, &mut it),
        '!' => lex_pair('=', Not, Ne, &mut it),
        ':' => lex_pair(':', Col, Meta, &mut it),

        // Symbols
        // -> Arr
        // = Ass
        // : Col
        ',' => {
          it.next();
          Com
        }
        '.' => {
          it.next();
          Dot
        }
        // :: Meta
        ';' => {
          it.next();
          Semi
        }

        // Braces
        '(' => {
          it.next();
          Pal
        }
        ')' => {
          it.next();
          Par
        }
        '[' => {
          it.next();
          Sql
        }
        ']' => {
          it.next();
          Sqr
        }
        '{' => {
          it.next();
          Cul
        }
        '}' => {
          it.next();
          Cur
        }

        // Operators
        '+' => {
          it.next();
          Add
        }
        '&' => {
          it.next();
          And
        }
        '@' => {
          it.next();
          At
        }
        '^' => {
          it.next();
          Car
        }
        '/' => {
          it.next();
          Div
        }
        '$' => {
          it.next();
          Dol
        }
        '*' => {
          it.next();
          Mul
        }
        '~' => {
          it.next();
          Neg
        }
        // ! Not
        '|' => {
          it.next();
          Or
        }
        '%' => {
          it.next();
          Pct
        }
        // - Sub
        _ => {
          it.next();
          Space
        }
      }
    };

    // figure out what the span was for this token
    // either there's something we can peek, or the span is until EOF
    let mut end_i = if let Some(&(j, _)) = it.peek() {
      j
    } else {
      input.source().len()
    };
    let span = input.span.subspan(i as u64, end_i as u64);

    match x {
      // don't emit tokens for spaces or comments
      Space => (),
      Comment(_) => (),

      // don't insert duplicate newlines, or file-leading newlines
      End => match tokens.last().cloned() {
        None => (),
        Some(x) => {
          if x.node != End {
            tokens.push(Spanned {
              node: End,
              span: span,
            });
          }
        }
      },

      // exit should always be followed by a End
      Exit => {
        tokens.push(Spanned {
          node: Exit,
          span: span,
        });
        tokens.push(Spanned {
          node: End,
          span: span,
        });
      }

      // emit everything else
      _ => tokens.push(Spanned {
        node: x,
        span: span,
      }),
    }
  }

  // make a span for all closing tokens
  let end = input.source().len() as u64;
  let span = input.span.subspan(end, end);

  // exit blocks that are open at EOF
  while indent_stack.len() > 1 {
    tokens.push(Spanned {
      node: Exit,
      span: span,
    });
    tokens.push(Spanned {
      node: End,
      span: span,
    });
    indent_stack.pop();
  }

  // sometimes a trailing newline goes missing before EOF
  if let Some(x) = tokens.last().cloned() {
    if x.node != End {
      tokens.push(Spanned {
        node: End,
        span: span,
      });
    }
  }

  // push the EOF token
  tokens.push(Spanned {
    node: EOF,
    span: span,
  });

  tokens
}

#[cfg(test)]
#[path = "./tests/lexer.rs"]
mod tests;
<commit_msg>lexer: Change 'func' keyword to 'fn'<commit_after>use codemap::File;
use codemap::Spanned;
use self::Token::*;
use std::iter::Enumerate;
use std::iter::Peekable;
use std::str::Chars;

type LexIter<'a> = Peekable<Enumerate<Chars<'a>>>;

#[derive(Debug, Clone, PartialEq)]
pub enum Token {
  // Structure
  EOF,
  Enter,
  Exit,
  Space,
  End,
  Comment(String),

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  Str(String),
  Name(String),

  // Keywords
  Break,
  Catch,
  Continue,
  Else,
  For,
  Func,
  If,
  Import,
  In,
  Loop,
  Pass,
  Return,
  Save,
  Table,
  Var,
  While,

  // Symbols
  Arr,  // ->
  Ass,  // =
  Col,  // :
  Com,  // ,
  Dot,  // .
  Meta, // ::
  Semi, // ;

  // Braces
  Cul, // {
  Cur, // }
  Pal, // (
  Par, // )
  Sql, // [
  Sqr, // ]

  // Operators
  Add, // +
  And, // &
  At,  // @
  Car, // ^
  Div, // /
  Dol, // $
  Mul, // *
  Neg, // ~
  Not, // !
  Or,  // |
  Pct, // %
  Sub, // -

  // Comparisons
  Eql, // ==
  Ge,  // >=
  Gt,  // >
  Le,  // <=
  Lt,  // <
  Ne,  // !=
}

fn lex_number(it: &mut LexIter) -> Token {
  let mut digits = String::new();
  while let Some(&(_i, c)) = it.peek() {
    match c {
      '0'...'9' | '.' => {
        it.next();
        digits.push(c);
      }
      _ => break,
    }
  }

  match digits.contains(".") {
    true => Float(digits.parse::<f64>().unwrap()),
    false => Int(digits.parse::<i64>().unwrap()),
  }
}

fn lex_name(it: &mut LexIter) -> Token {
  let mut name = String::new();
  name.push(it.next().unwrap().1);

  while let Some(&(_i, c)) = it.peek() {
    match c {
      'a'...'z' | 'A'...'Z' | '0'...'9' | '_' => {
        it.next();
        name.push(c);
      }
      _ => break,
    }
  }

  match name.as_str() {
    "true" => Bool(true),
    "false" => Bool(false),
    "null" => Null,

    "break" => Break,
    "catch" => Catch,
    "continue" => Continue,
    "else" => Else,
    "for" => For,
    "fn" => Func,
    "if" => If,
    "import" => Import,
    "in" => In,
    "loop" => Loop,
    "pass" => Pass,
    "return" => Return,
    "save" => Save,
    "table" => Table,
    "var" => Var,
    "while" => While,

    _ => Name(name),
  }
}

fn lex_comment(it: &mut LexIter) -> Token {
  let mut comment = String::new();
  it.next();

  while let Some(&(_i, c)) = it.peek() {
    match c {
      '\n' => break,
      _ => {
        it.next();
        comment.push(c);
      }
    }
  }

  println!("Comment: {:?}", comment);
  Comment(comment)
}

fn lex_indent(it: &mut LexIter) -> u64 {
  let mut indent: u64 = 0;
  it.next();

  while let Some(&(_i, c)) = it.peek() {
    match c {
      ' ' => {
        it.next();
        indent += 1;
      }
      _ => break,
    }
  }

  indent
}

fn lex_pair(next: char, solo: Token, pair: Token, it: &mut LexIter) -> Token {
  it.next();

  if let Some(&(_i, c)) = it.peek() {
    if c == next {
      it.next();
      return pair;
    }
  }

  // is this right? if peek() returns a None, we just return `solo`?
  // seems right. None should be the EOF, meaning `solo` is the last token
  solo
}

pub fn lex(input: &File) -> Vec<Spanned<Token>> {
  let mut tokens: Vec<Spanned<Token>> = Vec::new();
  let mut it: LexIter = input.source().chars().enumerate().peekable();
  let mut indent_stack: Vec<u64> = Vec::new();
  let mut current_indent: u64 = 0;

  // start at indentation 0
  indent_stack.push(current_indent);

  while let Some(&(i, c)) = it.peek() {
    let x = if current_indent < indent_stack[indent_stack.len() - 1] {
      indent_stack.pop();
      Exit
    } else {
      match c {
        '#' => lex_comment(&mut it),
        'a'...'z' | 'A'...'Z' | '_' => lex_name(&mut it),
        '0'...'9' => lex_number(&mut it),
        '\n' => {
          let indent = lex_indent(&mut it);

          if let Some(&(_, c)) = it.peek() {
            match c {
              '\n' => Space,
              _ => {
                current_indent = indent;
                // if this panics, there's a bug - indent_stack should always have a 0
                if indent > indent_stack[indent_stack.len() - 1] {
                  indent_stack.push(indent);
                  Enter
                } else {
                  End
                }
              }
            }
          } else {
            End
          }
        }

        // Compound
        '-' => lex_pair('>', Sub, Arr, &mut it),
        '<' => lex_pair('=', Lt, Le, &mut it),
        '>' => lex_pair('=', Gt, Ge, &mut it),
        '=' => lex_pair('=', Ass, Eql, &mut it),
        '!' => lex_pair('=', Not, Ne, &mut it),
        ':' => lex_pair(':', Col, Meta, &mut it),

        // Symbols
        // -> Arr
        // = Ass
        // : Col
        ',' => {
          it.next();
          Com
        }
        '.' => {
          it.next();
          Dot
        }
        // :: Meta
        ';' => {
          it.next();
          Semi
        }

        // Braces
        '(' => {
          it.next();
          Pal
        }
        ')' => {
          it.next();
          Par
        }
        '[' => {
          it.next();
          Sql
        }
        ']' => {
          it.next();
          Sqr
        }
        '{' => {
          it.next();
          Cul
        }
        '}' => {
          it.next();
          Cur
        }

        // Operators
        '+' => {
          it.next();
          Add
        }
        '&' => {
          it.next();
          And
        }
        '@' => {
          it.next();
          At
        }
        '^' => {
          it.next();
          Car
        }
        '/' => {
          it.next();
          Div
        }
        '$' => {
          it.next();
          Dol
        }
        '*' => {
          it.next();
          Mul
        }
        '~' => {
          it.next();
          Neg
        }
        // ! Not
        '|' => {
          it.next();
          Or
        }
        '%' => {
          it.next();
          Pct
        }
        // - Sub
        _ => {
          it.next();
          Space
        }
      }
    };

    // figure out what the span was for this token
    // either there's something we can peek, or the span is until EOF
    let mut end_i = if let Some(&(j, _)) = it.peek() {
      j
    } else {
      input.source().len()
    };
    let span = input.span.subspan(i as u64, end_i as u64);

    match x {
      // don't emit tokens for spaces or comments
      Space => (),
      Comment(_) => (),

      // don't insert duplicate newlines, or file-leading newlines
      End => match tokens.last().cloned() {
        None => (),
        Some(x) => {
          if x.node != End {
            tokens.push(Spanned {
              node: End,
              span: span,
            });
          }
        }
      },

      // exit should always be followed by a End
      Exit => {
        tokens.push(Spanned {
          node: Exit,
          span: span,
        });
        tokens.push(Spanned {
          node: End,
          span: span,
        });
      }

      // emit everything else
      _ => tokens.push(Spanned {
        node: x,
        span: span,
      }),
    }
  }

  // make a span for all closing tokens
  let end = input.source().len() as u64;
  let span = input.span.subspan(end, end);

  // exit blocks that are open at EOF
  while indent_stack.len() > 1 {
    tokens.push(Spanned {
      node: Exit,
      span: span,
    });
    tokens.push(Spanned {
      node: End,
      span: span,
    });
    indent_stack.pop();
  }

  // sometimes a trailing newline goes missing before EOF
  if let Some(x) = tokens.last().cloned() {
    if x.node != End {
      tokens.push(Spanned {
        node: End,
        span: span,
      });
    }
  }

  // push the EOF token
  tokens.push(Spanned {
    node: EOF,
    span: span,
  });

  tokens
}

#[cfg(test)]
#[path = "./tests/lexer.rs"]
mod tests;
<|endoftext|>


<commit_before>use self::Token::{Identifier, LeftParenthesis, RightParenthesis, Comma, SingleQuote, EqualSign, Semicolon, Asterisk};

const DELIMETERS: &'static str = "(),\';=* ";

#[derive(Debug,PartialEq)]
pub enum Token {
    Identifier(String),
    LeftParenthesis,
    RightParenthesis,
    Comma,
    SingleQuote,
    EqualSign,
    Semicolon,
    Asterisk
}

pub trait Tokenizer {

    fn tokenize(&self) -> Vec<Token>;
}

impl Tokenizer for String {

    fn tokenize(&self) -> Vec<Token> {
        fn push_identifier(tokens: &mut Vec<Token>, buffer: &mut String) {
            if !buffer.is_empty() {
                tokens.push(Identifier(buffer.clone()));
                buffer.clear();
            }
        }

        fn char_to_token(c: char) -> Option<Token> {
            match c {
                '('     => Some(LeftParenthesis),
                ')'     => Some(RightParenthesis),
                ','     => Some(Comma),
                '\''    => Some(SingleQuote),
                ';'     => Some(Semicolon),
                '='     => Some(EqualSign),
                '*'     => Some(Asterisk),
                _       => None
            }
        }

        let mut tokens = vec![];
        let mut buffer = String::with_capacity(self.len());
        for c in self.chars() {
            if DELIMETERS.contains(c) {
                push_identifier(&mut tokens, &mut buffer);
                if let Some(token) = char_to_token(c) {
                    tokens.push(token);
                }
            }
            else {
                buffer.push(c);
            }
        }
        push_identifier(&mut tokens, &mut buffer);
        tokens
    }

}
<commit_msg>remove unnecessary memory allocation<commit_after>use self::Token::{Identifier, LeftParenthesis, RightParenthesis, Comma, SingleQuote, EqualSign, Semicolon, Asterisk};

const DELIMETERS: &'static str = "(),\';=* ";

#[derive(Debug,PartialEq)]
pub enum Token {
    Identifier(String),
    LeftParenthesis,
    RightParenthesis,
    Comma,
    SingleQuote,
    EqualSign,
    Semicolon,
    Asterisk
}

pub trait Tokenizer {

    fn tokenize(&self) -> Vec<Token>;
}

impl Tokenizer for String {

    fn tokenize(&self) -> Vec<Token> {
        let mut tokens = vec![];
        let mut end = 0;
        let mut start = end;
        for c in self.chars() {
            if DELIMETERS.contains(c) {
                if start < end {
                    tokens.push(Identifier(self.chars().skip(start).take(end - start).collect::<String>()));
                }
                end += 1;
                start = end;
                if let Some(token) = char_to_token(c) {
                    tokens.push(token);
                }
            }
            else {
                end += 1;
            }
        }
        if start < end {
            tokens.push(Identifier(self.chars().skip(start).take(end - start).collect::<String>()));
        }
        tokens
    }

}

fn char_to_token(c: char) -> Option<Token> {
    match c {
        '('     => Some(LeftParenthesis),
        ')'     => Some(RightParenthesis),
        ','     => Some(Comma),
        '\''    => Some(SingleQuote),
        ';'     => Some(Semicolon),
        '='     => Some(EqualSign),
        '*'     => Some(Asterisk),
        _       => None
    }
}
<|endoftext|>


<commit_before>//! # ADC module
//!
//! This module provides access to the ADC of the stm32f0 board.
//! You can:
//!
//! * configure a PIN in Input
//! * read the analog value from the PIN
//!
//! ## Examples
//!
//! ```
//! extern crate stm32f0_hal;
//!
//! use stm32f0_hal::adc;
//!
//! let p = adc::Input::setup(adc::Pin::PB0);
//! let b = p.read();
//! ```

use cortex_m;
use stm32f0x2::{ADC, GPIOA, GPIOB, GPIOC, RCC};

/// ADC Pin
pub enum Pin {
    PA0,
    PA1,
    PB0,
    PB1,
    PC13,
    PC14,
}

/// Input Mode Pin
pub struct Analog {
    pin: Pin,
}
impl Analog {
    /// Setup a PIN in Input Mode
    pub fn setup(pin: Pin) -> Analog {
        setup_pin(&pin);
        Analog { pin }
    }
    /// Read the analog value of a PIN
    pub fn read(&self) -> u16 {
        cortex_m::interrupt::free(|cs| {
            let adc = ADC.borrow(cs);

            // ADC Pin selection
            match self.pin {
                Pin::PA0 => adc.chselr.write(|w| w.chsel0().set_bit()),
                Pin::PA1 => adc.chselr.write(|w| w.chsel1().set_bit()),
                Pin::PB0 => adc.chselr.write(|w| w.chsel8().set_bit()),
                Pin::PB1 => adc.chselr.write(|w| w.chsel9().set_bit()),
                Pin::PC13 => adc.chselr.write(|w| w.chsel13().set_bit()),
                Pin::PC14 => adc.chselr.write(|w| w.chsel14().set_bit()),
            }

            // Active ADC and Start Conversion
            adc.cr.write(|w| w.aden().set_bit().adstart().set_bit());

            // Wait end of conversation
            while adc.isr.read().eoc().bit_is_clear() {}

            // Return result
            adc.dr.read().data().bits()
        })
    }
}

fn setup_pin(pin: &Pin) {
    cortex_m::interrupt::free(|cs| {
        let rcc = RCC.borrow(cs);
        let gpioa = GPIOA.borrow(cs);
        let gpiob = GPIOB.borrow(cs);
        let gpioc = GPIOC.borrow(cs);
        // Clock Activation
        match *pin {
            Pin::PA0 => rcc.ahbenr.modify(|_, w| w.iopaen().enabled()),
            Pin::PA1 => rcc.ahbenr.modify(|_, w| w.iopaen().enabled()),
            Pin::PB0 => rcc.ahbenr.modify(|_, w| w.iopben().enabled()),
            Pin::PB1 => rcc.ahbenr.modify(|_, w| w.iopben().enabled()),
            Pin::PC13 => rcc.ahbenr.modify(|_, w| w.iopcen().enabled()),
            Pin::PC14 => rcc.ahbenr.modify(|_, w| w.iopcen().enabled()),
        }

        // Clock activation ADC
        rcc.apb2enr.modify(|_, w| w.adcen().enabled());

        // PA Analog Input Pin
        match *pin {
            Pin::PA0 => gpioa.moder.modify(|_, w| w.moder0().analog()),
            Pin::PA1 => gpioa.moder.modify(|_, w| w.moder1().analog()),
            Pin::PB0 => gpiob.moder.modify(|_, w| w.moder0().analog()),
            Pin::PB1 => gpiob.moder.modify(|_, w| w.moder1().analog()),
            Pin::PC13 => gpioc.moder.modify(|_, w| w.moder3().analog()),
            Pin::PC14 => gpioc.moder.modify(|_, w| w.moder4().analog()),
        }
    });
}
<commit_msg>Fix typo in ADC for PC13 & PC14.<commit_after>//! # ADC module
//!
//! This module provides access to the ADC of the stm32f0 board.
//! You can:
//!
//! * configure a PIN in Input
//! * read the analog value from the PIN
//!
//! ## Examples
//!
//! ```
//! extern crate stm32f0_hal;
//!
//! use stm32f0_hal::adc;
//!
//! let p = adc::Input::setup(adc::Pin::PB0);
//! let b = p.read();
//! ```

use cortex_m;
use stm32f0x2::{ADC, GPIOA, GPIOB, GPIOC, RCC};

/// ADC Pin
pub enum Pin {
    PA0,
    PA1,
    PB0,
    PB1,
    PC13,
    PC14,
}

/// Input Mode Pin
pub struct Analog {
    pin: Pin,
}
impl Analog {
    /// Setup a PIN in Input Mode
    pub fn setup(pin: Pin) -> Analog {
        setup_pin(&pin);
        Analog { pin }
    }
    /// Read the analog value of a PIN
    pub fn read(&self) -> u16 {
        cortex_m::interrupt::free(|cs| {
            let adc = ADC.borrow(cs);

            // ADC Pin selection
            match self.pin {
                Pin::PA0 => adc.chselr.write(|w| w.chsel0().set_bit()),
                Pin::PA1 => adc.chselr.write(|w| w.chsel1().set_bit()),
                Pin::PB0 => adc.chselr.write(|w| w.chsel8().set_bit()),
                Pin::PB1 => adc.chselr.write(|w| w.chsel9().set_bit()),
                Pin::PC13 => adc.chselr.write(|w| w.chsel13().set_bit()),
                Pin::PC14 => adc.chselr.write(|w| w.chsel14().set_bit()),
            }

            // Active ADC and Start Conversion
            adc.cr.write(|w| w.aden().set_bit().adstart().set_bit());

            // Wait end of conversation
            while adc.isr.read().eoc().bit_is_clear() {}

            // Return result
            adc.dr.read().data().bits()
        })
    }
}

fn setup_pin(pin: &Pin) {
    cortex_m::interrupt::free(|cs| {
        let rcc = RCC.borrow(cs);
        let gpioa = GPIOA.borrow(cs);
        let gpiob = GPIOB.borrow(cs);
        let gpioc = GPIOC.borrow(cs);
        // Clock Activation
        match *pin {
            Pin::PA0 => rcc.ahbenr.modify(|_, w| w.iopaen().enabled()),
            Pin::PA1 => rcc.ahbenr.modify(|_, w| w.iopaen().enabled()),
            Pin::PB0 => rcc.ahbenr.modify(|_, w| w.iopben().enabled()),
            Pin::PB1 => rcc.ahbenr.modify(|_, w| w.iopben().enabled()),
            Pin::PC13 => rcc.ahbenr.modify(|_, w| w.iopcen().enabled()),
            Pin::PC14 => rcc.ahbenr.modify(|_, w| w.iopcen().enabled()),
        }

        // Clock activation ADC
        rcc.apb2enr.modify(|_, w| w.adcen().enabled());

        // PA Analog Input Pin
        match *pin {
            Pin::PA0 => gpioa.moder.modify(|_, w| w.moder0().analog()),
            Pin::PA1 => gpioa.moder.modify(|_, w| w.moder1().analog()),
            Pin::PB0 => gpiob.moder.modify(|_, w| w.moder0().analog()),
            Pin::PB1 => gpiob.moder.modify(|_, w| w.moder1().analog()),
            Pin::PC13 => gpioc.moder.modify(|_, w| w.moder13().analog()),
            Pin::PC14 => gpioc.moder.modify(|_, w| w.moder14().analog()),
        }
    });
}
<|endoftext|>


<commit_before>use stm32f0x2::{TIM3, GPIOB, GPIOC, RCC};

use cortex_m;

static mut FREQ: u32 = 0;
static mut DUT: f32 = 0.0;
const FREQUENCY: u32 = 48_000_000;

// PWM channels : Pins available
pub enum Pin {
    PB4,
    PB5,
    PC6,
    PC7,
    PC8,
    PC9,
}

pub struct Pwm {
    pin: Pin,
}

impl Pwm {
    pub fn init(pin: Pin) -> Pwm {
        cortex_m::interrupt::free(|cs| {
            let rcc = RCC.borrow(cs);
            let tim3 = TIM3.borrow(cs);
            let gpiob = GPIOB.borrow(cs);
            let gpioc = GPIOC.borrow(cs);

            // GPIOB and GPIOC Clock Activated
            rcc.ahbenr
                .modify(|_, w| w.iopben().enabled().iopcen().enabled());
            // TIMER Clock Activated
            rcc.apb1enr.modify(|_, w| w.tim3en().enabled());

            match pin {
                Pin::PB4 => {
                    gpiob.moder.modify(|_, w| w.moder4().alternate());
                    gpiob.afrl.modify(|_, w| w.afrl4().af1());
                    gpiob.otyper.modify(|_, w| w.ot4().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc1m().pwmmode1().oc1pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc1p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc1e().active());
                }
                Pin::PB5 => {
                    gpiob.moder.modify(|_, w| w.moder5().alternate());
                    gpiob.afrl.modify(|_, w| w.afrl5().af1());
                    gpiob.otyper.modify(|_, w| w.ot5().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc2m().pwmmode1().oc2pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc2p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc2e().active());
                }
                Pin::PC6 => {
                    gpioc.moder.modify(|_, w| w.moder6().alternate());
                    gpioc.afrl.modify(|_, w| w.afrl6().af0());
                    gpioc.otyper.modify(|_, w| w.ot6().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc1m().pwmmode1().oc1pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc1p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc1e().active());
                }
                Pin::PC7 => {
                    gpioc.moder.modify(|_, w| w.moder7().alternate());
                    gpioc.afrl.modify(|_, w| w.afrl7().af0());
                    gpioc.otyper.modify(|_, w| w.ot7().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc2m().pwmmode1().oc2pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc2p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc2e().active());
                }
                Pin::PC8 => {
                    gpioc.moder.modify(|_, w| w.moder8().alternate());
                    gpioc.afrh.modify(|_, w| w.afrh8().af0());
                    gpioc.otyper.modify(|_, w| w.ot8().push_pull());
                    tim3.ccmr2_output
                        .modify(|_, w| w.oc3m().pwmmode1().oc3pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc3p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc3e().active());
                }
                Pin::PC9 => {
                    gpioc.moder.modify(|_, w| w.moder9().alternate());
                    gpioc.afrh.modify(|_, w| w.afrh9().af0());
                    gpioc.otyper.modify(|_, w| w.ot9().push_pull());
                    tim3.ccmr2_output
                        .modify(|_, w| w.oc4m().pwmmode1().oc4pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc4p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc4e().active());
                }
            }

            tim3.cr1.write(|w| {
                w.cms()
                    .center_align_mode1()
                    .dir()
                    .up()
                    .opm()
                    .continuous()
                    .cen()
                    .enabled()
            });

            tim3.egr.write(|w| w.ug().set_bit());
        });
        Pwm { pin }
    }

    // Be careful, after you have set frequency, it will be necessary to set all duty cycles of others PWMs
    pub fn set_frequency(&self, frequency: u32) {
        cortex_m::interrupt::free(|cs| {
            let tim3 = TIM3.borrow(cs);

            // Set Prescaler Register - 16 bits
            const PRE_SCALER: u16 = ((FREQUENCY / (1_000_000 * 2)) - 1) as u16;
            tim3.psc.write(|w| w.psc().bits(PRE_SCALER)); // Counter clock Frequency = (fCK_PSC / (PSC[15:0] + 1)

            // Set Auto-Reload register - 16 bits
            let arr = 1000000 / frequency; //1000000
            tim3.arr.write(|w| w.arr_h().bits((arr >> 16) as u16));
            tim3.arr.write(|w| w.arr_l().bits(arr as u16));
            unsafe {
                FREQ = frequency;
            }
            unsafe {
                self.set_duty(DUT);
            }
        });
    }

    pub fn enable(&self) {
        cortex_m::interrupt::free(|cs| {
            let tim3 = TIM3.borrow(cs);
            match self.pin {
                Pin::PB4 => tim3.ccer.modify(|_, w| w.cc1e().set_bit()),
                Pin::PB5 => tim3.ccer.modify(|_, w| w.cc2e().set_bit()),
                Pin::PC6 => tim3.ccer.modify(|_, w| w.cc1e().set_bit()),
                Pin::PC7 => tim3.ccer.modify(|_, w| w.cc2e().set_bit()),
                Pin::PC8 => tim3.ccer.modify(|_, w| w.cc3e().set_bit()),
                Pin::PC9 => tim3.ccer.modify(|_, w| w.cc4e().set_bit()),
            }
        });
    }

    pub fn set_duty(&self, duty: f32) {
        cortex_m::interrupt::free(|cs| {
            let tim3 = TIM3.borrow(cs);
            unsafe {
                let ccr_value = (((1000000.0 / FREQ as f32) / 100.0) * duty) as u32;
                DUT = duty;
                match self.pin {
                    Pin::PB4 => tim3.ccr1.write(|w| {
                        w.ccr1_l()
                            .bits((ccr_value) as u16)
                            .ccr1_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PB5 => tim3.ccr2.write(|w| {
                        w.ccr2_l()
                            .bits((ccr_value) as u16)
                            .ccr2_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC6 => tim3.ccr1.write(|w| {
                        w.ccr1_l()
                            .bits((ccr_value) as u16)
                            .ccr1_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC7 => tim3.ccr2.write(|w| {
                        w.ccr2_l()
                            .bits((ccr_value) as u16)
                            .ccr2_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC8 => tim3.ccr3.write(|w| {
                        w.ccr3_l()
                            .bits((ccr_value) as u16)
                            .ccr3_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC9 => tim3.ccr4.write(|w| {
                        w.ccr4_l()
                            .bits((ccr_value) as u16)
                            .ccr4_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                }
            }
        });
    }
}
<commit_msg>Add PA0, PB3, PB10 & PB11 as pwm.<commit_after>use stm32f0x2::{TIM2, TIM3, GPIOA, GPIOB, GPIOC, RCC};

use cortex_m;

static mut FREQ: u32 = 0;
static mut DUTY: f32 = 0.0;
const FREQUENCY: u32 = 48_000_000;

// PWM channels : Pins available
pub enum Pin {
    PA0,
    PB3,
    PB4,
    PB5,
    PB10,
    PB11,
    PC6,
    PC7,
    PC8,
    PC9,
}

pub struct Pwm {
    pin: Pin,
}

impl Pwm {
    pub fn init(pin: Pin) -> Pwm {
        cortex_m::interrupt::free(|cs| {
            let rcc = RCC.borrow(cs);
            let tim2 = TIM2.borrow(cs);
            let tim3 = TIM3.borrow(cs);

            let gpioa = GPIOA.borrow(cs);
            let gpiob = GPIOB.borrow(cs);
            let gpioc = GPIOC.borrow(cs);

            // GPIOA, GPIOB and GPIOC Clock Activated
            rcc.ahbenr
                .modify(|_, w| w.iopaen().enabled().iopben().enabled().iopcen().enabled());
            // TIMER Clock Activated
            rcc.apb1enr.modify(|_, w| w.tim2en().enabled());
            rcc.apb1enr.modify(|_, w| w.tim3en().enabled());

            match pin {
                Pin::PA0 => {
                    gpioa.moder.modify(|_, w| w.moder0().alternate());
                    gpioa.afrl.modify(|_, w| w.afrl0().af2());
                    gpioa.otyper.modify(|_, w| w.ot0().push_pull());
                    tim2.ccmr1_output
                        .modify(|_, w| w.oc1m().pwmmode1().oc1pe().enabled());
                    tim2.ccer.modify(|_, w| w.cc1p().clear_bit());
                    tim2.ccer.modify(|_, w| w.cc1e().active());
                }
                Pin::PB3 => {
                    gpiob.moder.modify(|_, w| w.moder3().alternate());
                    gpiob.afrl.modify(|_, w| w.afrl3().af2());
                    gpiob.otyper.modify(|_, w| w.ot3().push_pull());
                    tim2.ccmr1_output
                        .modify(|_, w| w.oc2m().pwmmode1().oc2pe().enabled());
                    tim2.ccer.modify(|_, w| w.cc2p().clear_bit());
                    tim2.ccer.modify(|_, w| w.cc2e().active());
                }
                Pin::PB10 => {
                    gpiob.moder.modify(|_, w| w.moder10().alternate());
                    gpiob.afrh.modify(|_, w| w.afrh10().af2());
                    gpiob.otyper.modify(|_, w| w.ot10().push_pull());
                    tim2.ccmr2_output
                        .modify(|_, w| w.oc3m().pwmmode1().oc3pe().enabled());
                    tim2.ccer.modify(|_, w| w.cc3p().clear_bit());
                    tim2.ccer.modify(|_, w| w.cc3e().active());
                }
                Pin::PB11 => {
                    gpiob.moder.modify(|_, w| w.moder11().alternate());
                    gpiob.afrh.modify(|_, w| w.afrh11().af2());
                    gpiob.otyper.modify(|_, w| w.ot11().push_pull());
                    tim2.ccmr2_output
                        .modify(|_, w| w.oc4m().pwmmode1().oc4pe().enabled());
                    tim2.ccer.modify(|_, w| w.cc4p().clear_bit());
                    tim2.ccer.modify(|_, w| w.cc4e().active());
                }
                Pin::PB4 => {
                    gpiob.moder.modify(|_, w| w.moder4().alternate());
                    gpiob.afrl.modify(|_, w| w.afrl4().af1());
                    gpiob.otyper.modify(|_, w| w.ot4().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc1m().pwmmode1().oc1pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc1p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc1e().active());
                }
                Pin::PB5 => {
                    gpiob.moder.modify(|_, w| w.moder5().alternate());
                    gpiob.afrl.modify(|_, w| w.afrl5().af1());
                    gpiob.otyper.modify(|_, w| w.ot5().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc2m().pwmmode1().oc2pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc2p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc2e().active());
                }
                Pin::PC6 => {
                    gpioc.moder.modify(|_, w| w.moder6().alternate());
                    gpioc.afrl.modify(|_, w| w.afrl6().af0());
                    gpioc.otyper.modify(|_, w| w.ot6().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc1m().pwmmode1().oc1pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc1p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc1e().active());
                }
                Pin::PC7 => {
                    gpioc.moder.modify(|_, w| w.moder7().alternate());
                    gpioc.afrl.modify(|_, w| w.afrl7().af0());
                    gpioc.otyper.modify(|_, w| w.ot7().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc2m().pwmmode1().oc2pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc2p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc2e().active());
                }
                Pin::PC8 => {
                    gpioc.moder.modify(|_, w| w.moder8().alternate());
                    gpioc.afrh.modify(|_, w| w.afrh8().af0());
                    gpioc.otyper.modify(|_, w| w.ot8().push_pull());
                    tim3.ccmr2_output
                        .modify(|_, w| w.oc3m().pwmmode1().oc3pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc3p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc3e().active());
                }
                Pin::PC9 => {
                    gpioc.moder.modify(|_, w| w.moder9().alternate());
                    gpioc.afrh.modify(|_, w| w.afrh9().af0());
                    gpioc.otyper.modify(|_, w| w.ot9().push_pull());
                    tim3.ccmr2_output
                        .modify(|_, w| w.oc4m().pwmmode1().oc4pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc4p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc4e().active());
                }
            }

            tim2.cr1.write(|w| {
                w.cms()
                    .center_align_mode1()
                    .dir()
                    .up()
                    .opm()
                    .continuous()
                    .cen()
                    .enabled()
            });
            tim2.egr.write(|w| w.ug().set_bit());

            tim3.cr1.write(|w| {
                w.cms()
                    .center_align_mode1()
                    .dir()
                    .up()
                    .opm()
                    .continuous()
                    .cen()
                    .enabled()
            });
            tim3.egr.write(|w| w.ug().set_bit());
        });
        Pwm { pin }
    }

    // Be careful, after you have set frequency, it will be necessary to set all duty cycles of others PWMs
    pub fn set_frequency(&self, frequency: u32) {
        cortex_m::interrupt::free(|cs| {
            let tim2 = TIM2.borrow(cs);
            let tim3 = TIM3.borrow(cs);

            // Set Prescaler Register - 16 bits
            const PRE_SCALER: u16 = ((FREQUENCY / (1_000_000 * 2)) - 1) as u16;
            tim2.psc.write(|w| w.psc().bits(PRE_SCALER));
            tim3.psc.write(|w| w.psc().bits(PRE_SCALER)); // Counter clock Frequency = (fCK_PSC / (PSC[15:0] + 1)

            // Set Auto-Reload register - 16 bits
            let arr = 1000000 / frequency; //1000000
            tim3.arr.write(|w| w.arr_h().bits((arr >> 16) as u16));
            tim3.arr.write(|w| w.arr_l().bits(arr as u16));
            tim2.arr.write(|w| w.arr_h().bits((arr >> 16) as u16));
            tim2.arr.write(|w| w.arr_l().bits(arr as u16));

            unsafe {
                FREQ = frequency;
            }
            unsafe {
                self.set_duty(DUTY);
            }
        });
    }

    pub fn enable(&self) {
        cortex_m::interrupt::free(|cs| {
            let tim2 = TIM2.borrow(cs);
            let tim3 = TIM3.borrow(cs);
            match self.pin {
                Pin::PA0 => tim2.ccer.modify(|_, w| w.cc1e().set_bit()),
                Pin::PB3 => tim2.ccer.modify(|_, w| w.cc2e().set_bit()),
                Pin::PB10 => tim2.ccer.modify(|_, w| w.cc3e().set_bit()),
                Pin::PB11 => tim2.ccer.modify(|_, w| w.cc4e().set_bit()),
                Pin::PB4 => tim3.ccer.modify(|_, w| w.cc1e().set_bit()),
                Pin::PB5 => tim3.ccer.modify(|_, w| w.cc2e().set_bit()),
                Pin::PC6 => tim3.ccer.modify(|_, w| w.cc1e().set_bit()),
                Pin::PC7 => tim3.ccer.modify(|_, w| w.cc2e().set_bit()),
                Pin::PC8 => tim3.ccer.modify(|_, w| w.cc3e().set_bit()),
                Pin::PC9 => tim3.ccer.modify(|_, w| w.cc4e().set_bit()),
            }
        });
    }

    pub fn set_duty(&self, duty: f32) {
        cortex_m::interrupt::free(|cs| {
            let tim2 = TIM2.borrow(cs);
            let tim3 = TIM3.borrow(cs);
            unsafe {
                let ccr_value = (((1000000.0 / FREQ as f32) / 100.0) * duty) as u32;
                DUTY = duty;
                match self.pin {
                    Pin::PA0 => tim2.ccr1.write(|w| {
                        w.ccr1_l()
                            .bits((ccr_value) as u16)
                            .ccr1_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PB3 => tim2.ccr2.write(|w| {
                        w.ccr2_l()
                            .bits((ccr_value) as u16)
                            .ccr2_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PB10 => tim2.ccr3.write(|w| {
                        w.ccr3_l()
                            .bits((ccr_value) as u16)
                            .ccr3_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PB11 => tim2.ccr4.write(|w| {
                        w.ccr4_l()
                            .bits((ccr_value) as u16)
                            .ccr4_h()
                            .bits((ccr_value >> 16) as u16)
                    }),

                    Pin::PB4 => tim3.ccr1.write(|w| {
                        w.ccr1_l()
                            .bits((ccr_value) as u16)
                            .ccr1_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PB5 => tim3.ccr2.write(|w| {
                        w.ccr2_l()
                            .bits((ccr_value) as u16)
                            .ccr2_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC6 => tim3.ccr1.write(|w| {
                        w.ccr1_l()
                            .bits((ccr_value) as u16)
                            .ccr1_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC7 => tim3.ccr2.write(|w| {
                        w.ccr2_l()
                            .bits((ccr_value) as u16)
                            .ccr2_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC8 => tim3.ccr3.write(|w| {
                        w.ccr3_l()
                            .bits((ccr_value) as u16)
                            .ccr3_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC9 => tim3.ccr4.write(|w| {
                        w.ccr4_l()
                            .bits((ccr_value) as u16)
                            .ccr4_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                }
            }
        });
    }
}
<|endoftext|>


<commit_before>//! A collection of traits abstracting over Listeners and Streams.
use std::any::{Any, AnyRefExt};
use std::boxed::BoxAny;
use std::fmt;
use std::intrinsics::TypeId;
use std::io::{IoResult, IoError, ConnectionAborted, InvalidInput, OtherIoError,
              Stream, Listener, Acceptor};
use std::io::net::ip::{SocketAddr, ToSocketAddr, Port};
use std::io::net::tcp::{TcpStream, TcpListener, TcpAcceptor};
use std::mem::{self, transmute, transmute_copy};
use std::raw::{self, TraitObject};

use uany::UnsafeAnyExt;
use openssl::ssl::{Ssl, SslStream, SslContext, VerifyCallback};
use openssl::ssl::SslVerifyMode::SslVerifyPeer;
use openssl::ssl::SslMethod::Sslv23;
use openssl::ssl::error::{SslError, StreamError, OpenSslErrors, SslSessionClosed};

use self::HttpStream::{Http, Https};

/// The write-status indicating headers have not been written.
#[allow(missing_copy_implementations)]
pub struct Fresh;

/// The write-status indicating headers have been written.
#[allow(missing_copy_implementations)]
pub struct Streaming;

/// An abstraction to listen for connections on a certain port.
pub trait NetworkListener<S: NetworkStream, A: NetworkAcceptor<S>>: Listener<S, A> {
    /// Bind to a socket.
    ///
    /// Note: This does not start listening for connections. You must call
    /// `listen()` to do that.
    fn bind<To: ToSocketAddr>(addr: To) -> IoResult<Self>;

    /// Get the address this Listener ended up listening on.
    fn socket_name(&mut self) -> IoResult<SocketAddr>;
}

/// An abstraction to receive `NetworkStream`s.
pub trait NetworkAcceptor<S: NetworkStream>: Acceptor<S> + Clone + Send {
    /// Closes the Acceptor, so no more incoming connections will be handled.
    fn close(&mut self) -> IoResult<()>;
}

/// An abstraction over streams that a Server can utilize.
pub trait NetworkStream: Stream + Any + StreamClone + Send {
    /// Get the remote address of the underlying connection.
    fn peer_name(&mut self) -> IoResult<SocketAddr>;
}

#[doc(hidden)]
pub trait StreamClone {
    fn clone_box(&self) -> Box<NetworkStream + Send>;
}

impl<T: NetworkStream + Send + Clone> StreamClone for T {
    #[inline]
    fn clone_box(&self) -> Box<NetworkStream + Send> {
        box self.clone()
    }
}

/// A connector creates a NetworkStream.
pub trait NetworkConnector<S: NetworkStream> {
    /// Connect to a remote address.
    fn connect(&mut self, host: &str, port: Port, scheme: &str) -> IoResult<S>;
}

impl fmt::Show for Box<NetworkStream + Send> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.pad("Box<NetworkStream>")
    }
}

impl Clone for Box<NetworkStream + Send> {
    #[inline]
    fn clone(&self) -> Box<NetworkStream + Send> { self.clone_box() }
}

impl Reader for Box<NetworkStream + Send> {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { (**self).read(buf) }
}

impl Writer for Box<NetworkStream + Send> {
    #[inline]
    fn write(&mut self, msg: &[u8]) -> IoResult<()> { (**self).write(msg) }

    #[inline]
    fn flush(&mut self) -> IoResult<()> { (**self).flush() }
}

impl<'a> Reader for &'a mut NetworkStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { (**self).read(buf) }
}

impl<'a> Writer for &'a mut NetworkStream {
    #[inline]
    fn write(&mut self, msg: &[u8]) -> IoResult<()> { (**self).write(msg) }

    #[inline]
    fn flush(&mut self) -> IoResult<()> { (**self).flush() }
}

impl UnsafeAnyExt for NetworkStream + Send {
    unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
        mem::transmute(mem::transmute::<&(NetworkStream + Send),
                                        raw::TraitObject>(self).data)
    }

    unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
        mem::transmute(mem::transmute::<&mut (NetworkStream + Send),
                                        raw::TraitObject>(self).data)
    }

    unsafe fn downcast_unchecked<T: 'static>(self: Box<NetworkStream + Send>) -> Box<T>  {
        mem::transmute(mem::transmute::<Box<NetworkStream + Send>,
                                        raw::TraitObject>(self).data)
    }
}

impl<'a> AnyRefExt<'a> for &'a (NetworkStream + 'static) {
    #[inline]
    fn is<T: 'static>(self) -> bool {
        self.get_type_id() == TypeId::of::<T>()
    }

    #[inline]
    fn downcast_ref<T: 'static>(self) -> Option<&'a T> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject = transmute_copy(&self);
                // Extract the data pointer
                Some(transmute(to.data))
            }
        } else {
            None
        }
    }
}

impl BoxAny for Box<NetworkStream + Send> {
    fn downcast<T: 'static>(self) -> Result<Box<T>, Box<NetworkStream + Send>> {
        if self.is::<T>() {
            Ok(unsafe { self.downcast_unchecked() })
        } else {
            Err(self)
        }
    }
}

/// A `NetworkListener` for `HttpStream`s.
pub struct HttpListener {
    inner: TcpListener
}

impl Listener<HttpStream, HttpAcceptor> for HttpListener {
    #[inline]
    fn listen(self) -> IoResult<HttpAcceptor> {
        Ok(HttpAcceptor {
            inner: try!(self.inner.listen())
        })
    }
}

impl NetworkListener<HttpStream, HttpAcceptor> for HttpListener {
    #[inline]
    fn bind<To: ToSocketAddr>(addr: To) -> IoResult<HttpListener> {
        Ok(HttpListener {
            inner: try!(TcpListener::bind(addr))
        })
    }

    #[inline]
    fn socket_name(&mut self) -> IoResult<SocketAddr> {
        self.inner.socket_name()
    }
}

/// A `NetworkAcceptor` for `HttpStream`s.
#[derive(Clone)]
pub struct HttpAcceptor {
    inner: TcpAcceptor
}

impl Acceptor<HttpStream> for HttpAcceptor {
    #[inline]
    fn accept(&mut self) -> IoResult<HttpStream> {
        Ok(Http(try!(self.inner.accept())))
    }
}

impl NetworkAcceptor<HttpStream> for HttpAcceptor {
    #[inline]
    fn close(&mut self) -> IoResult<()> {
        self.inner.close_accept()
    }
}

/// A wrapper around a TcpStream.
#[derive(Clone)]
pub enum HttpStream {
    /// A stream over the HTTP protocol.
    Http(TcpStream),
    /// A stream over the HTTP protocol, protected by SSL.
    Https(SslStream<TcpStream>),
}

impl Reader for HttpStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match *self {
            Http(ref mut inner) => inner.read(buf),
            Https(ref mut inner) => inner.read(buf)
        }
    }
}

impl Writer for HttpStream {
    #[inline]
    fn write(&mut self, msg: &[u8]) -> IoResult<()> {
        match *self {
            Http(ref mut inner) => inner.write(msg),
            Https(ref mut inner) => inner.write(msg)
        }
    }
    #[inline]
    fn flush(&mut self) -> IoResult<()> {
        match *self {
            Http(ref mut inner) => inner.flush(),
            Https(ref mut inner) => inner.flush(),
        }
    }
}

impl NetworkStream for HttpStream {
    fn peer_name(&mut self) -> IoResult<SocketAddr> {
        match *self {
            Http(ref mut inner) => inner.peer_name(),
            Https(ref mut inner) => inner.get_mut().peer_name()
        }
    }
}

/// A connector that will produce HttpStreams.
#[allow(missing_copy_implementations)]
pub struct HttpConnector(pub Option<VerifyCallback>);

impl NetworkConnector<HttpStream> for HttpConnector {
    fn connect(&mut self, host: &str, port: Port, scheme: &str) -> IoResult<HttpStream> {
        let addr = (host, port);
        match scheme {
            "http" => {
                debug!("http scheme");
                Ok(Http(try!(TcpStream::connect(addr))))
            },
            "https" => {
                debug!("https scheme");
                let stream = try!(TcpStream::connect(addr));
                let mut context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error));
                self.0.as_ref().map(|cb| context.set_verify(SslVerifyPeer, Some(*cb)));
                let ssl = try!(Ssl::new(&context).map_err(lift_ssl_error));
                try!(ssl.set_hostname(host).map_err(lift_ssl_error));
                let stream = try!(SslStream::new(&context, stream).map_err(lift_ssl_error));
                Ok(Https(stream))
            },
            _ => {
                Err(IoError {
                    kind: InvalidInput,
                    desc: "Invalid scheme for Http",
                    detail: None
                })
            }
        }
    }
}

fn lift_ssl_error(ssl: SslError) -> IoError {
    debug!("lift_ssl_error: {}", ssl);
    match ssl {
        StreamError(err) => err,
        SslSessionClosed => IoError {
            kind: ConnectionAborted,
            desc: "SSL Connection Closed",
            detail: None
        },
        // Unfortunately throw this away. No way to support this
        // detail without a better Error abstraction.
        OpenSslErrors(errs) => IoError {
            kind: OtherIoError,
            desc: "Error in OpenSSL",
            detail: Some(format!("{}", errs))
        }
    }
}

#[cfg(test)]
mod tests {
    use std::boxed::BoxAny;
    use uany::UnsafeAnyExt;

    use mock::MockStream;
    use super::NetworkStream;

    #[test]
    fn test_downcast_box_stream() {
        let stream = box MockStream::new() as Box<NetworkStream + Send>;

        let mock = stream.downcast::<MockStream>().unwrap();
        assert_eq!(mock, box MockStream::new());

    }

    #[test]
    fn test_downcast_unchecked_box_stream() {
        let stream = box MockStream::new() as Box<NetworkStream + Send>;

        let mock = unsafe { stream.downcast_unchecked::<MockStream>() };
        assert_eq!(mock, box MockStream::new());

    }

}
<commit_msg>Make downcasting inherent methods on NetworkStream.<commit_after>//! A collection of traits abstracting over Listeners and Streams.
use std::any::Any;
use std::fmt;
use std::intrinsics::TypeId;
use std::io::{IoResult, IoError, ConnectionAborted, InvalidInput, OtherIoError,
              Stream, Listener, Acceptor};
use std::io::net::ip::{SocketAddr, ToSocketAddr, Port};
use std::io::net::tcp::{TcpStream, TcpListener, TcpAcceptor};
use std::mem;
use std::raw::{self, TraitObject};

use uany::UnsafeAnyExt;
use openssl::ssl::{Ssl, SslStream, SslContext, VerifyCallback};
use openssl::ssl::SslVerifyMode::SslVerifyPeer;
use openssl::ssl::SslMethod::Sslv23;
use openssl::ssl::error::{SslError, StreamError, OpenSslErrors, SslSessionClosed};

use self::HttpStream::{Http, Https};

/// The write-status indicating headers have not been written.
#[allow(missing_copy_implementations)]
pub struct Fresh;

/// The write-status indicating headers have been written.
#[allow(missing_copy_implementations)]
pub struct Streaming;

/// An abstraction to listen for connections on a certain port.
pub trait NetworkListener<S: NetworkStream, A: NetworkAcceptor<S>>: Listener<S, A> {
    /// Bind to a socket.
    ///
    /// Note: This does not start listening for connections. You must call
    /// `listen()` to do that.
    fn bind<To: ToSocketAddr>(addr: To) -> IoResult<Self>;

    /// Get the address this Listener ended up listening on.
    fn socket_name(&mut self) -> IoResult<SocketAddr>;
}

/// An abstraction to receive `NetworkStream`s.
pub trait NetworkAcceptor<S: NetworkStream>: Acceptor<S> + Clone + Send {
    /// Closes the Acceptor, so no more incoming connections will be handled.
    fn close(&mut self) -> IoResult<()>;
}

/// An abstraction over streams that a Server can utilize.
pub trait NetworkStream: Stream + Any + StreamClone + Send {
    /// Get the remote address of the underlying connection.
    fn peer_name(&mut self) -> IoResult<SocketAddr>;
}

#[doc(hidden)]
pub trait StreamClone {
    fn clone_box(&self) -> Box<NetworkStream + Send>;
}

impl<T: NetworkStream + Send + Clone> StreamClone for T {
    #[inline]
    fn clone_box(&self) -> Box<NetworkStream + Send> {
        box self.clone()
    }
}

/// A connector creates a NetworkStream.
pub trait NetworkConnector<S: NetworkStream> {
    /// Connect to a remote address.
    fn connect(&mut self, host: &str, port: Port, scheme: &str) -> IoResult<S>;
}

impl fmt::Show for Box<NetworkStream + Send> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.pad("Box<NetworkStream>")
    }
}

impl Clone for Box<NetworkStream + Send> {
    #[inline]
    fn clone(&self) -> Box<NetworkStream + Send> { self.clone_box() }
}

impl Reader for Box<NetworkStream + Send> {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { (**self).read(buf) }
}

impl Writer for Box<NetworkStream + Send> {
    #[inline]
    fn write(&mut self, msg: &[u8]) -> IoResult<()> { (**self).write(msg) }

    #[inline]
    fn flush(&mut self) -> IoResult<()> { (**self).flush() }
}

impl<'a> Reader for &'a mut NetworkStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { (**self).read(buf) }
}

impl<'a> Writer for &'a mut NetworkStream {
    #[inline]
    fn write(&mut self, msg: &[u8]) -> IoResult<()> { (**self).write(msg) }

    #[inline]
    fn flush(&mut self) -> IoResult<()> { (**self).flush() }
}

impl UnsafeAnyExt for NetworkStream {
    unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
        mem::transmute(mem::transmute::<&NetworkStream,
                                        raw::TraitObject>(self).data)
    }

    unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
        mem::transmute(mem::transmute::<&mut NetworkStream,
                                        raw::TraitObject>(self).data)
    }

    unsafe fn downcast_unchecked<T: 'static>(self: Box<NetworkStream>) -> Box<T>  {
        mem::transmute(mem::transmute::<Box<NetworkStream>,
                                        raw::TraitObject>(self).data)
    }
}

impl NetworkStream {
    /// Is the underlying type in this trait object a T?
    #[inline]
    pub fn is<T: 'static>(&self) -> bool {
        self.get_type_id() == TypeId::of::<T>()
    }

    /// If the underlying type is T, get a reference to the contained data.
    #[inline]
    pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
        if self.is::<T>() {
            Some(unsafe { self.downcast_ref_unchecked() })
        } else {
            None
        }
    }

    /// If the underlying type is T, get a mutable reference to the contained
    /// data.
    #[inline]
    pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
        if self.is::<T>() {
            Some(unsafe { self.downcast_mut_unchecked() })
        } else {
            None
        }
    }

    /// If the underlying type is T, extract it.
    pub fn downcast<T: 'static>(self: Box<NetworkStream>)
            -> Result<Box<T>, Box<NetworkStream>> {
        if self.is::<T>() {
            Ok(unsafe { self.downcast_unchecked() })
        } else {
            Err(self)
        }
    }
}

/// A `NetworkListener` for `HttpStream`s.
pub struct HttpListener {
    inner: TcpListener
}

impl Listener<HttpStream, HttpAcceptor> for HttpListener {
    #[inline]
    fn listen(self) -> IoResult<HttpAcceptor> {
        Ok(HttpAcceptor {
            inner: try!(self.inner.listen())
        })
    }
}

impl NetworkListener<HttpStream, HttpAcceptor> for HttpListener {
    #[inline]
    fn bind<To: ToSocketAddr>(addr: To) -> IoResult<HttpListener> {
        Ok(HttpListener {
            inner: try!(TcpListener::bind(addr))
        })
    }

    #[inline]
    fn socket_name(&mut self) -> IoResult<SocketAddr> {
        self.inner.socket_name()
    }
}

/// A `NetworkAcceptor` for `HttpStream`s.
#[derive(Clone)]
pub struct HttpAcceptor {
    inner: TcpAcceptor
}

impl Acceptor<HttpStream> for HttpAcceptor {
    #[inline]
    fn accept(&mut self) -> IoResult<HttpStream> {
        Ok(Http(try!(self.inner.accept())))
    }
}

impl NetworkAcceptor<HttpStream> for HttpAcceptor {
    #[inline]
    fn close(&mut self) -> IoResult<()> {
        self.inner.close_accept()
    }
}

/// A wrapper around a TcpStream.
#[derive(Clone)]
pub enum HttpStream {
    /// A stream over the HTTP protocol.
    Http(TcpStream),
    /// A stream over the HTTP protocol, protected by SSL.
    Https(SslStream<TcpStream>),
}

impl Reader for HttpStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match *self {
            Http(ref mut inner) => inner.read(buf),
            Https(ref mut inner) => inner.read(buf)
        }
    }
}

impl Writer for HttpStream {
    #[inline]
    fn write(&mut self, msg: &[u8]) -> IoResult<()> {
        match *self {
            Http(ref mut inner) => inner.write(msg),
            Https(ref mut inner) => inner.write(msg)
        }
    }
    #[inline]
    fn flush(&mut self) -> IoResult<()> {
        match *self {
            Http(ref mut inner) => inner.flush(),
            Https(ref mut inner) => inner.flush(),
        }
    }
}

impl NetworkStream for HttpStream {
    fn peer_name(&mut self) -> IoResult<SocketAddr> {
        match *self {
            Http(ref mut inner) => inner.peer_name(),
            Https(ref mut inner) => inner.get_mut().peer_name()
        }
    }
}

/// A connector that will produce HttpStreams.
#[allow(missing_copy_implementations)]
pub struct HttpConnector(pub Option<VerifyCallback>);

impl NetworkConnector<HttpStream> for HttpConnector {
    fn connect(&mut self, host: &str, port: Port, scheme: &str) -> IoResult<HttpStream> {
        let addr = (host, port);
        match scheme {
            "http" => {
                debug!("http scheme");
                Ok(Http(try!(TcpStream::connect(addr))))
            },
            "https" => {
                debug!("https scheme");
                let stream = try!(TcpStream::connect(addr));
                let mut context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error));
                self.0.as_ref().map(|cb| context.set_verify(SslVerifyPeer, Some(*cb)));
                let ssl = try!(Ssl::new(&context).map_err(lift_ssl_error));
                try!(ssl.set_hostname(host).map_err(lift_ssl_error));
                let stream = try!(SslStream::new(&context, stream).map_err(lift_ssl_error));
                Ok(Https(stream))
            },
            _ => {
                Err(IoError {
                    kind: InvalidInput,
                    desc: "Invalid scheme for Http",
                    detail: None
                })
            }
        }
    }
}

fn lift_ssl_error(ssl: SslError) -> IoError {
    debug!("lift_ssl_error: {}", ssl);
    match ssl {
        StreamError(err) => err,
        SslSessionClosed => IoError {
            kind: ConnectionAborted,
            desc: "SSL Connection Closed",
            detail: None
        },
        // Unfortunately throw this away. No way to support this
        // detail without a better Error abstraction.
        OpenSslErrors(errs) => IoError {
            kind: OtherIoError,
            desc: "Error in OpenSSL",
            detail: Some(format!("{}", errs))
        }
    }
}

#[cfg(test)]
mod tests {
    use std::boxed::BoxAny;
    use uany::UnsafeAnyExt;

    use mock::MockStream;
    use super::NetworkStream;

    #[test]
    fn test_downcast_box_stream() {
        let stream = box MockStream::new() as Box<NetworkStream + Send>;

        let mock = stream.downcast::<MockStream>().ok().unwrap();
        assert_eq!(mock, box MockStream::new());

    }

    #[test]
    fn test_downcast_unchecked_box_stream() {
        let stream = box MockStream::new() as Box<NetworkStream + Send>;

        let mock = unsafe { stream.downcast_unchecked::<MockStream>() };
        assert_eq!(mock, box MockStream::new());

    }

}
<|endoftext|>