<commit_before>// Rx -- Reactive programming for Rust
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

#![feature(fn_traits, unboxed_closures)]

use std::iter::IntoIterator;

mod observer;

pub use observer::{Observer, PanickingObserver};

trait Observable<'this> where Self: 'this {
    type Item;
    type Error;
    type Subscription: Drop;

    fn subscribe<O>(&'this mut self, observer: O) -> Self::Subscription
        where O: Observer<Self::Item, Self::Error>;
}

struct UncancellableSubscription;

impl Drop for UncancellableSubscription {
    fn drop(&mut self) { }
}

impl<'i, I> Observable<'i> for &'i I where &'i I: IntoIterator {
    type Item = <&'i I as IntoIterator>::Item;
    type Error = ();
    type Subscription = UncancellableSubscription;

    fn subscribe<O>(&'i mut self, mut observer: O) -> UncancellableSubscription
        where O: Observer<Self::Item, Self::Error> {
        for x in self.into_iter() {
            observer.on_next(x);
        }
        observer.on_completed();
        UncancellableSubscription
    }
}

#[test]
fn it_works() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    values.subscribe(|x| println!("{:?}", x));
}
<commit_msg>Simplify lifetimes<commit_after>// Rx -- Reactive programming for Rust
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

#![feature(fn_traits, unboxed_closures)]

use std::iter::IntoIterator;

mod observer;

pub use observer::{Observer, PanickingObserver};

trait Observable {
    type Item;
    type Error;
    type Subscription: Drop;

    fn subscribe<O>(&mut self, observer: O) -> Self::Subscription
        where O: Observer<Self::Item, Self::Error>;
}

struct UncancellableSubscription;

impl Drop for UncancellableSubscription {
    fn drop(&mut self) { }
}

impl<'i, I> Observable for &'i I where &'i I: IntoIterator {
    type Item = <&'i I as IntoIterator>::Item;
    type Error = ();
    type Subscription = UncancellableSubscription;

    fn subscribe<O>(&mut self, mut observer: O) -> UncancellableSubscription
        where O: Observer<Self::Item, Self::Error> {
        for x in self.into_iter() {
            observer.on_next(x);
        }
        observer.on_completed();
        UncancellableSubscription
    }
}

#[test]
fn it_works() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    values.subscribe(|x| println!("{:?}", x));
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name = "core_foundation"]
#![crate_type = "rlib"]

#![allow(non_snake_case_functions)]

extern crate libc;
extern crate std;
extern crate debug;

#[cfg(target_os="macos")]
pub mod array;
#[cfg(target_os="macos")]
pub mod base;
#[cfg(target_os="macos")]
pub mod boolean;
#[cfg(target_os="macos")]
pub mod data;
#[cfg(target_os="macos")]
pub mod dictionary;
#[cfg(target_os="macos")]
pub mod number;
#[cfg(target_os="macos")]
pub mod set;
#[cfg(target_os="macos")]
pub mod string;
#[cfg(target_os="macos")]
pub mod url;

#[cfg(target_os="macos")]
#[cfg(test)]
pub mod test {
    #[test]
    fn test_stuff() {
        use base::TCFType;
        use boolean::CFBoolean;
        use number::number;
        use dictionary::CFDictionary;
        use string::CFString;

        /*let n = CFNumber::new_number(42 as i32);
        io::println(format!("%d", (&n).retain_count() as int));
        (&n).show();*/

        let bar = CFString::from_static_string("Bar");
        let baz = CFString::from_static_string("Baz");
        let boo = CFString::from_static_string("Boo");
        let foo = CFString::from_static_string("Foo");
        let tru = CFBoolean::true_value();
        let n42 = number(42);

        let _d = CFDictionary::from_CFType_pairs([
            (bar.as_CFType(), boo.as_CFType()),
            (baz.as_CFType(), tru.as_CFType()),
            (foo.as_CFType(), n42.as_CFType()),
        ]);
    }
}
<commit_msg>Rust upgrade<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name = "core_foundation"]
#![crate_type = "rlib"]

#![allow(non_snake_case_functions)]

extern crate libc;
extern crate debug;

#[cfg(target_os="macos")]
pub mod array;
#[cfg(target_os="macos")]
pub mod base;
#[cfg(target_os="macos")]
pub mod boolean;
#[cfg(target_os="macos")]
pub mod data;
#[cfg(target_os="macos")]
pub mod dictionary;
#[cfg(target_os="macos")]
pub mod number;
#[cfg(target_os="macos")]
pub mod set;
#[cfg(target_os="macos")]
pub mod string;
#[cfg(target_os="macos")]
pub mod url;

#[cfg(target_os="macos")]
#[cfg(test)]
pub mod test {
    #[test]
    fn test_stuff() {
        use base::TCFType;
        use boolean::CFBoolean;
        use number::number;
        use dictionary::CFDictionary;
        use string::CFString;

        /*let n = CFNumber::new_number(42 as i32);
        io::println(format!("%d", (&n).retain_count() as int));
        (&n).show();*/

        let bar = CFString::from_static_string("Bar");
        let baz = CFString::from_static_string("Baz");
        let boo = CFString::from_static_string("Boo");
        let foo = CFString::from_static_string("Foo");
        let tru = CFBoolean::true_value();
        let n42 = number(42);

        let _d = CFDictionary::from_CFType_pairs([
            (bar.as_CFType(), boo.as_CFType()),
            (baz.as_CFType(), tru.as_CFType()),
            (foo.as_CFType(), n42.as_CFType()),
        ]);
    }
}
<|endoftext|>


<commit_before>//! Rustic scripts (`#!/usr/bin/rustic`) with access to the Cargo ecosystem

#![deny(missing_docs)]
#![deny(warnings)]

#[macro_use] extern crate log;
#[macro_use] extern crate clap;
#[macro_use] extern crate sha1;

extern crate env_logger;
extern crate lines;

use std::path::PathBuf;
use std::process::Command;
use std::{fmt, io};

use cargo::Project;
use clap::{Arg, App, ClapErrorType};

pub mod cargo;

/// Errors
#[derive(Debug)]
pub enum Error {
    /// `cargo build` failed
    CargoBuild(Vec<u8>),
    /// `cargo new` failed
    CargoNew(Vec<u8>),
    /// IO error
    Io(io::Error),
    /// Logger initialization failed
    Log(log::SetLoggerError),
    /// `time.stamp` is malformed
    MalformedTimestamp(String),
    /// Wrong arguments passed
    WrongArgs(clap::ClapError),
    /// Can't find cache directory
    NoCacheDir,
    /// First argument is not a file
    NotAFile(PathBuf),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            CargoBuild(ref stderr) => {
                let stderr = String::from_utf8_lossy(stderr);
                write!(f, "`cargo build` failed with:\n{}`", stderr)
            },
            CargoNew(ref stderr) => {
                let stderr = String::from_utf8_lossy(stderr);
                write!(f, "`cargo new` failed with:\n{}", stderr)
            },
            Io(ref e) => e.fmt(f),
            Log(ref e) => e.fmt(f),
            MalformedTimestamp(ref s) => write!(f, "malformed timestamp: {}", s),
            WrongArgs(ref e) => e.fmt(f),
            NoCacheDir => f.write_str("Couldn't find cache directory (is $HOME not set?)"),
            NotAFile(ref path) => write!(f, "{:?} is not a file", path),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Error {
        Error::Io(e)
    }
}

impl From<log::SetLoggerError> for Error {
    fn from(e: log::SetLoggerError) -> Error {
        Error::Log(e)
    }
}

impl From<clap::ClapError> for Error {
    fn from(e: clap::ClapError) -> Error {
        Error::WrongArgs(e)
    }
}

fn init_logger() -> Result<(), Error> {
    try!(env_logger::init());
    Ok(())
}

/// Entry point for the `rustic` binary
pub fn run() -> Result<Option<i32>, Error> {
    try!(init_logger());

    let clap_result = App::new("rustc")
        .version(&crate_version!()[..])
        .author("Jorge Aparicio <japaricious@gmail.com>")
        .about("Cargo wrapper that lets you run Rust source files like scripts")
        .arg(Arg::with_name("FILE")
            .index(1)
            .help("Rust source file to compile and run")
            .required(true)
        )
        .arg(Arg::with_name("ARGS")
            .index(2)
            .multiple(true)
            .help("Arguments for the compiled program")
            .required(false)
        )
        .get_matches_safe();

    match clap_result {
        Err(err) => match err.error_type {
            ClapErrorType::VersionDisplayed => {
                try!(try!(Command::new("rustc").arg("-V").spawn()).wait());
                try!(try!(Command::new("cargo").arg("-V").spawn()).wait());
                Ok(None)
            },
            ClapErrorType::HelpDisplayed => Ok(None),
            _ => Err(err.into())
        },
        Ok(matches) => {
            let project = try!(Project::new(PathBuf::from(matches.value_of("FILE").unwrap())));

            if try!(project.has_changed()) {
                try!(project.update_cargo_toml());
                try!(project.remove_lock());
                try!(project.build());
                try!(project.update_timestamp());
            }

            let output = try!(project.run(matches.values_of("ARGS").unwrap_or(vec![])));

            Ok(output.status.code())
        }
    }
}
<commit_msg>fix typo in app name<commit_after>//! Rustic scripts (`#!/usr/bin/rustic`) with access to the Cargo ecosystem

#![deny(missing_docs)]
#![deny(warnings)]

#[macro_use] extern crate log;
#[macro_use] extern crate clap;
#[macro_use] extern crate sha1;

extern crate env_logger;
extern crate lines;

use std::path::PathBuf;
use std::process::Command;
use std::{fmt, io};

use cargo::Project;
use clap::{Arg, App, ClapErrorType};

pub mod cargo;

/// Errors
#[derive(Debug)]
pub enum Error {
    /// `cargo build` failed
    CargoBuild(Vec<u8>),
    /// `cargo new` failed
    CargoNew(Vec<u8>),
    /// IO error
    Io(io::Error),
    /// Logger initialization failed
    Log(log::SetLoggerError),
    /// `time.stamp` is malformed
    MalformedTimestamp(String),
    /// Wrong arguments passed
    WrongArgs(clap::ClapError),
    /// Can't find cache directory
    NoCacheDir,
    /// First argument is not a file
    NotAFile(PathBuf),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            CargoBuild(ref stderr) => {
                let stderr = String::from_utf8_lossy(stderr);
                write!(f, "`cargo build` failed with:\n{}`", stderr)
            },
            CargoNew(ref stderr) => {
                let stderr = String::from_utf8_lossy(stderr);
                write!(f, "`cargo new` failed with:\n{}", stderr)
            },
            Io(ref e) => e.fmt(f),
            Log(ref e) => e.fmt(f),
            MalformedTimestamp(ref s) => write!(f, "malformed timestamp: {}", s),
            WrongArgs(ref e) => e.fmt(f),
            NoCacheDir => f.write_str("Couldn't find cache directory (is $HOME not set?)"),
            NotAFile(ref path) => write!(f, "{:?} is not a file", path),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Error {
        Error::Io(e)
    }
}

impl From<log::SetLoggerError> for Error {
    fn from(e: log::SetLoggerError) -> Error {
        Error::Log(e)
    }
}

impl From<clap::ClapError> for Error {
    fn from(e: clap::ClapError) -> Error {
        Error::WrongArgs(e)
    }
}

fn init_logger() -> Result<(), Error> {
    try!(env_logger::init());
    Ok(())
}

/// Entry point for the `rustic` binary
pub fn run() -> Result<Option<i32>, Error> {
    try!(init_logger());

    let clap_result = App::new("rustic")
        .version(&crate_version!()[..])
        .author("Jorge Aparicio <japaricious@gmail.com>")
        .about("Cargo wrapper that lets you run Rust source files like scripts")
        .arg(Arg::with_name("FILE")
            .index(1)
            .help("Rust source file to compile and run")
            .required(true)
        )
        .arg(Arg::with_name("ARGS")
            .index(2)
            .multiple(true)
            .help("Arguments for the compiled program")
            .required(false)
        )
        .get_matches_safe();

    match clap_result {
        Err(err) => match err.error_type {
            ClapErrorType::VersionDisplayed => {
                try!(try!(Command::new("rustc").arg("-V").spawn()).wait());
                try!(try!(Command::new("cargo").arg("-V").spawn()).wait());
                Ok(None)
            },
            ClapErrorType::HelpDisplayed => Ok(None),
            _ => Err(err.into())
        },
        Ok(matches) => {
            let project = try!(Project::new(PathBuf::from(matches.value_of("FILE").unwrap())));

            if try!(project.has_changed()) {
                try!(project.update_cargo_toml());
                try!(project.remove_lock());
                try!(project.build());
                try!(project.update_timestamp());
            }

            let output = try!(project.run(matches.values_of("ARGS").unwrap_or(vec![])));

            Ok(output.status.code())
        }
    }
}
<|endoftext|>


<commit_before>
extern crate ws;
extern crate url;
extern crate regex;

mod message;
mod user;
mod client;
mod kraken;
mod irc;
mod channel;
mod rfc;
mod subscriber;

macro_rules! get_arg {
	($e:expr) => (env::args().nth($e).unwrap_or(String::from("")));
}

#[cfg(test)]
mod tests {

	use std::env;
	use client::TwitchClient;
	use client::Event;

	#[test]
	fn it_works() {

		let client: TwitchClient;
		let mut user = String::from("");
		let mut pass = String::from("");
		let mut channel = String::from("");
		let mut logging = false;

		for (index, arg) in env::args().enumerate() {
			if index == 0 { continue; }

			match arg.as_ref() {
				"-u" => user = get_arg!(index + 1),
				"-p" => pass = get_arg!(index + 1),
				"-c" => channel = get_arg!(index + 1),
				"-l" => logging = true,
				_ => panic!("Unexpected argument passed: {}", arg),
			}
		}

		client = TwitchClient::from(user, pass, channel, logging);

		client.connect();

		loop {
			match client.recv_event() {
				Ok(Event::MessageReceived(m)) => {

				}
				Err(err) => println!("Error {:?}", err),
			}
		}
	}
}
<commit_msg>Old test code wasnt up to date with the current version of the API, it should be function... untested, WIP<commit_after>
extern crate ws;
extern crate url;
extern crate regex;

mod message;
mod user;
mod client;
mod kraken;
mod irc;
mod channel;
mod rfc;
mod subscriber;

use client::{TwitchClient, Event};

macro_rules! get_arg {
	($e:expr) => (env::args().nth($e).unwrap_or(String::from("")));
}

#[cfg(test)]
mod tests {

	use std::env;
	use client::TwitchClient;
	use client::Event;

	#[test]
	fn it_works() {

		let mut user = String::from("");
		let mut pass = String::from("");
		let mut channel = String::from("");
		let mut logging = false;

		for (index, arg) in env::args().enumerate() {
			if index == 0 { continue; }

			match arg.as_ref() {
				"-u" => user = get_arg!(index + 1),
				"-p" => pass = get_arg!(index + 1),
				"-c" => channel = get_arg!(index + 1),
				"-l" => logging = true,
				_ => panic!("Unexpected argument passed: {}", arg),
			}
		}

		TwitchClient::connect(user, pass, channel, logging, on_event);

		//await
		loop {}
	}

	fn on_event(client: &TwitchClient, event: Event) {
		match event {
			Event::MessageReceived(message) => {
				println!("{}: {}", message.user().display_name(), message.text());
			}
			_ => {}
		}
	}
}
<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(convert)]

use std::borrow::Cow;
use std::borrow::Cow::{Borrowed};

pub fn compile(sass: &str, style: &str) -> Result<String, &'static str> {
    let mut st = SassTokenizer::new(&sass);

    // while let Some(foo) = st.next() {
    //     println!("{:?}", foo);
    // }

    match style {
        "nested"     => Ok(nested_output(&mut st)),
        "compressed" => Ok(compressed_output(&mut st)),
        "expanded"   => Ok(expanded_output(&mut st)),
        "compact"    => Ok(compact_output(&mut st)),
        _            => Err("Unknown style:. Please specify one of nested, compressed, expanded, or compact."),
    }
}

pub fn nested_output(tokenizer: &mut SassTokenizer) -> String {
    let mut output =  String::from_str("");
    while let Some(token) = tokenizer.next() {
        let print_token = match token {
            Event::Start(_) => continue,
            Event::Selector(name) => format!("{} {{", name),
            Event::Property(name, value) => format!("\n  {}: {};", name, value),
            Event::End(_) => format!(" }}\n"),
        };
        output.push_str(print_token.as_str());
    }
    output
}

pub fn compressed_output(tokenizer: &mut SassTokenizer) -> String {
    let mut output =  String::from_str("");
    while let Some(token) = tokenizer.next() {
        let print_token = match token {
            Event::Start(_) => continue,
            Event::Selector(name) => format!("{}{{", name),
            Event::Property(name, value) => format!("{}:{}", name, value),
            Event::End(_) => format!("}}"),
        };
        output.push_str(print_token.as_str());
    }
    output
}

pub fn expanded_output(tokenizer: &mut SassTokenizer) -> String {
    let mut output =  String::from_str("");
    while let Some(token) = tokenizer.next() {
        let print_token = match token {
            Event::Start(_) => continue,
            Event::Selector(name) => format!("{} {{", name),
            Event::Property(name, value) => format!("\n  {}: {};", name, value),
            Event::End(_) => format!("\n}}"),
        };
        output.push_str(print_token.as_str());
    }
    output
}

pub fn compact_output(tokenizer: &mut SassTokenizer) -> String {
    let mut output =  String::from_str("");
    while let Some(token) = tokenizer.next() {
        let print_token = match token {
            Event::Start(_) => continue,
            Event::Selector(name) => format!("{} {{", name),
            Event::Property(name, value) => format!(" {}: {};", name, value),
            Event::End(_) => format!(" }}"),
        };
        output.push_str(print_token.as_str());
    }
    output
}

#[derive(PartialEq, Debug)]
pub enum State {
    StartRule,
    InSelectors,
    InProperties,
}

#[derive(Debug)]
pub enum Rule {
    SassRule,
}

#[derive(Debug)]
pub enum Event<'a> {
    Start(Rule),
    End(Rule),
    Selector(Cow<'a, str>),
    Property(Cow<'a, str>, Cow<'a, str>),
}

#[derive(Debug)]
pub struct SassTokenizer<'a> {
    sass: &'a str,
    offset: usize,
    stack: Vec<Rule>,
    state: State,
}

impl<'a> SassTokenizer<'a> {
    pub fn new(sass: &'a str) -> SassTokenizer<'a> {
        SassTokenizer {
            sass: &sass,
            offset: 0,
            stack: Vec::new(),
            state: State::StartRule,
        }
    }

    pub fn start_rule(&mut self) -> Option<Event<'a>> {
        self.state = State::InSelectors;
        self.stack.push(Rule::SassRule);

        Some(Event::Start(Rule::SassRule))
    }

    fn end(&mut self) -> Event<'a> {
        let rule = self.stack.pop().unwrap();
        self.state = State::StartRule;
        Event::End(rule)
    }

    fn scan_while<F>(&mut self, data: &str, f: F) -> usize
            where F: Fn(u8) -> bool {
        match data.as_bytes().iter().position(|&c| !f(c)) {
            Some(i) => i,
            None => data.len()
        }
    }

    fn skip_leading_whitespace(&mut self) {
        let i = self.offset;
        self.offset += self.scan_while(&self.sass[i..self.sass.len()], is_ascii_whitespace);
    }

    pub fn next_property(&mut self) -> Event<'a> {
        self.skip_leading_whitespace();

        let bytes = self.sass.as_bytes();
        let name_beginning = self.offset;
        let mut i = name_beginning;
        let limit = self.sass.len();

        let c = bytes[i];
        if c == b'}' {
            self.offset += 1;
            return self.end()
        }

        while i < limit {
            match bytes[i..limit].iter().position(|&c| c == b':') {
                Some(pos) => { i += pos; },
                None => { break; },
            }

            let name_end = i;

            i += 1;
            self.offset = i;
            self.skip_leading_whitespace();

            let value_beginning = self.offset;
            i = value_beginning;

            while i < limit {
                match bytes[i..limit].iter().position(|&c| c == b';') {
                    Some(pos) => { i += pos; },
                    None => { i = limit; break; },
                }

                let value_end = i;
                self.offset = i + 1;

                self.skip_leading_whitespace();

                return Event::Property(
                    Borrowed(&self.sass[name_beginning..name_end]),
                    Borrowed(&self.sass[value_beginning..value_end])
                )

            }
        }
        self.offset = self.sass.len();
        Event::Property(Borrowed(""), Borrowed(""))
    }

    pub fn next_selector(&mut self) -> Event<'a> {
        let bytes = self.sass.as_bytes();
        let beginning = self.offset;
        let mut i = beginning;
        let limit = self.sass.len();

        while i < limit {
            match bytes[i..limit].iter().position(|&c| c == b',' || c == b'{') {
                Some(pos) => { i += pos; },
                None => { i = limit; break; },
            }

            let c = bytes[i];

            if c == b',' || c == b'{' {
                let n = scan_trailing_whitespace(&self.sass[beginning..i]);
                let end = i - n;
                if end > beginning {
                    if c == b'{' {
                        self.state = State::InProperties;
                    }
                    self.offset = i + 1;
                    return Event::Selector(Borrowed(&self.sass[beginning..end]));
                }
            }

            self.offset = i;
            if i > beginning {
                return Event::Selector(Borrowed(&self.sass[beginning..i]))
            }
            i += 1;
        }

        if i > beginning {
            self.offset = i;
            Event::Selector(Borrowed(&self.sass[beginning..i]))
        } else {
            self.end()
        }
    }
}

impl<'a> Iterator for SassTokenizer<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Event<'a>> {
        if self.offset < self.sass.len() {
            match self.state {
                State::StartRule => {
                    let ret = self.start_rule();
                    if ret.is_some() {
                        return ret
                    }
                },
                State::InSelectors => return Some(self.next_selector()),
                State::InProperties => return Some(self.next_property()),
            }
        }
        None
    }
}

pub fn char_at(s: &str, byte: usize) -> char {
    s[byte..].chars().next().unwrap()
}

pub fn is_ascii_whitespace(c: u8) -> bool {
    c == b'\n' || c == b'\r' || is_ascii_whitespace_no_nl(c)
}

pub fn is_ascii_whitespace_no_nl(c: u8) -> bool {
    c == b'\t' || c == 0x0b || c == 0x0c || c == b' '
}

// unusual among "scan" functions in that it scans from the _back_ of the string
// TODO: should also scan unicode whitespace?
pub fn scan_trailing_whitespace(data: &str) -> usize {
    match data.as_bytes().iter().rev().position(|&c| !is_ascii_whitespace_no_nl(c)) {
        Some(i) => i,
        None => data.len()
    }
}
<commit_msg>Add a debugging output that just prints the tokens<commit_after>#![feature(collections)]
#![feature(convert)]

use std::borrow::Cow;
use std::borrow::Cow::{Borrowed};

pub fn compile(sass: &str, style: &str) -> Result<String, &'static str> {
    let mut st = SassTokenizer::new(&sass);

    match style {
        "nested"     => Ok(nested_output(&mut st)),
        "compressed" => Ok(compressed_output(&mut st)),
        "expanded"   => Ok(expanded_output(&mut st)),
        "compact"    => Ok(compact_output(&mut st)),
        "debug"      => Ok(debug_output(&mut st)),
        _            => Err("Unknown style:. Please specify one of nested, compressed, expanded, or compact."),
    }
}

pub fn nested_output(tokenizer: &mut SassTokenizer) -> String {
    let mut output =  String::from_str("");
    while let Some(token) = tokenizer.next() {
        let print_token = match token {
            Event::Start(_) => continue,
            Event::Selector(name) => format!("{} {{", name),
            Event::Property(name, value) => format!("\n  {}: {};", name, value),
            Event::End(_) => format!(" }}\n"),
        };
        output.push_str(print_token.as_str());
    }
    output
}

pub fn compressed_output(tokenizer: &mut SassTokenizer) -> String {
    let mut output =  String::from_str("");
    while let Some(token) = tokenizer.next() {
        let print_token = match token {
            Event::Start(_) => continue,
            Event::Selector(name) => format!("{}{{", name),
            Event::Property(name, value) => format!("{}:{}", name, value),
            Event::End(_) => format!("}}"),
        };
        output.push_str(print_token.as_str());
    }
    output
}

pub fn expanded_output(tokenizer: &mut SassTokenizer) -> String {
    let mut output =  String::from_str("");
    while let Some(token) = tokenizer.next() {
        let print_token = match token {
            Event::Start(_) => continue,
            Event::Selector(name) => format!("{} {{", name),
            Event::Property(name, value) => format!("\n  {}: {};", name, value),
            Event::End(_) => format!("\n}}"),
        };
        output.push_str(print_token.as_str());
    }
    output
}

pub fn compact_output(tokenizer: &mut SassTokenizer) -> String {
    let mut output =  String::from_str("");
    while let Some(token) = tokenizer.next() {
        let print_token = match token {
            Event::Start(_) => continue,
            Event::Selector(name) => format!("{} {{", name),
            Event::Property(name, value) => format!(" {}: {};", name, value),
            Event::End(_) => format!(" }}"),
        };
        output.push_str(print_token.as_str());
    }
    output
}

pub fn debug_output(tokenizer: &mut SassTokenizer) -> String {
    let mut output =  String::from_str("");
    while let Some(token) = tokenizer.next() {
        output.push_str(format!("{:?}\n", token).as_str());
    }
    output
}

#[derive(PartialEq, Debug)]
pub enum State {
    StartRule,
    InSelectors,
    InProperties,
}

#[derive(Debug)]
pub enum Rule {
    SassRule,
}

#[derive(Debug)]
pub enum Event<'a> {
    Start(Rule),
    End(Rule),
    Selector(Cow<'a, str>),
    Property(Cow<'a, str>, Cow<'a, str>),
}

#[derive(Debug)]
pub struct SassTokenizer<'a> {
    sass: &'a str,
    offset: usize,
    stack: Vec<Rule>,
    state: State,
}

impl<'a> SassTokenizer<'a> {
    pub fn new(sass: &'a str) -> SassTokenizer<'a> {
        SassTokenizer {
            sass: &sass,
            offset: 0,
            stack: Vec::new(),
            state: State::StartRule,
        }
    }

    pub fn start_rule(&mut self) -> Option<Event<'a>> {
        self.state = State::InSelectors;
        self.stack.push(Rule::SassRule);

        Some(Event::Start(Rule::SassRule))
    }

    fn end(&mut self) -> Event<'a> {
        let rule = self.stack.pop().unwrap();
        self.state = State::StartRule;
        Event::End(rule)
    }

    fn scan_while<F>(&mut self, data: &str, f: F) -> usize
            where F: Fn(u8) -> bool {
        match data.as_bytes().iter().position(|&c| !f(c)) {
            Some(i) => i,
            None => data.len()
        }
    }

    fn skip_leading_whitespace(&mut self) {
        let i = self.offset;
        self.offset += self.scan_while(&self.sass[i..self.sass.len()], is_ascii_whitespace);
    }

    pub fn next_property(&mut self) -> Event<'a> {
        self.skip_leading_whitespace();

        let bytes = self.sass.as_bytes();
        let name_beginning = self.offset;
        let mut i = name_beginning;
        let limit = self.sass.len();

        let c = bytes[i];
        if c == b'}' {
            self.offset += 1;
            return self.end()
        }

        while i < limit {
            match bytes[i..limit].iter().position(|&c| c == b':') {
                Some(pos) => { i += pos; },
                None => { break; },
            }

            let name_end = i;

            i += 1;
            self.offset = i;
            self.skip_leading_whitespace();

            let value_beginning = self.offset;
            i = value_beginning;

            while i < limit {
                match bytes[i..limit].iter().position(|&c| c == b';') {
                    Some(pos) => { i += pos; },
                    None => { i = limit; break; },
                }

                let value_end = i;
                self.offset = i + 1;

                self.skip_leading_whitespace();

                return Event::Property(
                    Borrowed(&self.sass[name_beginning..name_end]),
                    Borrowed(&self.sass[value_beginning..value_end])
                )

            }
        }
        self.offset = self.sass.len();
        Event::Property(Borrowed(""), Borrowed(""))
    }

    pub fn next_selector(&mut self) -> Event<'a> {
        let bytes = self.sass.as_bytes();
        let beginning = self.offset;
        let mut i = beginning;
        let limit = self.sass.len();

        while i < limit {
            match bytes[i..limit].iter().position(|&c| c == b',' || c == b'{') {
                Some(pos) => { i += pos; },
                None => { i = limit; break; },
            }

            let c = bytes[i];

            if c == b',' || c == b'{' {
                let n = scan_trailing_whitespace(&self.sass[beginning..i]);
                let end = i - n;
                if end > beginning {
                    if c == b'{' {
                        self.state = State::InProperties;
                    }
                    self.offset = i + 1;
                    return Event::Selector(Borrowed(&self.sass[beginning..end]));
                }
            }

            self.offset = i;
            if i > beginning {
                return Event::Selector(Borrowed(&self.sass[beginning..i]))
            }
            i += 1;
        }

        if i > beginning {
            self.offset = i;
            Event::Selector(Borrowed(&self.sass[beginning..i]))
        } else {
            self.end()
        }
    }
}

impl<'a> Iterator for SassTokenizer<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Event<'a>> {
        if self.offset < self.sass.len() {
            match self.state {
                State::StartRule => {
                    let ret = self.start_rule();
                    if ret.is_some() {
                        return ret
                    }
                },
                State::InSelectors => return Some(self.next_selector()),
                State::InProperties => return Some(self.next_property()),
            }
        }
        None
    }
}

pub fn char_at(s: &str, byte: usize) -> char {
    s[byte..].chars().next().unwrap()
}

pub fn is_ascii_whitespace(c: u8) -> bool {
    c == b'\n' || c == b'\r' || is_ascii_whitespace_no_nl(c)
}

pub fn is_ascii_whitespace_no_nl(c: u8) -> bool {
    c == b'\t' || c == 0x0b || c == 0x0c || c == b' '
}

// unusual among "scan" functions in that it scans from the _back_ of the string
// TODO: should also scan unicode whitespace?
pub fn scan_trailing_whitespace(data: &str) -> usize {
    match data.as_bytes().iter().rev().position(|&c| !is_ascii_whitespace_no_nl(c)) {
        Some(i) => i,
        None => data.len()
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Serde 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. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Serde JSON
//!
//! JSON is a ubiquitous open-standard format that uses human-readable text to
//! transmit data objects consisting of key-value pairs.
//!
//! ```json,ignore
//! {
//!   "name": "John Doe",
//!   "age": 43,
//!   "address": {
//!     "street": "10 Downing Street",
//!     "city": "London"
//!   },
//!   "phones": [
//!     "+44 1234567",
//!     "+44 2345678"
//!   ]
//! }
//! ```
//!
//! There are three common ways that you might find yourself needing to work
//! with JSON data in Rust.
//!
//!  - **As text data.** An unprocessed string of JSON data that you receive on
//!    an HTTP endpoint, read from a file, or prepare to send to a remote
//!    server.
//!  - **As an untyped or loosely typed representation.** Maybe you want to
//!    check that some JSON data is valid before passing it on, but without
//!    knowing the structure of what it contains. Or you want to do very basic
//!    manipulations like insert a key in a particular spot.
//!  - **As a strongly typed Rust data structure.** When you expect all or most
//!    of your data to conform to a particular structure and want to get real
//!    work done without JSON's loosey-goosey nature tripping you up.
//!
//! Serde JSON provides efficient, flexible, safe ways of converting data
//! between each of these representations.
//!
//! # Operating on untyped JSON values
//!
//! Any valid JSON data can be manipulated in the following recursive enum
//! representation. This data structure is [`serde_json::Value`][value].
//!
//! ```rust
//! # use serde_json::{Number, Map};
//! #
//! # #[allow(dead_code)]
//! enum Value {
//!     Null,
//!     Bool(bool),
//!     Number(Number),
//!     String(String),
//!     Array(Vec<Value>),
//!     Object(Map<String, Value>),
//! }
//! ```
//!
//! A string of JSON data can be parsed into a `serde_json::Value` by the
//! [`serde_json::from_str`][from_str] function. There is also
//! [`from_slice`][from_slice] for parsing from a byte slice &[u8] and
//! [`from_reader`][from_reader] for parsing from any `io::Read` like a File or
//! a TCP stream.
//!
//! ```rust
//! extern crate serde_json;
//!
//! use serde_json::{Value, Error};
//!
//! fn untyped_example() -> Result<(), Error> {
//!     // Some JSON input data as a &str. Maybe this comes from the user.
//!     let data = r#"{
//!                     "name": "John Doe",
//!                     "age": 43,
//!                     "phones": [
//!                       "+44 1234567",
//!                       "+44 2345678"
//!                     ]
//!                   }"#;
//!
//!     // Parse the string of data into serde_json::Value.
//!     let v: Value = serde_json::from_str(data)?;
//!
//!     // Access parts of the data by indexing with square brackets.
//!     println!("Please call {} at the number {}", v["name"], v["phones"][0]);
//!
//!     Ok(())
//! }
//! #
//! # fn main() {
//! #     untyped_example().unwrap();
//! # }
//! ```
//!
//! The `Value` representation is sufficient for very basic tasks but can be
//! tedious to work with for anything more significant. Error handling is
//! verbose to implement correctly, for example imagine trying to detect the
//! presence of unrecognized fields in the input data. The compiler is powerless
//! to help you when you make a mistake, for example imagine typoing `v["name"]`
//! as `v["nmae"]` in one of the dozens of places it is used in your code.
//!
//! # Parsing JSON as strongly typed data structures
//!
//! Serde provides a powerful way of mapping JSON data into Rust data structures
//! largely automatically.
//!
//! ```rust
//! extern crate serde;
//! extern crate serde_json;
//!
//! #[macro_use]
//! extern crate serde_derive;
//!
//! use serde_json::Error;
//!
//! #[derive(Serialize, Deserialize)]
//! struct Person {
//!     name: String,
//!     age: u8,
//!     phones: Vec<String>,
//! }
//!
//! fn typed_example() -> Result<(), Error> {
//!     // Some JSON input data as a &str. Maybe this comes from the user.
//!     let data = r#"{
//!                     "name": "John Doe",
//!                     "age": 43,
//!                     "phones": [
//!                       "+44 1234567",
//!                       "+44 2345678"
//!                     ]
//!                   }"#;
//!
//!     // Parse the string of data into a Person object. This is exactly the
//!     // same function as the one that produced serde_json::Value above, but
//!     // now we are asking it for a Person as output.
//!     let p: Person = serde_json::from_str(data)?;
//!
//!     // Do things just like with any other Rust data structure.
//!     println!("Please call {} at the number {}", p.name, p.phones[0]);
//!
//!     Ok(())
//! }
//! #
//! # fn main() {
//! #     typed_example().unwrap();
//! # }
//! ```
//!
//! This is the same `serde_json::from_str` function as before, but this time we
//! assign the return value to a variable of type `Person` so Serde will
//! automatically interpret the input data as a `Person` and produce informative
//! error messages if the layout does not conform to what a `Person` is expected
//! to look like.
//!
//! Any type that implements Serde's `Deserialize` trait can be deserialized
//! this way. This includes built-in Rust standard library types like `Vec<T>`
//! and `HashMap<K, V>`, as well as any structs or enums annotated with
//! `#[derive(Deserialize)]`.
//!
//! Once we have `p` of type `Person`, our IDE and the Rust compiler can help us
//! use it correctly like they do for any other Rust code. The IDE can
//! autocomplete field names to prevent typos, which was impossible in the
//! `serde_json::Value` representation. And the Rust compiler can check that
//! when we write `p.phones[0]`, then `p.phones` is guaranteed to be a
//! `Vec<String>` so indexing into it makes sense and produces a `String`.
//!
//! # Constructing JSON values
//!
//! Serde JSON provides a [`json!` macro][macro] to build `serde_json::Value`
//! objects with very natural JSON syntax. In order to use this macro,
//! `serde_json` needs to be imported with the `#[macro_use]` attribute.
//!
//! ```rust
//! #[macro_use]
//! extern crate serde_json;
//!
//! fn main() {
//!     // The type of `john` is `serde_json::Value`
//!     let john = json!({
//!       "name": "John Doe",
//!       "age": 43,
//!       "phones": [
//!         "+44 1234567",
//!         "+44 2345678"
//!       ]
//!     });
//!
//!     println!("first phone number: {}", john["phones"][0]);
//!
//!     // Convert to a string of JSON and print it out
//!     println!("{}", john.to_string());
//! }
//! ```
//!
//! The `Value::to_string()` function converts a `serde_json::Value` into a
//! `String` of JSON text.
//!
//! One neat thing about the `json!` macro is that variables and expressions can
//! be interpolated directly into the JSON value as you are building it. Serde
//! will check at compile time that the value you are interpolating is able to
//! be represented as JSON.
//!
//! ```rust
//! # #[macro_use]
//! # extern crate serde_json;
//! #
//! # fn random_phone() -> u16 { 0 }
//! #
//! # fn main() {
//! let full_name = "John Doe";
//! let age_last_year = 42;
//!
//! // The type of `john` is `serde_json::Value`
//! let john = json!({
//!   "name": full_name,
//!   "age": age_last_year + 1,
//!   "phones": [
//!     format!("+44 {}", random_phone())
//!   ]
//! });
//! #     let _ = john;
//! # }
//! ```
//!
//! This is amazingly convenient but we have the problem we had before with
//! `Value` which is that the IDE and Rust compiler cannot help us if we get it
//! wrong. Serde JSON provides a better way of serializing strongly-typed data
//! structures into JSON text.
//!
//! # Creating JSON by serializing data structures
//!
//! A data structure can be converted to a JSON string by
//! [`serde_json::to_string`][to_string]. There is also
//! [`serde_json::to_vec`][to_vec] which serializes to a `Vec<u8>` and
//! [`serde_json::to_writer`][to_writer] which serializes to any `io::Write`
//! such as a File or a TCP stream.
//!
//! ```rust
//! extern crate serde;
//! extern crate serde_json;
//!
//! #[macro_use]
//! extern crate serde_derive;
//!
//! use serde_json::Error;
//!
//! #[derive(Serialize, Deserialize)]
//! struct Address {
//!     street: String,
//!     city: String,
//! }
//!
//! fn print_an_address() -> Result<(), Error> {
//!     // Some data structure.
//!     let address = Address {
//!         street: "10 Downing Street".to_owned(),
//!         city: "London".to_owned(),
//!     };
//!
//!     // Serialize it to a JSON string.
//!     let j = serde_json::to_string(&address)?;
//!
//!     // Print, write to a file, or send to an HTTP server.
//!     println!("{}", j);
//!
//!     Ok(())
//! }
//! #
//! # fn main() {
//! #     print_an_address().unwrap();
//! # }
//! ```
//!
//! Any type that implements Serde's `Serialize` trait can be serialized this
//! way. This includes built-in Rust standard library types like `Vec<T>` and
//! `HashMap<K, V>`, as well as any structs or enums annotated with
//! `#[derive(Serialize)]`.
//!
//! [value]: https://docs.serde.rs/serde_json/value/enum.Value.html
//! [from_str]: https://docs.serde.rs/serde_json/de/fn.from_str.html
//! [from_slice]: https://docs.serde.rs/serde_json/de/fn.from_slice.html
//! [from_reader]: https://docs.serde.rs/serde_json/de/fn.from_reader.html
//! [to_string]: https://docs.serde.rs/serde_json/ser/fn.to_string.html
//! [to_vec]: https://docs.serde.rs/serde_json/ser/fn.to_vec.html
//! [to_writer]: https://docs.serde.rs/serde_json/ser/fn.to_writer.html
//! [macro]: https://docs.serde.rs/serde_json/macro.json.html

#![doc(html_root_url = "https://docs.rs/serde_json/1.0.2")]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Because of "JavaScript"... fixed in Manishearth/rust-clippy#1071
#![cfg_attr(feature = "cargo-clippy", allow(doc_markdown))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow(
// Deserializer::from_str, into_iter
    should_implement_trait,
// integer and float ser/de requires these sorts of casts
    cast_possible_truncation,
    cast_possible_wrap,
    cast_precision_loss,
    cast_sign_loss,
// string ser/de uses indexing and slicing
    indexing_slicing,
// things are often more readable this way
    shadow_reuse,
    shadow_unrelated,
    single_match_else,
    stutter,
// not practical
    missing_docs_in_private_items,
))]

#![deny(missing_docs)]

extern crate num_traits;
extern crate core;
#[macro_use]
extern crate serde;
extern crate itoa;
extern crate dtoa;
#[cfg(feature = "preserve_order")]
extern crate linked_hash_map;

#[doc(inline)]
pub use self::de::{Deserializer, StreamDeserializer, from_reader, from_slice, from_str};
#[doc(inline)]
pub use self::error::{Error, Result};
#[doc(inline)]
pub use self::ser::{Serializer, to_string, to_string_pretty, to_vec, to_vec_pretty, to_writer,
                    to_writer_pretty};
#[doc(inline)]
pub use self::value::{Map, Number, Value, from_value, to_value};

#[macro_use]
mod macros;

pub mod de;
pub mod error;
pub mod map;
pub mod ser;
pub mod value;

mod iter;
mod number;
mod read;
<commit_msg>Ignore clippy's use_self lint<commit_after>// Copyright 2017 Serde 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. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Serde JSON
//!
//! JSON is a ubiquitous open-standard format that uses human-readable text to
//! transmit data objects consisting of key-value pairs.
//!
//! ```json,ignore
//! {
//!   "name": "John Doe",
//!   "age": 43,
//!   "address": {
//!     "street": "10 Downing Street",
//!     "city": "London"
//!   },
//!   "phones": [
//!     "+44 1234567",
//!     "+44 2345678"
//!   ]
//! }
//! ```
//!
//! There are three common ways that you might find yourself needing to work
//! with JSON data in Rust.
//!
//!  - **As text data.** An unprocessed string of JSON data that you receive on
//!    an HTTP endpoint, read from a file, or prepare to send to a remote
//!    server.
//!  - **As an untyped or loosely typed representation.** Maybe you want to
//!    check that some JSON data is valid before passing it on, but without
//!    knowing the structure of what it contains. Or you want to do very basic
//!    manipulations like insert a key in a particular spot.
//!  - **As a strongly typed Rust data structure.** When you expect all or most
//!    of your data to conform to a particular structure and want to get real
//!    work done without JSON's loosey-goosey nature tripping you up.
//!
//! Serde JSON provides efficient, flexible, safe ways of converting data
//! between each of these representations.
//!
//! # Operating on untyped JSON values
//!
//! Any valid JSON data can be manipulated in the following recursive enum
//! representation. This data structure is [`serde_json::Value`][value].
//!
//! ```rust
//! # use serde_json::{Number, Map};
//! #
//! # #[allow(dead_code)]
//! enum Value {
//!     Null,
//!     Bool(bool),
//!     Number(Number),
//!     String(String),
//!     Array(Vec<Value>),
//!     Object(Map<String, Value>),
//! }
//! ```
//!
//! A string of JSON data can be parsed into a `serde_json::Value` by the
//! [`serde_json::from_str`][from_str] function. There is also
//! [`from_slice`][from_slice] for parsing from a byte slice &[u8] and
//! [`from_reader`][from_reader] for parsing from any `io::Read` like a File or
//! a TCP stream.
//!
//! ```rust
//! extern crate serde_json;
//!
//! use serde_json::{Value, Error};
//!
//! fn untyped_example() -> Result<(), Error> {
//!     // Some JSON input data as a &str. Maybe this comes from the user.
//!     let data = r#"{
//!                     "name": "John Doe",
//!                     "age": 43,
//!                     "phones": [
//!                       "+44 1234567",
//!                       "+44 2345678"
//!                     ]
//!                   }"#;
//!
//!     // Parse the string of data into serde_json::Value.
//!     let v: Value = serde_json::from_str(data)?;
//!
//!     // Access parts of the data by indexing with square brackets.
//!     println!("Please call {} at the number {}", v["name"], v["phones"][0]);
//!
//!     Ok(())
//! }
//! #
//! # fn main() {
//! #     untyped_example().unwrap();
//! # }
//! ```
//!
//! The `Value` representation is sufficient for very basic tasks but can be
//! tedious to work with for anything more significant. Error handling is
//! verbose to implement correctly, for example imagine trying to detect the
//! presence of unrecognized fields in the input data. The compiler is powerless
//! to help you when you make a mistake, for example imagine typoing `v["name"]`
//! as `v["nmae"]` in one of the dozens of places it is used in your code.
//!
//! # Parsing JSON as strongly typed data structures
//!
//! Serde provides a powerful way of mapping JSON data into Rust data structures
//! largely automatically.
//!
//! ```rust
//! extern crate serde;
//! extern crate serde_json;
//!
//! #[macro_use]
//! extern crate serde_derive;
//!
//! use serde_json::Error;
//!
//! #[derive(Serialize, Deserialize)]
//! struct Person {
//!     name: String,
//!     age: u8,
//!     phones: Vec<String>,
//! }
//!
//! fn typed_example() -> Result<(), Error> {
//!     // Some JSON input data as a &str. Maybe this comes from the user.
//!     let data = r#"{
//!                     "name": "John Doe",
//!                     "age": 43,
//!                     "phones": [
//!                       "+44 1234567",
//!                       "+44 2345678"
//!                     ]
//!                   }"#;
//!
//!     // Parse the string of data into a Person object. This is exactly the
//!     // same function as the one that produced serde_json::Value above, but
//!     // now we are asking it for a Person as output.
//!     let p: Person = serde_json::from_str(data)?;
//!
//!     // Do things just like with any other Rust data structure.
//!     println!("Please call {} at the number {}", p.name, p.phones[0]);
//!
//!     Ok(())
//! }
//! #
//! # fn main() {
//! #     typed_example().unwrap();
//! # }
//! ```
//!
//! This is the same `serde_json::from_str` function as before, but this time we
//! assign the return value to a variable of type `Person` so Serde will
//! automatically interpret the input data as a `Person` and produce informative
//! error messages if the layout does not conform to what a `Person` is expected
//! to look like.
//!
//! Any type that implements Serde's `Deserialize` trait can be deserialized
//! this way. This includes built-in Rust standard library types like `Vec<T>`
//! and `HashMap<K, V>`, as well as any structs or enums annotated with
//! `#[derive(Deserialize)]`.
//!
//! Once we have `p` of type `Person`, our IDE and the Rust compiler can help us
//! use it correctly like they do for any other Rust code. The IDE can
//! autocomplete field names to prevent typos, which was impossible in the
//! `serde_json::Value` representation. And the Rust compiler can check that
//! when we write `p.phones[0]`, then `p.phones` is guaranteed to be a
//! `Vec<String>` so indexing into it makes sense and produces a `String`.
//!
//! # Constructing JSON values
//!
//! Serde JSON provides a [`json!` macro][macro] to build `serde_json::Value`
//! objects with very natural JSON syntax. In order to use this macro,
//! `serde_json` needs to be imported with the `#[macro_use]` attribute.
//!
//! ```rust
//! #[macro_use]
//! extern crate serde_json;
//!
//! fn main() {
//!     // The type of `john` is `serde_json::Value`
//!     let john = json!({
//!       "name": "John Doe",
//!       "age": 43,
//!       "phones": [
//!         "+44 1234567",
//!         "+44 2345678"
//!       ]
//!     });
//!
//!     println!("first phone number: {}", john["phones"][0]);
//!
//!     // Convert to a string of JSON and print it out
//!     println!("{}", john.to_string());
//! }
//! ```
//!
//! The `Value::to_string()` function converts a `serde_json::Value` into a
//! `String` of JSON text.
//!
//! One neat thing about the `json!` macro is that variables and expressions can
//! be interpolated directly into the JSON value as you are building it. Serde
//! will check at compile time that the value you are interpolating is able to
//! be represented as JSON.
//!
//! ```rust
//! # #[macro_use]
//! # extern crate serde_json;
//! #
//! # fn random_phone() -> u16 { 0 }
//! #
//! # fn main() {
//! let full_name = "John Doe";
//! let age_last_year = 42;
//!
//! // The type of `john` is `serde_json::Value`
//! let john = json!({
//!   "name": full_name,
//!   "age": age_last_year + 1,
//!   "phones": [
//!     format!("+44 {}", random_phone())
//!   ]
//! });
//! #     let _ = john;
//! # }
//! ```
//!
//! This is amazingly convenient but we have the problem we had before with
//! `Value` which is that the IDE and Rust compiler cannot help us if we get it
//! wrong. Serde JSON provides a better way of serializing strongly-typed data
//! structures into JSON text.
//!
//! # Creating JSON by serializing data structures
//!
//! A data structure can be converted to a JSON string by
//! [`serde_json::to_string`][to_string]. There is also
//! [`serde_json::to_vec`][to_vec] which serializes to a `Vec<u8>` and
//! [`serde_json::to_writer`][to_writer] which serializes to any `io::Write`
//! such as a File or a TCP stream.
//!
//! ```rust
//! extern crate serde;
//! extern crate serde_json;
//!
//! #[macro_use]
//! extern crate serde_derive;
//!
//! use serde_json::Error;
//!
//! #[derive(Serialize, Deserialize)]
//! struct Address {
//!     street: String,
//!     city: String,
//! }
//!
//! fn print_an_address() -> Result<(), Error> {
//!     // Some data structure.
//!     let address = Address {
//!         street: "10 Downing Street".to_owned(),
//!         city: "London".to_owned(),
//!     };
//!
//!     // Serialize it to a JSON string.
//!     let j = serde_json::to_string(&address)?;
//!
//!     // Print, write to a file, or send to an HTTP server.
//!     println!("{}", j);
//!
//!     Ok(())
//! }
//! #
//! # fn main() {
//! #     print_an_address().unwrap();
//! # }
//! ```
//!
//! Any type that implements Serde's `Serialize` trait can be serialized this
//! way. This includes built-in Rust standard library types like `Vec<T>` and
//! `HashMap<K, V>`, as well as any structs or enums annotated with
//! `#[derive(Serialize)]`.
//!
//! [value]: https://docs.serde.rs/serde_json/value/enum.Value.html
//! [from_str]: https://docs.serde.rs/serde_json/de/fn.from_str.html
//! [from_slice]: https://docs.serde.rs/serde_json/de/fn.from_slice.html
//! [from_reader]: https://docs.serde.rs/serde_json/de/fn.from_reader.html
//! [to_string]: https://docs.serde.rs/serde_json/ser/fn.to_string.html
//! [to_vec]: https://docs.serde.rs/serde_json/ser/fn.to_vec.html
//! [to_writer]: https://docs.serde.rs/serde_json/ser/fn.to_writer.html
//! [macro]: https://docs.serde.rs/serde_json/macro.json.html

#![doc(html_root_url = "https://docs.rs/serde_json/1.0.2")]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Because of "JavaScript"... fixed in Manishearth/rust-clippy#1071
#![cfg_attr(feature = "cargo-clippy", allow(doc_markdown))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow(
// Deserializer::from_str, into_iter
    should_implement_trait,
// integer and float ser/de requires these sorts of casts
    cast_possible_truncation,
    cast_possible_wrap,
    cast_precision_loss,
    cast_sign_loss,
// string ser/de uses indexing and slicing
    indexing_slicing,
// things are often more readable this way
    shadow_reuse,
    shadow_unrelated,
    single_match_else,
    stutter,
    use_self,
// not practical
    missing_docs_in_private_items,
))]

#![deny(missing_docs)]

extern crate num_traits;
extern crate core;
#[macro_use]
extern crate serde;
extern crate itoa;
extern crate dtoa;
#[cfg(feature = "preserve_order")]
extern crate linked_hash_map;

#[doc(inline)]
pub use self::de::{Deserializer, StreamDeserializer, from_reader, from_slice, from_str};
#[doc(inline)]
pub use self::error::{Error, Result};
#[doc(inline)]
pub use self::ser::{Serializer, to_string, to_string_pretty, to_vec, to_vec_pretty, to_writer,
                    to_writer_pretty};
#[doc(inline)]
pub use self::value::{Map, Number, Value, from_value, to_value};

#[macro_use]
mod macros;

pub mod de;
pub mod error;
pub mod map;
pub mod ser;
pub mod value;

mod iter;
mod number;
mod read;
<|endoftext|>


<commit_before>extern crate emailaddress;
#[macro_use]
extern crate log;
extern crate hyper;
extern crate iron;
extern crate lettre;
extern crate mustache;
extern crate redis;
extern crate serde;
extern crate serde_json;
extern crate time;
extern crate url;
extern crate urlencoded;

use emailaddress::EmailAddress;
use iron::headers::{ContentType, Location};
use iron::middleware::Handler;
use iron::modifiers;
use iron::method::Method;
use iron::prelude::*;
use iron::status;
use iron::typemap;
use iron::Url;
use serde_json::builder::{ArrayBuilder, ObjectBuilder};
use serde_json::value::Value;
use std::env;
use std::fs::File;
use std::io::{BufReader, Read};
use std::sync::Arc;
use std::error::Error;
use time::now_utc;
use urlencoded::{UrlEncodedBody, UrlEncodedQuery};

pub mod error;
pub mod config;
pub use config::AppConfig;
pub mod crypto;
pub mod email;
pub mod oidc;
pub mod store;
pub mod store_cache;

use error::{BrokerResult, BrokerError};

/// Iron extension key we use to store the redirect_uri.
/// Once set, the error handler will return errors to the RP.
struct RedirectUri;
impl typemap::Key for RedirectUri { type Value = Url; }

/// Macro that creates Handler implementations that log the request,
/// and keep a reference to the AppConfig.
macro_rules! broker_handler {
    ( $name:ident , | $app:ident, $req:ident | $body:block ) => {
        pub struct $name {
            pub app: Arc<AppConfig>,
        }
        impl $name {
            pub fn new(app: &Arc<AppConfig>) -> Self {
                $name { app: app.clone() }
            }
            fn handle_body($app: &AppConfig, $req: &mut Request)
                -> BrokerResult<Response> $body
        }
        impl Handler for $name {
            fn handle(&self, req: &mut Request) -> IronResult<Response> {
                info!("{} {}", req.method, req.url);
                Self::handle_body(&self.app, req)
                    .or_else(|e| handle_error(&self.app, req, e))
            }
        }
    }
}

/// Macro used to extract a parameter from a QueryMap.
///
/// Will return from the caller with a BrokerError if the parameter is missing.
///
/// ```
/// let foo = try_get_param!(params, "foo");
/// ```
macro_rules! try_get_param {
    ( $input:expr , $param:tt ) => {
        try!($input.get($param).map(|list| &list[0]).ok_or_else(|| {
            BrokerError::Input(concat!("missing request parameter ", $param).to_string())
        }))
    }
}

/// Handle an BrokerError and create an IronResult.
///
/// The `broker_handler!` macro calls this on error. We don't use a `From`
/// implementation, because this way we get app and request context, and we
/// don't necessarily have to pass the error on to Iron.
fn handle_error(app: &AppConfig, _: &mut Request, err: BrokerError) -> IronResult<Response> {
    match err {
        BrokerError::Input(_) => {
            let obj = ObjectBuilder::new()
                .insert("error", err.description())
                .build();
            let content = serde_json::to_string(&obj).unwrap();
            let content_type = modifiers::Header(ContentType::json());
            Ok(Response::with((status::BadRequest, content_type, content)))
        }
        BrokerError::Provider(_) => {
            // TODO: Redirect to RP with the error description
            Err(IronError::new(err, status::ServiceUnavailable))
        }
        _ => {
            Err(IronError::new(err, (status::InternalServerError,
                                     modifiers::Header(ContentType::html()),
                                     app.templates.error.render(&[]))))
        }
    }
}

/// Helper function for returning an Iron response with JSON data.
///
/// Serializes the argument value to JSON and returns a HTTP 200 response
/// code with the serialized JSON as the body.
fn json_response(obj: &Value) -> BrokerResult<Response> {
    let content = serde_json::to_string(&obj).unwrap();
    Ok(Response::with((status::Ok,
                       modifiers::Header(ContentType::json()),
                       content)))
}

/// Iron handler for the root path, returns human-friendly message.
///
/// This is not actually used in the protocol.
broker_handler!(WelcomeHandler, |_app, _req| {
    json_response(&ObjectBuilder::new()
        .insert("ladaemon", "Welcome")
        .insert("version", env!("CARGO_PKG_VERSION"))
        .build())
});

/// Iron handler for files in .well-known.
///
/// Mainly directed at Let's Encrypt verification. Returns text/plain always.
broker_handler!(WellKnownHandler, |_app, req| {
    let mut file_name = env::current_dir().unwrap();
    file_name.push(req.url.path().join("/"));
    let file_res = File::open(file_name);
    if file_res.is_err() {
        return Ok(Response::with((status::NotFound)));
    }
    let mut bytes = Vec::<u8>::new();
    let mut reader = BufReader::new(file_res.unwrap());
    let _ = reader.read_to_end(&mut bytes).unwrap();
    Ok(Response::with((status::Ok,
                       modifiers::Header(ContentType::plaintext()),
                       bytes)))
});

/// Iron handler to return the OpenID Discovery document.
///
/// Most of this is hard-coded for now, although the URLs are constructed by
/// using the base URL as configured in the `base_url` configuration value.
broker_handler!(OIDConfigHandler, |app, _req| {
    json_response(&ObjectBuilder::new()
        .insert("issuer", &app.base_url)
        .insert("authorization_endpoint",
                format!("{}/auth", app.base_url))
        .insert("jwks_uri", format!("{}/keys.json", app.base_url))
        .insert("scopes_supported", vec!["openid", "email"])
        .insert("claims_supported",
                vec!["aud", "email", "email_verified", "exp", "iat", "iss", "sub"])
        .insert("response_types_supported", vec!["id_token"])
        .insert("response_modes_supported", vec!["form_post"])
        .insert("grant_types_supported", vec!["implicit"])
        .insert("subject_types_supported", vec!["public"])
        .insert("id_token_signing_alg_values_supported", vec!["RS256"])
        .build())
});

/// Iron handler for the JSON Web Key Set document.
///
/// Respond with the JWK key set containing all of the configured keys.
///
/// Relying Parties will need to fetch this data to be able to verify identity
/// tokens issued by this daemon instance.
broker_handler!(KeysHandler, |app, _req| {
    let mut keys = ArrayBuilder::new();
    for key in &app.keys {
        keys = keys.push(key.public_jwk())
    }
    json_response(&ObjectBuilder::new()
                      .insert("keys", keys.build())
                      .build())
});

/// Iron handler for authentication requests from the RP.
///
/// Calls the `oidc::request()` function if the provided email address's
/// domain matches one of the configured famous providers. Otherwise, calls the
/// `email::request()` function to allow authentication through the email loop.
broker_handler!(AuthHandler, |app, req| {
    let params = try!(
        match req.method {
            Method::Get => {
                req.compute::<UrlEncodedQuery>()
                    .map_err(|_| BrokerError::Input("no query string in GET request".to_string()))
            },
            Method::Post => {
                req.compute::<UrlEncodedBody>()
                    .map_err(|_| BrokerError::Input("no query string in POST data".to_string()))
            },
            _ => {
                panic!("Unsupported method: {}", req.method)
            }
        }
    );

    // Per the OAuth2 spec, we may redirect to the RP once we have validated client_id and
    // redirect_uri. In our case, this means we make redirect_uri available to error handling.
    let client_id = try_get_param!(params, "client_id");
    let redirect_uri = try!(
        Url::parse(try_get_param!(params, "redirect_uri"))
            .map_err(|_| BrokerError::Input("redirect_uri is not a valid URL".to_string()))
    );
    req.extensions.insert::<RedirectUri>(redirect_uri.clone());

    let email_addr = try!(
        EmailAddress::new(try_get_param!(params, "login_hint"))
            .map_err(|_| BrokerError::Input("login_hint is not a valid email address".to_string()))
    );
    let nonce = try_get_param!(params, "nonce");
    if app.providers.contains_key(&email_addr.domain) {

        // OIDC authentication. Redirect to the identity provider.
        let auth_url = try!(oidc::request(app, email_addr, client_id, nonce, &redirect_uri));
        Ok(Response::with((status::SeeOther, modifiers::Header(Location(auth_url.to_string())))))

    } else {

        // Email loop authentication. Render a message and form.
        let session_id = try!(email::request(app, email_addr, client_id, nonce, &redirect_uri));
        Ok(Response::with((status::Ok,
                           modifiers::Header(ContentType::html()),
                           app.templates.confirm_email.render(&[
                               ("client_id", &client_id),
                               ("session_id", &session_id),
                           ]))))

    }
});

/// Helper method to create a JWT for a given email address and origin.
///
/// Builds the JSON payload, then signs it using the last key provided in
/// the configuration object.
fn create_jwt(app: &AppConfig, email: &str, origin: &str, nonce: &str) -> String {
    let now = now_utc().to_timespec().sec;
    let payload = &ObjectBuilder::new()
        .insert("aud", origin)
        .insert("email", email)
        .insert("email_verified", email)
        .insert("exp", now + app.token_validity as i64)
        .insert("iat", now)
        .insert("iss", &app.base_url)
        .insert("sub", email)
        .insert("nonce", nonce)
        .build();
    app.keys.last().unwrap().sign_jws(&payload)
}

/// Helper function for returning a result to the Relying Party.
///
/// Takes an array of `(name, value)` parameter pairs to send to the relier and
/// embeds them in a form in `tmpl/forward.html`, from where it's POSTed to the
/// RP's `redirect_uri` as soon as the page has loaded.
///
/// The return value is a tuple of response modifiers.
fn return_to_relier(app: &AppConfig, redirect_uri: &str, params: &[(&str, &str)])
    -> (hyper::status::StatusCode, modifiers::Header<ContentType>, String) {
    let data = mustache::MapBuilder::new()
        .insert_str("redirect_uri", redirect_uri)
        .insert_map("params", |mut builder| {
            for &param in params {
                let (name, value) = param;
                builder = builder
                    .insert_str("name", name)
                    .insert_str("value", value);
            }
            builder
        })
        .build();
    (status::Ok,
     modifiers::Header(ContentType::html()),
     app.templates.forward.render_data(&data))
}

/// Iron handler for one-time pad email loop confirmation.
///
/// Retrieves the session based session ID and the expected one-time pad.
/// Verify the code and return the resulting token or error to the RP.
broker_handler!(ConfirmHandler, |app, req| {
    let params = try!(
        req.compute::<UrlEncodedQuery>()
            .map_err(|_| BrokerError::Input("no query string in GET request".to_string()))
    );

    let stored = try!(app.store.get_session("email", &try_get_param!(params, "session")));
    req.extensions.insert::<RedirectUri>(Url::parse(&stored["redirect"]).unwrap());

    let code = try_get_param!(params, "code");
    let (jwt, redirect_uri) = try!(email::verify(app, &stored, code));
    Ok(Response::with(return_to_relier(app, &redirect_uri, &[("id_token", &jwt)])))
});

/// Iron handler for OAuth callbacks
///
/// After the user allows or denies the Authentication Request with the famous
/// identity provider, they will be redirected back to the callback handler.
/// Verify the callback data and return the resulting token or error.
broker_handler!(CallbackHandler, |app, req| {
    let params = try!(
        req.compute::<UrlEncodedQuery>()
            .map_err(|_| BrokerError::Input("no query string in GET request".to_string()))
    );

    let stored = try!(app.store.get_session("oidc", &try_get_param!(params, "state")));
    req.extensions.insert::<RedirectUri>(Url::parse(&stored["redirect"]).unwrap());

    let code = try_get_param!(params, "code");
    let (jwt, redirect_uri) = try!(oidc::verify(app, &stored, code));
    Ok(Response::with(return_to_relier(app, &redirect_uri, &[("id_token", &jwt)])))
});
<commit_msg>Move return_to_relier up in source file.<commit_after>extern crate emailaddress;
#[macro_use]
extern crate log;
extern crate hyper;
extern crate iron;
extern crate lettre;
extern crate mustache;
extern crate redis;
extern crate serde;
extern crate serde_json;
extern crate time;
extern crate url;
extern crate urlencoded;

use emailaddress::EmailAddress;
use iron::headers::{ContentType, Location};
use iron::middleware::Handler;
use iron::modifiers;
use iron::method::Method;
use iron::prelude::*;
use iron::status;
use iron::typemap;
use iron::Url;
use serde_json::builder::{ArrayBuilder, ObjectBuilder};
use serde_json::value::Value;
use std::env;
use std::fs::File;
use std::io::{BufReader, Read};
use std::sync::Arc;
use std::error::Error;
use time::now_utc;
use urlencoded::{UrlEncodedBody, UrlEncodedQuery};

pub mod error;
pub mod config;
pub use config::AppConfig;
pub mod crypto;
pub mod email;
pub mod oidc;
pub mod store;
pub mod store_cache;

use error::{BrokerResult, BrokerError};

/// Iron extension key we use to store the redirect_uri.
/// Once set, the error handler will return errors to the RP.
struct RedirectUri;
impl typemap::Key for RedirectUri { type Value = Url; }

/// Macro that creates Handler implementations that log the request,
/// and keep a reference to the AppConfig.
macro_rules! broker_handler {
    ( $name:ident , | $app:ident, $req:ident | $body:block ) => {
        pub struct $name {
            pub app: Arc<AppConfig>,
        }
        impl $name {
            pub fn new(app: &Arc<AppConfig>) -> Self {
                $name { app: app.clone() }
            }
            fn handle_body($app: &AppConfig, $req: &mut Request)
                -> BrokerResult<Response> $body
        }
        impl Handler for $name {
            fn handle(&self, req: &mut Request) -> IronResult<Response> {
                info!("{} {}", req.method, req.url);
                Self::handle_body(&self.app, req)
                    .or_else(|e| handle_error(&self.app, req, e))
            }
        }
    }
}

/// Macro used to extract a parameter from a QueryMap.
///
/// Will return from the caller with a BrokerError if the parameter is missing.
///
/// ```
/// let foo = try_get_param!(params, "foo");
/// ```
macro_rules! try_get_param {
    ( $input:expr , $param:tt ) => {
        try!($input.get($param).map(|list| &list[0]).ok_or_else(|| {
            BrokerError::Input(concat!("missing request parameter ", $param).to_string())
        }))
    }
}

/// Helper function for returning a result to the Relying Party.
///
/// Takes an array of `(name, value)` parameter pairs to send to the relier and
/// embeds them in a form in `tmpl/forward.html`, from where it's POSTed to the
/// RP's `redirect_uri` as soon as the page has loaded.
///
/// The return value is a tuple of response modifiers.
fn return_to_relier(app: &AppConfig, redirect_uri: &str, params: &[(&str, &str)])
    -> (hyper::status::StatusCode, modifiers::Header<ContentType>, String) {
    let data = mustache::MapBuilder::new()
        .insert_str("redirect_uri", redirect_uri)
        .insert_map("params", |mut builder| {
            for &param in params {
                let (name, value) = param;
                builder = builder
                    .insert_str("name", name)
                    .insert_str("value", value);
            }
            builder
        })
        .build();
    (status::Ok,
     modifiers::Header(ContentType::html()),
     app.templates.forward.render_data(&data))
}

/// Handle an BrokerError and create an IronResult.
///
/// The `broker_handler!` macro calls this on error. We don't use a `From`
/// implementation, because this way we get app and request context, and we
/// don't necessarily have to pass the error on to Iron.
fn handle_error(app: &AppConfig, _: &mut Request, err: BrokerError) -> IronResult<Response> {
    match err {
        BrokerError::Input(_) => {
            let obj = ObjectBuilder::new()
                .insert("error", err.description())
                .build();
            let content = serde_json::to_string(&obj).unwrap();
            let content_type = modifiers::Header(ContentType::json());
            Ok(Response::with((status::BadRequest, content_type, content)))
        }
        BrokerError::Provider(_) => {
            // TODO: Redirect to RP with the error description
            Err(IronError::new(err, status::ServiceUnavailable))
        }
        _ => {
            Err(IronError::new(err, (status::InternalServerError,
                                     modifiers::Header(ContentType::html()),
                                     app.templates.error.render(&[]))))
        }
    }
}

/// Helper function for returning an Iron response with JSON data.
///
/// Serializes the argument value to JSON and returns a HTTP 200 response
/// code with the serialized JSON as the body.
fn json_response(obj: &Value) -> BrokerResult<Response> {
    let content = serde_json::to_string(&obj).unwrap();
    Ok(Response::with((status::Ok,
                       modifiers::Header(ContentType::json()),
                       content)))
}

/// Iron handler for the root path, returns human-friendly message.
///
/// This is not actually used in the protocol.
broker_handler!(WelcomeHandler, |_app, _req| {
    json_response(&ObjectBuilder::new()
        .insert("ladaemon", "Welcome")
        .insert("version", env!("CARGO_PKG_VERSION"))
        .build())
});

/// Iron handler for files in .well-known.
///
/// Mainly directed at Let's Encrypt verification. Returns text/plain always.
broker_handler!(WellKnownHandler, |_app, req| {
    let mut file_name = env::current_dir().unwrap();
    file_name.push(req.url.path().join("/"));
    let file_res = File::open(file_name);
    if file_res.is_err() {
        return Ok(Response::with((status::NotFound)));
    }
    let mut bytes = Vec::<u8>::new();
    let mut reader = BufReader::new(file_res.unwrap());
    let _ = reader.read_to_end(&mut bytes).unwrap();
    Ok(Response::with((status::Ok,
                       modifiers::Header(ContentType::plaintext()),
                       bytes)))
});

/// Iron handler to return the OpenID Discovery document.
///
/// Most of this is hard-coded for now, although the URLs are constructed by
/// using the base URL as configured in the `base_url` configuration value.
broker_handler!(OIDConfigHandler, |app, _req| {
    json_response(&ObjectBuilder::new()
        .insert("issuer", &app.base_url)
        .insert("authorization_endpoint",
                format!("{}/auth", app.base_url))
        .insert("jwks_uri", format!("{}/keys.json", app.base_url))
        .insert("scopes_supported", vec!["openid", "email"])
        .insert("claims_supported",
                vec!["aud", "email", "email_verified", "exp", "iat", "iss", "sub"])
        .insert("response_types_supported", vec!["id_token"])
        .insert("response_modes_supported", vec!["form_post"])
        .insert("grant_types_supported", vec!["implicit"])
        .insert("subject_types_supported", vec!["public"])
        .insert("id_token_signing_alg_values_supported", vec!["RS256"])
        .build())
});

/// Iron handler for the JSON Web Key Set document.
///
/// Respond with the JWK key set containing all of the configured keys.
///
/// Relying Parties will need to fetch this data to be able to verify identity
/// tokens issued by this daemon instance.
broker_handler!(KeysHandler, |app, _req| {
    let mut keys = ArrayBuilder::new();
    for key in &app.keys {
        keys = keys.push(key.public_jwk())
    }
    json_response(&ObjectBuilder::new()
                      .insert("keys", keys.build())
                      .build())
});

/// Iron handler for authentication requests from the RP.
///
/// Calls the `oidc::request()` function if the provided email address's
/// domain matches one of the configured famous providers. Otherwise, calls the
/// `email::request()` function to allow authentication through the email loop.
broker_handler!(AuthHandler, |app, req| {
    let params = try!(
        match req.method {
            Method::Get => {
                req.compute::<UrlEncodedQuery>()
                    .map_err(|_| BrokerError::Input("no query string in GET request".to_string()))
            },
            Method::Post => {
                req.compute::<UrlEncodedBody>()
                    .map_err(|_| BrokerError::Input("no query string in POST data".to_string()))
            },
            _ => {
                panic!("Unsupported method: {}", req.method)
            }
        }
    );

    // Per the OAuth2 spec, we may redirect to the RP once we have validated client_id and
    // redirect_uri. In our case, this means we make redirect_uri available to error handling.
    let client_id = try_get_param!(params, "client_id");
    let redirect_uri = try!(
        Url::parse(try_get_param!(params, "redirect_uri"))
            .map_err(|_| BrokerError::Input("redirect_uri is not a valid URL".to_string()))
    );
    req.extensions.insert::<RedirectUri>(redirect_uri.clone());

    let email_addr = try!(
        EmailAddress::new(try_get_param!(params, "login_hint"))
            .map_err(|_| BrokerError::Input("login_hint is not a valid email address".to_string()))
    );
    let nonce = try_get_param!(params, "nonce");
    if app.providers.contains_key(&email_addr.domain) {

        // OIDC authentication. Redirect to the identity provider.
        let auth_url = try!(oidc::request(app, email_addr, client_id, nonce, &redirect_uri));
        Ok(Response::with((status::SeeOther, modifiers::Header(Location(auth_url.to_string())))))

    } else {

        // Email loop authentication. Render a message and form.
        let session_id = try!(email::request(app, email_addr, client_id, nonce, &redirect_uri));
        Ok(Response::with((status::Ok,
                           modifiers::Header(ContentType::html()),
                           app.templates.confirm_email.render(&[
                               ("client_id", &client_id),
                               ("session_id", &session_id),
                           ]))))

    }
});

/// Helper method to create a JWT for a given email address and origin.
///
/// Builds the JSON payload, then signs it using the last key provided in
/// the configuration object.
fn create_jwt(app: &AppConfig, email: &str, origin: &str, nonce: &str) -> String {
    let now = now_utc().to_timespec().sec;
    let payload = &ObjectBuilder::new()
        .insert("aud", origin)
        .insert("email", email)
        .insert("email_verified", email)
        .insert("exp", now + app.token_validity as i64)
        .insert("iat", now)
        .insert("iss", &app.base_url)
        .insert("sub", email)
        .insert("nonce", nonce)
        .build();
    app.keys.last().unwrap().sign_jws(&payload)
}

/// Iron handler for one-time pad email loop confirmation.
///
/// Retrieves the session based session ID and the expected one-time pad.
/// Verify the code and return the resulting token or error to the RP.
broker_handler!(ConfirmHandler, |app, req| {
    let params = try!(
        req.compute::<UrlEncodedQuery>()
            .map_err(|_| BrokerError::Input("no query string in GET request".to_string()))
    );

    let stored = try!(app.store.get_session("email", &try_get_param!(params, "session")));
    req.extensions.insert::<RedirectUri>(Url::parse(&stored["redirect"]).unwrap());

    let code = try_get_param!(params, "code");
    let (jwt, redirect_uri) = try!(email::verify(app, &stored, code));
    Ok(Response::with(return_to_relier(app, &redirect_uri, &[("id_token", &jwt)])))
});

/// Iron handler for OAuth callbacks
///
/// After the user allows or denies the Authentication Request with the famous
/// identity provider, they will be redirected back to the callback handler.
/// Verify the callback data and return the resulting token or error.
broker_handler!(CallbackHandler, |app, req| {
    let params = try!(
        req.compute::<UrlEncodedQuery>()
            .map_err(|_| BrokerError::Input("no query string in GET request".to_string()))
    );

    let stored = try!(app.store.get_session("oidc", &try_get_param!(params, "state")));
    req.extensions.insert::<RedirectUri>(Url::parse(&stored["redirect"]).unwrap());

    let code = try_get_param!(params, "code");
    let (jwt, redirect_uri) = try!(oidc::verify(app, &stored, code));
    Ok(Response::with(return_to_relier(app, &redirect_uri, &[("id_token", &jwt)])))
});
<|endoftext|>


<commit_before>pub mod isomorphism;
pub mod parametric;

use isomorphism::{Iso, IsoOnce};
use parametric::{Param, ReParam};

pub trait Covariant<'a, B>: ReParam<B> {
    fn fmap<F: 'a + Fn(Self::Param) -> B>(self, F) -> Self::Output;
}

pub trait CovariantOnce<'a, B>: ReParam<B> {
    fn fmap_once<F: 'a + FnOnce(Self::Param) -> B>(self, F) -> Self::Output;
}

pub trait Contravariant<'a, B>: ReParam<B> {
    fn contramap<F: 'a + Fn(B) -> Self::Param>(self, F) -> Self::Output;
}

pub trait ContravariantOnce<'a, B>: ReParam<B> {
    fn contramap_once<F: 'a + FnOnce(B) -> Self::Param>(self, F) -> Self::Output;
}

pub trait Invariant<'a, B>: ReParam<B> {
    fn invmap<F: 'a + Iso<Self::Param, B>>(self, F) -> Self::Output;
}

pub trait InvariantOnce<'a, B>: ReParam<B> {
    fn invmap_once<F: 'a + IsoOnce<Self::Param, B>>(self, F) -> Self::Output;
}

pub trait Bivariant<'a, B>: ReParam<B> {
    fn xmap(self) -> Self::Output;
}

impl<'a, A, B> Covariant<'a, B> for std::option::Option<A> {
    fn fmap<F: 'a + Fn(A) -> B>(self, f: F) -> Self::Output {
        self.map(|a| f(a))
    }
}

impl<'a, A, B> CovariantOnce<'a, B> for std::option::Option<A> {
    fn fmap_once<F: 'a + FnOnce(A) -> B>(self, f: F) -> Self::Output {
        self.map(|a| f(a))
    }
}

impl<'a, X, A, B> Covariant<'a, B> for (X, A) {
    fn fmap<F: Fn(A) -> B>(self, f: F) -> Self::Output {
        (self.0, f(self.1))
    }
}

impl<'a, X, A, B> CovariantOnce<'a, B> for (X, A) {
    fn fmap_once<F: FnOnce(A) -> B>(self, f: F) -> Self::Output {
        (self.0, f(self.1))
    }
}

impl<'a, A, B> Bivariant<'a, B> for std::marker::PhantomData<A> {
    fn xmap(self) -> Self::Output { std::marker::PhantomData }
}

#[test]
fn it_works() {
}
<commit_msg>impl Covariant for Box and Result<commit_after>pub mod isomorphism;
pub mod parametric;

use isomorphism::{Iso, IsoOnce};
use parametric::{Param, ReParam};

pub trait Covariant<'a, B>: ReParam<B> {
    fn fmap<F: 'a + Fn(Self::Param) -> B>(self, F) -> Self::Output;
}

pub trait CovariantOnce<'a, B>: ReParam<B> + Covariant<'a, B> {
    fn fmap_once<F: 'a + FnOnce(Self::Param) -> B>(self, F) -> Self::Output;
}

pub trait Contravariant<'a, B>: ReParam<B> {
    fn contramap<F: 'a + Fn(B) -> Self::Param>(self, F) -> Self::Output;
}

pub trait ContravariantOnce<'a, B>: ReParam<B> + Contravariant<'a, B> {
    fn contramap_once<F: 'a + FnOnce(B) -> Self::Param>(self, F) -> Self::Output;
}

pub trait Invariant<'a, B>: ReParam<B> {
    fn invmap<F: 'a + Iso<Self::Param, B>>(self, F) -> Self::Output;
}

pub trait InvariantOnce<'a, B>: ReParam<B> + Invariant<'a, B> {
    fn invmap_once<F: 'a + IsoOnce<Self::Param, B>>(self, F) -> Self::Output;
}

pub trait Bivariant<'a, B>: ReParam<B> {
    fn xmap(self) -> Self::Output;
}

pub trait NaturalTransform<T: Param<Param=Self::Param>>: Param {
    fn transform(self) -> T;
}

impl<'a, A, B> Covariant<'a, B> for std::option::Option<A> {
    fn fmap<F: 'a + Fn(A) -> B>(self, f: F) -> Self::Output {
        self.fmap_once(f)
    }
}

impl<'a, A, B> CovariantOnce<'a, B> for std::option::Option<A> {
    fn fmap_once<F: 'a + FnOnce(A) -> B>(self, f: F) -> Self::Output {
        self.map(|a| f(a))
    }
}

impl<'a, X, A, B> Covariant<'a, B> for (X, A) {
    fn fmap<F: Fn(A) -> B>(self, f: F) -> Self::Output {
        self.fmap_once(f)
    }
}

impl<'a, X, A, B> CovariantOnce<'a, B> for (X, A) {
    fn fmap_once<F: FnOnce(A) -> B>(self, f: F) -> Self::Output {
        (self.0, f(self.1))
    }
}

impl<'a, A, B> Covariant<'a, B> for Box<A> {
    fn fmap<F: 'a + Fn(A) -> B>(self, f: F) -> Self::Output {
        self.fmap_once(f)
    }
}

impl<'a, A, B> CovariantOnce<'a, B> for Box<A> {
    fn fmap_once<F: FnOnce(A) -> B>(self, f: F) -> Self::Output {
        Box::new(f(*self))
    }
}

impl<'a, A, B, E> Covariant<'a, B> for Result<A, E> {
    fn fmap<F: 'a + Fn(A) -> B>(self, f: F) -> Self::Output {
        self.fmap_once(f)
    }
}

impl<'a, A, B, E> CovariantOnce<'a, B> for Result<A, E> {
    fn fmap_once<F: FnOnce(A) -> B>(self, f: F) -> Self::Output {
        self.map(f)
    }
}

impl<'a, A, B> Bivariant<'a, B> for std::marker::PhantomData<A> {
    fn xmap(self) -> Self::Output { std::marker::PhantomData }
}

#[test]
fn it_works() {
}
<|endoftext|>