<commit_before>// Unused mut warning is false in this context
#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_stream;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;
extern crate futures;
extern crate hyper;
extern crate tokio_core;
extern crate hyper_tls;
extern crate time;
extern crate clap; // TODO Add application help
extern crate curl;
extern crate webbrowser;

mod utils;
mod models;
mod client;
mod app;
mod endpoint;
mod cli;

use app::*;
use models::*;
use client::*;
use cli::*;

use tokio_core::reactor::{Core, Handle};
use std::io::{self, BufRead};
use std::thread::spawn;
use std::thread;
use std::process;
use futures::{Stream, Sink, Future};
use futures::sync::mpsc;
use futures::sync::mpsc::{Receiver, Sender};
use futures::stream::BoxStream;
use curl::easy::Easy;

fn main() {

    let mut app_domain = AppDomain::new();
    let mut app_cache: AppCache = AppCache::new();
    let mut app_state_machine: AppStateMachine = AppStateMachine::new();
    let mut main_core = Core::new().expect("Failed to create core");

    info!(&app_domain.logger, "Application started");
    app_cache.retrieved_top_stories = get_top_story_ids(&mut app_domain, &mut app_state_machine)
        .ok();
    print_ten_stories(&mut app_domain, &mut app_cache, &mut app_state_machine);
    let (mut sender, receiver) = mpsc::channel(1);

    spawn(move || {
        let stdin = io::stdin();
        for line in stdin.lock().lines() {
            let sender = sender.clone();
            sender.send(line).wait().unwrap();
        }
    });
    let listener =
        receiver.for_each(|msg| {
            gui_listener(msg, &mut app_domain, &mut app_cache, &mut app_state_machine)
        });

    main_core.run(listener);
}

fn gui_listener(msg_result: Result<String, io::Error>,
                app_domain: &mut AppDomain,
                app_cache: &mut AppCache,
                app_state_machine: &mut AppStateMachine)
                -> Result<(), ()> {
    // TODO Logging
    match msg_result {
        Ok(msg) => {
            if msg.len() >= 4 && &msg[0..4] == "next" {
                app_state_machine.listing_page_index += 1;
                print_ten_stories(app_domain, app_cache, app_state_machine);
                info!(&app_domain.logger,
                      format!("Retrieved next ten stories with index {}",
                              &app_state_machine.listing_page_index))
            } else if msg.len() >= 4 && &msg[0..4] == "exit" {
                process::exit(0);
            } else if msg.len() >= 8 && &msg[0..8] == "comments" {
                // TODO get comments for story
            } else if msg.len() >= 4 && &msg[0..4] == "load" {
                let numb = (msg[5..].parse::<i32>().unwrap() - 1) as usize; // FIXME not handling errors either
                load_page_to_local(numb, app_domain, app_cache, app_state_machine);
            } else if msg.len() >= 4 && &msg[0..4] == "back" {
                if app_state_machine.listing_page_index >= 0 {
                    app_state_machine.listing_page_index -= 1;
                }
                print_ten_stories(app_domain, app_cache, app_state_machine);
                info!(&app_domain.logger,
                      format!("Retrieved previous ten stories with index {}",
                              &app_state_machine.listing_page_index));
            } else if msg.len() >= 4 && &msg[0..4] == "open" {
                // https://github.com/overdrivenpotato/url_open/blob/master/src/lib.rs
                let numb = (msg[5..].parse::<i32>().unwrap() - 1) as usize; // FIXME not handling errors either
                open_page_with_default_browser(numb, app_domain, app_cache, app_state_machine);
            }
        }
        Err(_) => println!("{}", "Error"),
    }
    Ok(())
}

fn open_page_with_default_browser(numb: usize,
                                  app_domain: &mut AppDomain,
                                  app_cache: &mut AppCache,
                                  app_state_machine: &mut AppStateMachine) {
    let s = format!("{}",
                    app_cache.retrieved_top_stories.as_ref().unwrap().values[numb]); // FIXME unsafe way to do this
    let item = client::get_item_by_id(&s, app_domain, app_state_machine).unwrap();
    if item.url.is_some() && webbrowser::open(&item.url.as_ref().unwrap()).is_ok() {
        println!("{} {}",
                 "Opened browser to url ",
                 item.url.as_ref().unwrap());
        info!(&app_domain.logger,
              format!("Opened page with default browser from url {}",
                      item.url.as_ref().unwrap()));
    }
}

fn load_page_to_local(numb: usize,
                      app_domain: &mut AppDomain,
                      app_cache: &mut AppCache,
                      app_state_machine: &mut AppStateMachine) {
    let s = format!("{}",
                    app_cache.retrieved_top_stories.as_ref().unwrap().values[numb]); // FIXME unsafe way to do this
    let item = client::get_item_by_id(&s, app_domain, app_state_machine).unwrap();
    let filen = client::download_page_from_item(&item, app_domain, app_state_machine);
    match filen {
        Ok(n) =>  {
            cli::print_filename_of_loaded_page(&n, item.title.as_ref().unwrap());
            info!(&app_domain.logger, format!("Loaded page {} to file {}",  item.url.as_ref().unwrap(), &n));
        },
        Err(e) => {
            cli::could_not_load_page(item.title.as_ref().unwrap());
            warn!(&app_domain.logger, format!("Could not load page to file"));
        },
    }

}

fn print_ten_stories(app_domain: &mut AppDomain,
                     app_cache: &mut AppCache,
                     app_state_machine: &mut AppStateMachine) {

    // This probably should not need all the parameters
    let top_stories = app_cache.retrieved_top_stories.as_ref().unwrap();
    info!(&app_domain.logger,
          format!("Received {} top stories", top_stories.values.len()));
    let skipped: usize = (app_state_machine.listing_page_index * 10) as usize;
    let mut index = 0 + skipped as i32;

    for item_id in top_stories.values.iter().skip(skipped).take(10) {
        index += 1;
        let s = format!("{}", item_id);
        let item: HnItem = client::get_item_by_id(&s, app_domain, app_state_machine).unwrap();
        cli::print_headline_with_author(&item, &index);
    }
}
<commit_msg>minor logging addition<commit_after>// Unused mut warning is false in this context
#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_stream;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;
extern crate futures;
extern crate hyper;
extern crate tokio_core;
extern crate hyper_tls;
extern crate time;
extern crate clap; // TODO Add application help
extern crate curl;
extern crate webbrowser;

mod utils;
mod models;
mod client;
mod app;
mod endpoint;
mod cli;

use app::*;
use models::*;
use client::*;
use cli::*;

use tokio_core::reactor::{Core, Handle};
use std::io::{self, BufRead};
use std::thread::spawn;
use std::thread;
use std::process;
use futures::{Stream, Sink, Future};
use futures::sync::mpsc;
use futures::sync::mpsc::{Receiver, Sender};
use futures::stream::BoxStream;
use curl::easy::Easy;

fn main() {

    let mut app_domain = AppDomain::new();
    let mut app_cache: AppCache = AppCache::new();
    let mut app_state_machine: AppStateMachine = AppStateMachine::new();
    let mut main_core = Core::new().expect("Failed to create core");

    info!(&app_domain.logger, "Application started");
    app_cache.retrieved_top_stories = get_top_story_ids(&mut app_domain, &mut app_state_machine)
        .ok();
    print_ten_stories(&mut app_domain, &mut app_cache, &mut app_state_machine);
    let (mut sender, receiver) = mpsc::channel(1);

    spawn(move || {
        let stdin = io::stdin();
        for line in stdin.lock().lines() {
            let sender = sender.clone();
            sender.send(line).wait().unwrap();
        }
    });
    let listener =
        receiver.for_each(|msg| {
            gui_listener(msg, &mut app_domain, &mut app_cache, &mut app_state_machine)
        });

    main_core.run(listener);
}

fn gui_listener(msg_result: Result<String, io::Error>,
                app_domain: &mut AppDomain,
                app_cache: &mut AppCache,
                app_state_machine: &mut AppStateMachine)
                -> Result<(), ()> {
    // TODO Logging
    match msg_result {
        Ok(msg) => {
            if msg.len() >= 4 && &msg[0..4] == "next" {
                app_state_machine.listing_page_index += 1;
                print_ten_stories(app_domain, app_cache, app_state_machine);
                info!(&app_domain.logger,
                      format!("Retrieved next ten stories with index {}",
                              &app_state_machine.listing_page_index))
            } else if msg.len() >= 4 && &msg[0..4] == "exit" {
                info!(&app_domain.logger, "Exited application normally");
                process::exit(0);
            } else if msg.len() >= 8 && &msg[0..8] == "comments" {
                // TODO get comments for story
            } else if msg.len() >= 4 && &msg[0..4] == "load" {
                let numb = (msg[5..].parse::<i32>().unwrap() - 1) as usize; // FIXME not handling errors either
                load_page_to_local(numb, app_domain, app_cache, app_state_machine);
            } else if msg.len() >= 4 && &msg[0..4] == "back" {
                if app_state_machine.listing_page_index >= 0 {
                    app_state_machine.listing_page_index -= 1;
                }
                print_ten_stories(app_domain, app_cache, app_state_machine);
                info!(&app_domain.logger,
                      format!("Retrieved previous ten stories with index {}",
                              &app_state_machine.listing_page_index));
            } else if msg.len() >= 4 && &msg[0..4] == "open" {
                // https://github.com/overdrivenpotato/url_open/blob/master/src/lib.rs
                let numb = (msg[5..].parse::<i32>().unwrap() - 1) as usize; // FIXME not handling errors either
                open_page_with_default_browser(numb, app_domain, app_cache, app_state_machine);
            }
        }
        Err(_) => println!("{}", "Error"),
    }
    Ok(())
}

fn open_page_with_default_browser(numb: usize,
                                  app_domain: &mut AppDomain,
                                  app_cache: &mut AppCache,
                                  app_state_machine: &mut AppStateMachine) {
    let s = format!("{}",
                    app_cache.retrieved_top_stories.as_ref().unwrap().values[numb]); // FIXME unsafe way to do this
    let item = client::get_item_by_id(&s, app_domain, app_state_machine).unwrap();
    if item.url.is_some() && webbrowser::open(&item.url.as_ref().unwrap()).is_ok() {
        println!("{} {}",
                 "Opened browser to url ",
                 item.url.as_ref().unwrap());
        info!(&app_domain.logger,
              format!("Opened page with default browser from url {}",
                      item.url.as_ref().unwrap()));
    }
}

fn load_page_to_local(numb: usize,
                      app_domain: &mut AppDomain,
                      app_cache: &mut AppCache,
                      app_state_machine: &mut AppStateMachine) {
    let s = format!("{}",
                    app_cache.retrieved_top_stories.as_ref().unwrap().values[numb]); // FIXME unsafe way to do this
    let item = client::get_item_by_id(&s, app_domain, app_state_machine).unwrap();
    let filen = client::download_page_from_item(&item, app_domain, app_state_machine);
    match filen {
        Ok(n) =>  {
            cli::print_filename_of_loaded_page(&n, item.title.as_ref().unwrap());
            info!(&app_domain.logger, format!("Loaded page {} to file {}",  item.url.as_ref().unwrap(), &n));
        },
        Err(e) => {
            cli::could_not_load_page(item.title.as_ref().unwrap());
            warn!(&app_domain.logger, format!("Could not load page to file"));
        },
    }

}

fn print_ten_stories(app_domain: &mut AppDomain,
                     app_cache: &mut AppCache,
                     app_state_machine: &mut AppStateMachine) {

    // This probably should not need all the parameters
    let top_stories = app_cache.retrieved_top_stories.as_ref().unwrap();
    info!(&app_domain.logger,
          format!("Received {} top stories", top_stories.values.len()));
    let skipped: usize = (app_state_machine.listing_page_index * 10) as usize;
    let mut index = 0 + skipped as i32;

    for item_id in top_stories.values.iter().skip(skipped).take(10) {
        index += 1;
        let s = format!("{}", item_id);
        let item: HnItem = client::get_item_by_id(&s, app_domain, app_state_machine).unwrap();
        cli::print_headline_with_author(&item, &index);
    }
}
<|endoftext|>


<commit_before>use std::io::{File, BufferedReader};
use std::io::SeekStyle::SeekSet;
use error::{CTResult, CTDatabaseError, CTSyntaxError};
use error::CTError::{DatabaseError, SyntaxError};
use token::Token;
use token::TokenKind::Elem;

#[derive(Show, PartialEq)]
pub struct ElemData {
    short_name: String,
    long_name: String,
    mass: f64,
    atomic_num: u16,
}

pub struct ElemDatabase {
    db: BufferedReader<File>,
}

impl ElemDatabase {
    pub fn open(path: &str) -> CTResult<ElemDatabase> {
        match File::open(&Path::new(path)) {
            Ok(db_file) => Ok(ElemDatabase { db: BufferedReader::new(db_file) }),
            Err(_) => Err(DatabaseError(CTDatabaseError {
                desc: format!("Could not open database file. Expected at: {:?}", path)
            })),
        }
    }

    pub fn get_single_data(&mut self, elem: &Token) -> CTResult<ElemData> {
        // we return to the beginning of the underlying file, since the data
        // might lie on a line we have previously read past
        self.db.get_mut().seek(0, SeekSet).ok().expect("Internal error reading database");
        let mut line_iter = self.db.lines();
        let short_name = match elem.tok {
            Elem(ref name) => name.as_slice(),
            _ => unreachable!(),
        };
        match line_iter.find(|l| l.is_err() || l.as_ref().ok().unwrap().starts_with(short_name)) {
            Some(Ok(ref line)) => decode_line(line),
            Some(Err(_)) => Err(DatabaseError(CTDatabaseError {
                desc: "Error reading the database".to_string()
            })),
            None => Err(SyntaxError(CTSyntaxError {
                desc: format!("Could not find element: {:?}", short_name),
                pos: elem.pos,
                len: elem.len,
            })),
        }
    }

    pub fn get_data(&mut self, elems: &Vec<Token>) -> CTResult<Vec<ElemData>> {
        let mut out = Vec::new();
        for elem in elems.iter() {
           match self.get_single_data(elem) {
                Ok(data) => out.push(data),
                Err(e) => return Err(e),
            }
        }
        Ok(out)
    }
}

fn decode_line(line: &String) -> CTResult<ElemData> {
    let data: Vec<&str> = line.trim().split(';').collect();
    if data.len() < 4 {
        Err(DatabaseError(CTDatabaseError {
            desc: "Missing field in database".to_string()
        }))
    } else {
        let mass = data[1].parse::<f64>();
        let atomic_num = data[3].parse::<u16>();
        if let (Some(m), Some(an)) = (mass, atomic_num) {
            Ok(ElemData {
                short_name: data[0].to_string(),
                long_name: data[2].to_string(),
                mass: m,
                atomic_num: an,
            })
        } else {
            Err(DatabaseError(CTDatabaseError {
                desc: "Field in database corrupted".to_string()
            }))
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::File;
    use std::io::fs;
    use token::Token;
    use token::TokenKind::Elem;

    fn make_dummy_db(name: &str, contents: &str) -> ElemDatabase {
        if let Err(e) = File::create(&Path::new(name)).and_then(|mut f| f.write_str(contents)) {
            // if we can't make the database we can't test, so just abort here
            panic!("Could not create dummy database: {:?}", e.desc);
        }
        ElemDatabase::open(name).unwrap()
    }

    fn remove_dummy_db(name: &str) {
        if let Err(e) = fs::unlink(&Path::new(name)) {
            // if we can't remove the database something is wrong, and we abort the test
            panic!("Could not remove dummy database: {:?}", e.desc);
        }
    }

    #[test]
    fn decode() {
        let db_name = "decode_db";
        let mut db = make_dummy_db(db_name, "A;123.456789;Abba;12");
        let raw_result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        let expected = ElemData {
            short_name: "A".to_string(),
            long_name: "Abba".to_string(),
            mass: 123.456789,
            atomic_num: 12,
        };
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn missing_field() {
        let db_name = "missing_field_db";
        let mut db = make_dummy_db(db_name, "A;");
        let result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn field_corrupted() {
        let db_name = "field_corrupted_db";
        let mut db = make_dummy_db(db_name, "A;not a number;Abba;12");
        let result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }
}<commit_msg>Add more tests for the database<commit_after>use std::io::{File, BufferedReader};
use std::io::SeekStyle::SeekSet;
use error::{CTResult, CTDatabaseError, CTSyntaxError};
use error::CTError::{DatabaseError, SyntaxError};
use token::Token;
use token::TokenKind::Elem;

#[derive(Show, PartialEq)]
pub struct ElemData {
    short_name: String,
    long_name: String,
    mass: f64,
    atomic_num: u16,
}

pub struct ElemDatabase {
    db: BufferedReader<File>,
}

impl ElemDatabase {
    pub fn open(path: &str) -> CTResult<ElemDatabase> {
        match File::open(&Path::new(path)) {
            Ok(db_file) => Ok(ElemDatabase { db: BufferedReader::new(db_file) }),
            Err(_) => Err(DatabaseError(CTDatabaseError {
                desc: format!("Could not open database file. Expected at: {:?}", path)
            })),
        }
    }

    pub fn get_single_data(&mut self, elem: &Token) -> CTResult<ElemData> {
        // we return to the beginning of the underlying file, since the data
        // might lie on a line we have previously read past
        self.db.get_mut().seek(0, SeekSet).ok().expect("Internal error reading database");
        let mut line_iter = self.db.lines();
        let short_name = match elem.tok {
            Elem(ref name) => name.as_slice(),
            _ => unreachable!(),
        };
        match line_iter.find(|l| l.is_err() || l.as_ref().ok().unwrap().starts_with(short_name)) {
            Some(Ok(ref line)) => decode_line(line),
            Some(Err(_)) => Err(DatabaseError(CTDatabaseError {
                desc: "Error reading the database".to_string()
            })),
            None => Err(SyntaxError(CTSyntaxError {
                desc: format!("Could not find element: {:?}", short_name),
                pos: elem.pos,
                len: elem.len,
            })),
        }
    }

    pub fn get_data(&mut self, elems: &Vec<Token>) -> CTResult<Vec<ElemData>> {
        let mut out = Vec::new();
        for elem in elems.iter() {
           match self.get_single_data(elem) {
                Ok(data) => out.push(data),
                Err(e) => return Err(e),
            }
        }
        Ok(out)
    }
}

fn decode_line(line: &String) -> CTResult<ElemData> {
    let data: Vec<&str> = line.trim().split(';').collect();
    if data.len() < 4 {
        Err(DatabaseError(CTDatabaseError {
            desc: "Missing field in database".to_string()
        }))
    } else {
        let mass = data[1].parse::<f64>();
        let atomic_num = data[3].parse::<u16>();
        if let (Some(m), Some(an)) = (mass, atomic_num) {
            Ok(ElemData {
                short_name: data[0].to_string(),
                long_name: data[2].to_string(),
                mass: m,
                atomic_num: an,
            })
        } else {
            Err(DatabaseError(CTDatabaseError {
                desc: "Field in database corrupted".to_string()
            }))
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::File;
    use std::io::fs;
    use token::Token;
    use token::TokenKind::Elem;

    fn make_dummy_db(name: &str, contents: &str) -> ElemDatabase {
        if let Err(e) = File::create(&Path::new(name)).and_then(|mut f| f.write_str(contents)) {
            // if we can't make the database we can't test, so just abort here
            panic!("Could not create dummy database: {:?}", e.desc);
        }
        ElemDatabase::open(name).unwrap()
    }

    fn remove_dummy_db(name: &str) {
        if let Err(e) = fs::unlink(&Path::new(name)) {
            // if we can't remove the database something is wrong, and we abort the test
            panic!("Could not remove dummy database: {:?}", e.desc);
        }
    }

    #[test]
    fn multiple_elems() {
        let db_name = "multiple_elems_db";
        let mut db = make_dummy_db(db_name,
            "A;1;Abba;2\n\
            B;3;Beta;4");
        let raw_result = db.get_data(&vec!(
            Token { tok: Elem("B".to_string()), pos: 0, len: 1 },
            Token { tok: Elem("A".to_string()), pos: 1, len: 1 }
        ));
        let expected = vec!(
            ElemData {
                short_name: "B".to_string(),
                long_name: "Beta".to_string(),
                mass: 3.0,
                atomic_num: 4,
            },
            ElemData {
                short_name: "A".to_string(),
                long_name: "Abba".to_string(),
                mass: 1.0,
                atomic_num: 2,
            }
        );
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn find_elem() {
        let db_name = "find_elem_db";
        let mut db = make_dummy_db(db_name,
            "A;0;Abba;0\n\
            B;123.456789;Beta;12\n\
            C;0;Coop;0");
        let raw_result = db.get_single_data(&Token { tok: Elem("B".to_string()), pos: 0, len: 2 });
        let expected = ElemData {
            short_name: "B".to_string(),
            long_name: "Beta".to_string(),
            mass: 123.456789,
            atomic_num: 12,
        };
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn missing_elem() {
        let db_name = "missing_elem_db";
        let mut db = make_dummy_db(db_name, "A;123.456789;Abba;12");
        let result = db.get_single_data(&Token { tok: Elem("B".to_string()), pos: 0, len: 2 });
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn decode() {
        let db_name = "decode_db";
        let mut db = make_dummy_db(db_name, "A;123.456789;Abba;12");
        let raw_result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        let expected = ElemData {
            short_name: "A".to_string(),
            long_name: "Abba".to_string(),
            mass: 123.456789,
            atomic_num: 12,
        };
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn missing_field() {
        let db_name = "missing_field_db";
        let mut db = make_dummy_db(db_name, "A;");
        let result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn field_corrupted() {
        let db_name = "field_corrupted_db";
        let mut db = make_dummy_db(db_name, "A;not a number;Abba;12");
        let result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }
}<|endoftext|>


<commit_before>extern crate bitflags;

use super::ffi::*;

pub enum SpecialKeyring {
    ThreadKeyring,
    ProcessKeyring,
    SessionKeyring,
    UserKeyring,
    UserSessionKeyring,
    GroupKeyring,
}

pub type KeyringSerial = i32;

impl SpecialKeyring {
    pub fn serial(self) -> KeyringSerial {
        match self {
            SpecialKeyring::ThreadKeyring       => KEY_SPEC_THREAD_KEYRING,
            SpecialKeyring::ProcessKeyring      => KEY_SPEC_PROCESS_KEYRING,
            SpecialKeyring::SessionKeyring      => KEY_SPEC_SESSION_KEYRING,
            SpecialKeyring::UserKeyring         => KEY_SPEC_USER_KEYRING,
            SpecialKeyring::UserSessionKeyring  => KEY_SPEC_USER_SESSION_KEYRING,
            SpecialKeyring::GroupKeyring        => KEY_SPEC_GROUP_KEYRING,
        }
    }
}

pub enum DefaultKeyring {
    NoChange,
    ThreadKeyring,
    ProcessKeyring,
    SessionKeyring,
    UserKeyring,
    UserSessionKeyring,
    GroupKeyring,
    DefaultKeyring,
}

pub type KeyringDefaultSerial = i32;

impl DefaultKeyring {
    pub fn serial(self) -> KeyringDefaultSerial {
        match self {
            DefaultKeyring::NoChange            => KEY_REQKEY_DEFL_NO_CHANGE,
            DefaultKeyring::ThreadKeyring       => KEY_REQKEY_DEFL_THREAD_KEYRING,
            DefaultKeyring::ProcessKeyring      => KEY_REQKEY_DEFL_PROCESS_KEYRING,
            DefaultKeyring::SessionKeyring      => KEY_REQKEY_DEFL_SESSION_KEYRING,
            DefaultKeyring::UserKeyring         => KEY_REQKEY_DEFL_USER_KEYRING,
            DefaultKeyring::UserSessionKeyring  => KEY_REQKEY_DEFL_USER_SESSION_KEYRING,
            DefaultKeyring::GroupKeyring        => KEY_REQKEY_DEFL_GROUP_KEYRING,
            DefaultKeyring::DefaultKeyring      => KEY_REQKEY_DEFL_DEFAULT,
        }
    }
}

impl From<i32> for DefaultKeyring {
    fn from(id: i32) -> DefaultKeyring {
        match id {
            KEY_REQKEY_DEFL_NO_CHANGE               => DefaultKeyring::NoChange,
            KEY_REQKEY_DEFL_THREAD_KEYRING          => DefaultKeyring::ThreadKeyring,
            KEY_REQKEY_DEFL_PROCESS_KEYRING         => DefaultKeyring::ProcessKeyring,
            KEY_REQKEY_DEFL_SESSION_KEYRING         => DefaultKeyring::SessionKeyring,
            KEY_REQKEY_DEFL_USER_KEYRING            => DefaultKeyring::UserKeyring,
            KEY_REQKEY_DEFL_USER_SESSION_KEYRING    => DefaultKeyring::UserSessionKeyring,
            KEY_REQKEY_DEFL_GROUP_KEYRING           => DefaultKeyring::GroupKeyring,
            KEY_REQKEY_DEFL_DEFAULT                 => DefaultKeyring::DefaultKeyring,
            _                                       => panic!("Invalid value for a default keyring: {}", id),
        }
    }
}

pub type KeyPermissions = u32;

bitflags! {
    flags KeyringPermission: key_perm_t {
        const POSSESSOR_VIEW            = KEY_POS_VIEW,
        const POSSESSOR_READ            = KEY_POS_READ,
        const POSSESSOR_WRITE           = KEY_POS_WRITE,
        const POSSESSOR_SEARCH          = KEY_POS_SEARCH,
        const POSSESSOR_LINK            = KEY_POS_LINK,
        const POSSESSOR_SET_ATTRIBUTE   = KEY_POS_SETATTR,
        const POSSESSOR_ALL             = KEY_POS_ALL,

        const USER_VIEW             = KEY_USR_VIEW,
        const USER_READ             = KEY_USR_READ,
        const USER_WRITE            = KEY_USR_WRITE,
        const USER_SEARCH           = KEY_USR_SEARCH,
        const USER_LINK             = KEY_USR_LINK,
        const USER_SET_ATTRIBUTE    = KEY_USR_SETATTR,
        const USER_ALL              = KEY_USR_ALL,

        const GROUP_VIEW            = KEY_GRP_VIEW,
        const GROUP_READ            = KEY_GRP_READ,
        const GROUP_WRITE           = KEY_GRP_WRITE,
        const GROUP_SEARCH          = KEY_GRP_SEARCH,
        const GROUP_LINK            = KEY_GRP_LINK,
        const GROUP_SET_ATTRIBUTE   = KEY_GRP_SETATTR,
        const GROUP_ALL             = KEY_GRP_ALL,

        const OTHER_VIEW            = KEY_OTH_VIEW,
        const OTHER_READ            = KEY_OTH_READ,
        const OTHER_WRITE           = KEY_OTH_WRITE,
        const OTHER_SEARCH          = KEY_OTH_SEARCH,
        const OTHER_LINK            = KEY_OTH_LINK,
        const OTHER_SET_ATTRIBUTE   = KEY_OTH_SETATTR,
        const OTHER_ALL             = KEY_OTH_ALL,
    }
}

impl KeyringPermission {
    pub fn permissions(self) -> KeyPermissions {
        self.bits
    }
}

#[test]
fn test_keyring_ids() {
    assert_eq!(SpecialKeyring::ThreadKeyring.serial(), KEY_SPEC_THREAD_KEYRING);
    assert_eq!(SpecialKeyring::ProcessKeyring.serial(), KEY_SPEC_PROCESS_KEYRING);
    assert_eq!(SpecialKeyring::SessionKeyring.serial(), KEY_SPEC_SESSION_KEYRING);
    assert_eq!(SpecialKeyring::UserKeyring.serial(), KEY_SPEC_USER_KEYRING);
    assert_eq!(SpecialKeyring::UserSessionKeyring.serial(), KEY_SPEC_USER_SESSION_KEYRING);
    assert_eq!(SpecialKeyring::GroupKeyring.serial(), KEY_SPEC_GROUP_KEYRING);
}

#[test]
fn test_default_keyring_ids() {
    assert_eq!(DefaultKeyring::NoChange.serial(), KEY_REQKEY_DEFL_NO_CHANGE);
    assert_eq!(DefaultKeyring::ThreadKeyring.serial(), KEY_REQKEY_DEFL_THREAD_KEYRING);
    assert_eq!(DefaultKeyring::ProcessKeyring.serial(), KEY_REQKEY_DEFL_PROCESS_KEYRING);
    assert_eq!(DefaultKeyring::SessionKeyring.serial(), KEY_REQKEY_DEFL_SESSION_KEYRING);
    assert_eq!(DefaultKeyring::UserKeyring.serial(), KEY_REQKEY_DEFL_USER_KEYRING);
    assert_eq!(DefaultKeyring::UserSessionKeyring.serial(), KEY_REQKEY_DEFL_USER_SESSION_KEYRING);
    assert_eq!(DefaultKeyring::GroupKeyring.serial(), KEY_REQKEY_DEFL_GROUP_KEYRING);
    assert_eq!(DefaultKeyring::DefaultKeyring.serial(), KEY_REQKEY_DEFL_DEFAULT);
}

#[test]
fn test_permission_bits() {
    assert_eq!(POSSESSOR_VIEW.bits, KEY_POS_VIEW);
    assert_eq!(POSSESSOR_READ.bits, KEY_POS_READ);
    assert_eq!(POSSESSOR_WRITE.bits, KEY_POS_WRITE);
    assert_eq!(POSSESSOR_SEARCH.bits, KEY_POS_SEARCH);
    assert_eq!(POSSESSOR_LINK.bits, KEY_POS_LINK);
    assert_eq!(POSSESSOR_SET_ATTRIBUTE.bits, KEY_POS_SETATTR);
    assert_eq!(POSSESSOR_ALL.bits, KEY_POS_ALL);

    assert_eq!(USER_VIEW.bits, KEY_USR_VIEW);
    assert_eq!(USER_READ.bits, KEY_USR_READ);
    assert_eq!(USER_WRITE.bits, KEY_USR_WRITE);
    assert_eq!(USER_SEARCH.bits, KEY_USR_SEARCH);
    assert_eq!(USER_LINK.bits, KEY_USR_LINK);
    assert_eq!(USER_SET_ATTRIBUTE.bits, KEY_USR_SETATTR);
    assert_eq!(USER_ALL.bits, KEY_USR_ALL);

    assert_eq!(GROUP_VIEW.bits, KEY_GRP_VIEW);
    assert_eq!(GROUP_READ.bits, KEY_GRP_READ);
    assert_eq!(GROUP_WRITE.bits, KEY_GRP_WRITE);
    assert_eq!(GROUP_SEARCH.bits, KEY_GRP_SEARCH);
    assert_eq!(GROUP_LINK.bits, KEY_GRP_LINK);
    assert_eq!(GROUP_SET_ATTRIBUTE.bits, KEY_GRP_SETATTR);
    assert_eq!(GROUP_ALL.bits, KEY_GRP_ALL);

    assert_eq!(OTHER_VIEW.bits, KEY_OTH_VIEW);
    assert_eq!(OTHER_READ.bits, KEY_OTH_READ);
    assert_eq!(OTHER_WRITE.bits, KEY_OTH_WRITE);
    assert_eq!(OTHER_SEARCH.bits, KEY_OTH_SEARCH);
    assert_eq!(OTHER_LINK.bits, KEY_OTH_LINK);
    assert_eq!(OTHER_SET_ATTRIBUTE.bits, KEY_OTH_SETATTR);
    assert_eq!(OTHER_ALL.bits, KEY_OTH_ALL);
}
<commit_msg>constants: remove unused method<commit_after>extern crate bitflags;

use super::ffi::*;

pub enum SpecialKeyring {
    ThreadKeyring,
    ProcessKeyring,
    SessionKeyring,
    UserKeyring,
    UserSessionKeyring,
    GroupKeyring,
}

pub type KeyringSerial = i32;

impl SpecialKeyring {
    pub fn serial(self) -> KeyringSerial {
        match self {
            SpecialKeyring::ThreadKeyring       => KEY_SPEC_THREAD_KEYRING,
            SpecialKeyring::ProcessKeyring      => KEY_SPEC_PROCESS_KEYRING,
            SpecialKeyring::SessionKeyring      => KEY_SPEC_SESSION_KEYRING,
            SpecialKeyring::UserKeyring         => KEY_SPEC_USER_KEYRING,
            SpecialKeyring::UserSessionKeyring  => KEY_SPEC_USER_SESSION_KEYRING,
            SpecialKeyring::GroupKeyring        => KEY_SPEC_GROUP_KEYRING,
        }
    }
}

pub enum DefaultKeyring {
    NoChange,
    ThreadKeyring,
    ProcessKeyring,
    SessionKeyring,
    UserKeyring,
    UserSessionKeyring,
    GroupKeyring,
    DefaultKeyring,
}

pub type KeyringDefaultSerial = i32;

impl DefaultKeyring {
    pub fn serial(self) -> KeyringDefaultSerial {
        match self {
            DefaultKeyring::NoChange            => KEY_REQKEY_DEFL_NO_CHANGE,
            DefaultKeyring::ThreadKeyring       => KEY_REQKEY_DEFL_THREAD_KEYRING,
            DefaultKeyring::ProcessKeyring      => KEY_REQKEY_DEFL_PROCESS_KEYRING,
            DefaultKeyring::SessionKeyring      => KEY_REQKEY_DEFL_SESSION_KEYRING,
            DefaultKeyring::UserKeyring         => KEY_REQKEY_DEFL_USER_KEYRING,
            DefaultKeyring::UserSessionKeyring  => KEY_REQKEY_DEFL_USER_SESSION_KEYRING,
            DefaultKeyring::GroupKeyring        => KEY_REQKEY_DEFL_GROUP_KEYRING,
            DefaultKeyring::DefaultKeyring      => KEY_REQKEY_DEFL_DEFAULT,
        }
    }
}

impl From<i32> for DefaultKeyring {
    fn from(id: i32) -> DefaultKeyring {
        match id {
            KEY_REQKEY_DEFL_NO_CHANGE               => DefaultKeyring::NoChange,
            KEY_REQKEY_DEFL_THREAD_KEYRING          => DefaultKeyring::ThreadKeyring,
            KEY_REQKEY_DEFL_PROCESS_KEYRING         => DefaultKeyring::ProcessKeyring,
            KEY_REQKEY_DEFL_SESSION_KEYRING         => DefaultKeyring::SessionKeyring,
            KEY_REQKEY_DEFL_USER_KEYRING            => DefaultKeyring::UserKeyring,
            KEY_REQKEY_DEFL_USER_SESSION_KEYRING    => DefaultKeyring::UserSessionKeyring,
            KEY_REQKEY_DEFL_GROUP_KEYRING           => DefaultKeyring::GroupKeyring,
            KEY_REQKEY_DEFL_DEFAULT                 => DefaultKeyring::DefaultKeyring,
            _                                       => panic!("Invalid value for a default keyring: {}", id),
        }
    }
}

pub type KeyPermissions = u32;

bitflags! {
    flags KeyringPermission: key_perm_t {
        const POSSESSOR_VIEW            = KEY_POS_VIEW,
        const POSSESSOR_READ            = KEY_POS_READ,
        const POSSESSOR_WRITE           = KEY_POS_WRITE,
        const POSSESSOR_SEARCH          = KEY_POS_SEARCH,
        const POSSESSOR_LINK            = KEY_POS_LINK,
        const POSSESSOR_SET_ATTRIBUTE   = KEY_POS_SETATTR,
        const POSSESSOR_ALL             = KEY_POS_ALL,

        const USER_VIEW             = KEY_USR_VIEW,
        const USER_READ             = KEY_USR_READ,
        const USER_WRITE            = KEY_USR_WRITE,
        const USER_SEARCH           = KEY_USR_SEARCH,
        const USER_LINK             = KEY_USR_LINK,
        const USER_SET_ATTRIBUTE    = KEY_USR_SETATTR,
        const USER_ALL              = KEY_USR_ALL,

        const GROUP_VIEW            = KEY_GRP_VIEW,
        const GROUP_READ            = KEY_GRP_READ,
        const GROUP_WRITE           = KEY_GRP_WRITE,
        const GROUP_SEARCH          = KEY_GRP_SEARCH,
        const GROUP_LINK            = KEY_GRP_LINK,
        const GROUP_SET_ATTRIBUTE   = KEY_GRP_SETATTR,
        const GROUP_ALL             = KEY_GRP_ALL,

        const OTHER_VIEW            = KEY_OTH_VIEW,
        const OTHER_READ            = KEY_OTH_READ,
        const OTHER_WRITE           = KEY_OTH_WRITE,
        const OTHER_SEARCH          = KEY_OTH_SEARCH,
        const OTHER_LINK            = KEY_OTH_LINK,
        const OTHER_SET_ATTRIBUTE   = KEY_OTH_SETATTR,
        const OTHER_ALL             = KEY_OTH_ALL,
    }
}

#[test]
fn test_keyring_ids() {
    assert_eq!(SpecialKeyring::ThreadKeyring.serial(), KEY_SPEC_THREAD_KEYRING);
    assert_eq!(SpecialKeyring::ProcessKeyring.serial(), KEY_SPEC_PROCESS_KEYRING);
    assert_eq!(SpecialKeyring::SessionKeyring.serial(), KEY_SPEC_SESSION_KEYRING);
    assert_eq!(SpecialKeyring::UserKeyring.serial(), KEY_SPEC_USER_KEYRING);
    assert_eq!(SpecialKeyring::UserSessionKeyring.serial(), KEY_SPEC_USER_SESSION_KEYRING);
    assert_eq!(SpecialKeyring::GroupKeyring.serial(), KEY_SPEC_GROUP_KEYRING);
}

#[test]
fn test_default_keyring_ids() {
    assert_eq!(DefaultKeyring::NoChange.serial(), KEY_REQKEY_DEFL_NO_CHANGE);
    assert_eq!(DefaultKeyring::ThreadKeyring.serial(), KEY_REQKEY_DEFL_THREAD_KEYRING);
    assert_eq!(DefaultKeyring::ProcessKeyring.serial(), KEY_REQKEY_DEFL_PROCESS_KEYRING);
    assert_eq!(DefaultKeyring::SessionKeyring.serial(), KEY_REQKEY_DEFL_SESSION_KEYRING);
    assert_eq!(DefaultKeyring::UserKeyring.serial(), KEY_REQKEY_DEFL_USER_KEYRING);
    assert_eq!(DefaultKeyring::UserSessionKeyring.serial(), KEY_REQKEY_DEFL_USER_SESSION_KEYRING);
    assert_eq!(DefaultKeyring::GroupKeyring.serial(), KEY_REQKEY_DEFL_GROUP_KEYRING);
    assert_eq!(DefaultKeyring::DefaultKeyring.serial(), KEY_REQKEY_DEFL_DEFAULT);
}

#[test]
fn test_permission_bits() {
    assert_eq!(POSSESSOR_VIEW.bits, KEY_POS_VIEW);
    assert_eq!(POSSESSOR_READ.bits, KEY_POS_READ);
    assert_eq!(POSSESSOR_WRITE.bits, KEY_POS_WRITE);
    assert_eq!(POSSESSOR_SEARCH.bits, KEY_POS_SEARCH);
    assert_eq!(POSSESSOR_LINK.bits, KEY_POS_LINK);
    assert_eq!(POSSESSOR_SET_ATTRIBUTE.bits, KEY_POS_SETATTR);
    assert_eq!(POSSESSOR_ALL.bits, KEY_POS_ALL);

    assert_eq!(USER_VIEW.bits, KEY_USR_VIEW);
    assert_eq!(USER_READ.bits, KEY_USR_READ);
    assert_eq!(USER_WRITE.bits, KEY_USR_WRITE);
    assert_eq!(USER_SEARCH.bits, KEY_USR_SEARCH);
    assert_eq!(USER_LINK.bits, KEY_USR_LINK);
    assert_eq!(USER_SET_ATTRIBUTE.bits, KEY_USR_SETATTR);
    assert_eq!(USER_ALL.bits, KEY_USR_ALL);

    assert_eq!(GROUP_VIEW.bits, KEY_GRP_VIEW);
    assert_eq!(GROUP_READ.bits, KEY_GRP_READ);
    assert_eq!(GROUP_WRITE.bits, KEY_GRP_WRITE);
    assert_eq!(GROUP_SEARCH.bits, KEY_GRP_SEARCH);
    assert_eq!(GROUP_LINK.bits, KEY_GRP_LINK);
    assert_eq!(GROUP_SET_ATTRIBUTE.bits, KEY_GRP_SETATTR);
    assert_eq!(GROUP_ALL.bits, KEY_GRP_ALL);

    assert_eq!(OTHER_VIEW.bits, KEY_OTH_VIEW);
    assert_eq!(OTHER_READ.bits, KEY_OTH_READ);
    assert_eq!(OTHER_WRITE.bits, KEY_OTH_WRITE);
    assert_eq!(OTHER_SEARCH.bits, KEY_OTH_SEARCH);
    assert_eq!(OTHER_LINK.bits, KEY_OTH_LINK);
    assert_eq!(OTHER_SET_ATTRIBUTE.bits, KEY_OTH_SETATTR);
    assert_eq!(OTHER_ALL.bits, KEY_OTH_ALL);
}
<|endoftext|>


<commit_before>use std::borrow::Cow;

use serde::de::DeserializeOwned;

use crate::algorithms::AlgorithmFamily;
use crate::crypto::verify;
use crate::errors::{new_error, ErrorKind, Result};
use crate::header::Header;
use crate::pem::decoder::PemEncodedKey;
use crate::serialization::from_jwt_part_claims;
use crate::validation::{validate, Validation};

/// The return type of a successful call to [decode](fn.decode.html).
#[derive(Debug)]
pub struct TokenData<T> {
    /// The decoded JWT header
    pub header: Header,
    /// The decoded JWT claims
    pub claims: T,
}

/// Takes the result of a rsplit and ensure we only get 2 parts
/// Errors if we don't
macro_rules! expect_two {
    ($iter:expr) => {{
        let mut i = $iter;
        match (i.next(), i.next(), i.next()) {
            (Some(first), Some(second), None) => (first, second),
            _ => return Err(new_error(ErrorKind::InvalidToken)),
        }
    }};
}

#[derive(Debug, Clone, PartialEq)]
pub(crate) enum DecodingKeyKind<'a> {
    SecretOrDer(Cow<'a, [u8]>),
    RsaModulusExponent { n: Cow<'a, str>, e: Cow<'a, str> },
}

/// All the different kind of keys we can use to decode a JWT
/// This key can be re-used so make sure you only initialize it once if you can for better performance
#[derive(Debug, Clone, PartialEq)]
pub struct DecodingKey<'a> {
    pub(crate) family: AlgorithmFamily,
    pub(crate) kind: DecodingKeyKind<'a>,
}

impl<'a> DecodingKey<'a> {
    /// If you're using HMAC, use this.
    pub fn from_secret(secret: &'a [u8]) -> Self {
        DecodingKey {
            family: AlgorithmFamily::Hmac,
            kind: DecodingKeyKind::SecretOrDer(Cow::Borrowed(secret)),
        }
    }

    /// If you have (n, e) RSA public key components, use this.
    pub fn from_rsa_components(modulus: &'a str, exponent: &'a str) -> Self {
        DecodingKey {
            family: AlgorithmFamily::Rsa,
            kind: DecodingKeyKind::RsaModulusExponent {
                n: Cow::Borrowed(modulus),
                e: Cow::Borrowed(exponent),
            },
        }
    }

    /// If you know what you're doing and have a RSA DER encoded public key, use this.
    pub fn from_rsa_der(der: &'a [u8]) -> Self {
        DecodingKey {
            family: AlgorithmFamily::Rsa,
            kind: DecodingKeyKind::SecretOrDer(Cow::Borrowed(der)),
        }
    }

    /// If you know what you're doing and have a RSA EC encoded public key, use this.
    pub fn from_ec_der(der: &'a [u8]) -> Self {
        DecodingKey {
            family: AlgorithmFamily::Ec,
            kind: DecodingKeyKind::SecretOrDer(Cow::Borrowed(der)),
        }
    }

    /// Convert self to `DecodingKey<'static>`.
    pub fn into_static(self) -> DecodingKey<'static> {
        use DecodingKeyKind::*;
        let DecodingKey { family, kind } = self;
        let static_kind = match kind {
            SecretOrDer(key) => SecretOrDer(Cow::Owned(key.into_owned())),
            RsaModulusExponent { n, e } => {
                RsaModulusExponent { n: Cow::Owned(n.into_owned()), e: Cow::Owned(e.into_owned()) }
            }
        };
        DecodingKey { family, kind: static_kind }
    }

    pub(crate) fn as_bytes(&self) -> &[u8] {
        match &self.kind {
            DecodingKeyKind::SecretOrDer(b) => &b,
            DecodingKeyKind::RsaModulusExponent { .. } => unreachable!(),
        }
    }
}

impl DecodingKey<'static> {
    /// If you're using HMAC with a base64 encoded, use this.
    pub fn from_base64_secret(secret: &str) -> Result<Self> {
        let out = base64::decode(&secret)?;
        Ok(DecodingKey {
            family: AlgorithmFamily::Hmac,
            kind: DecodingKeyKind::SecretOrDer(Cow::Owned(out)),
        })
    }

    /// If you are loading a public RSA key in a PEM format, use this.
    pub fn from_rsa_pem(key: &[u8]) -> Result<Self> {
        let pem_key = PemEncodedKey::new(key)?;
        let content = pem_key.as_rsa_key()?;
        Ok(DecodingKey {
            family: AlgorithmFamily::Rsa,
            kind: DecodingKeyKind::SecretOrDer(Cow::Owned(content.to_vec())),
        })
    }

    /// If you have a ECDSA public key in PEM format, use this.
    pub fn from_ec_pem(key: &[u8]) -> Result<Self> {
        let pem_key = PemEncodedKey::new(key)?;
        let content = pem_key.as_ec_public_key()?;
        Ok(DecodingKey {
            family: AlgorithmFamily::Ec,
            kind: DecodingKeyKind::SecretOrDer(Cow::Owned(content.to_vec())),
        })
    }
}

/// Decode and validate a JWT
///
/// If the token or its signature is invalid or the claims fail validation, it will return an error.
///
/// ```rust
/// use serde::{Deserialize, Serialize};
/// use jsonwebtoken::{decode, DecodingKey, Validation, Algorithm};
///
/// #[derive(Debug, Serialize, Deserialize)]
/// struct Claims {
///    sub: String,
///    company: String
/// }
///
/// let token = "a.jwt.token".to_string();
/// // Claims is a struct that implements Deserialize
/// let token_message = decode::<Claims>(&token, &DecodingKey::from_secret("secret".as_ref()), &Validation::new(Algorithm::HS256));
/// ```
pub fn decode<T: DeserializeOwned>(
    token: &str,
    key: &DecodingKey,
    validation: &Validation,
) -> Result<TokenData<T>> {
    for alg in &validation.algorithms {
        if key.family != alg.family() {
            return Err(new_error(ErrorKind::InvalidAlgorithm));
        }
    }

    let (signature, message) = expect_two!(token.rsplitn(2, '.'));
    let (claims, header) = expect_two!(message.rsplitn(2, '.'));
    let header = Header::from_encoded(header)?;

    if !validation.algorithms.contains(&header.alg) {
        return Err(new_error(ErrorKind::InvalidAlgorithm));
    }

    if !verify(signature, message, key, header.alg)? {
        return Err(new_error(ErrorKind::InvalidSignature));
    }

    let (decoded_claims, claims_map): (T, _) = from_jwt_part_claims(claims)?;
    validate(&claims_map, validation)?;

    Ok(TokenData { header, claims: decoded_claims })
}

/// Decode a JWT without any signature verification/validations.
///
/// NOTE: Do not use this unless you know what you are doing! If the token's signature is invalid, it will *not* return an error.
///
/// ```rust
/// use serde::{Deserialize, Serialize};
/// use jsonwebtoken::{dangerous_unsafe_decode, Validation, Algorithm};
///
/// #[derive(Debug, Serialize, Deserialize)]
/// struct Claims {
///     sub: String,
///     company: String
/// }
///
/// let token = "a.jwt.token".to_string();
/// // Claims is a struct that implements Deserialize
/// let token_message = dangerous_unsafe_decode::<Claims>(&token);
/// ```
pub fn dangerous_unsafe_decode<T: DeserializeOwned>(token: &str) -> Result<TokenData<T>> {
    let (_, message) = expect_two!(token.rsplitn(2, '.'));
    let (claims, header) = expect_two!(message.rsplitn(2, '.'));
    let header = Header::from_encoded(header)?;

    let (decoded_claims, _): (T, _) = from_jwt_part_claims(claims)?;

    Ok(TokenData { header, claims: decoded_claims })
}

/// Decode a JWT without any signature verification/validations and return its [Header](struct.Header.html).
///
/// If the token has an invalid format (ie 3 parts separated by a `.`), it will return an error.
///
/// ```rust
/// use jsonwebtoken::decode_header;
///
/// let token = "a.jwt.token".to_string();
/// let header = decode_header(&token);
/// ```
pub fn decode_header(token: &str) -> Result<Header> {
    let (_, message) = expect_two!(token.rsplitn(2, '.'));
    let (_, header) = expect_two!(message.rsplitn(2, '.'));
    Header::from_encoded(header)
}
<commit_msg>revert breaking change of DecodingKey<commit_after>use std::borrow::Cow;

use serde::de::DeserializeOwned;

use crate::algorithms::AlgorithmFamily;
use crate::crypto::verify;
use crate::errors::{new_error, ErrorKind, Result};
use crate::header::Header;
use crate::pem::decoder::PemEncodedKey;
use crate::serialization::from_jwt_part_claims;
use crate::validation::{validate, Validation};

/// The return type of a successful call to [decode](fn.decode.html).
#[derive(Debug)]
pub struct TokenData<T> {
    /// The decoded JWT header
    pub header: Header,
    /// The decoded JWT claims
    pub claims: T,
}

/// Takes the result of a rsplit and ensure we only get 2 parts
/// Errors if we don't
macro_rules! expect_two {
    ($iter:expr) => {{
        let mut i = $iter;
        match (i.next(), i.next(), i.next()) {
            (Some(first), Some(second), None) => (first, second),
            _ => return Err(new_error(ErrorKind::InvalidToken)),
        }
    }};
}

#[derive(Debug, Clone, PartialEq)]
pub(crate) enum DecodingKeyKind<'a> {
    SecretOrDer(Cow<'a, [u8]>),
    RsaModulusExponent { n: Cow<'a, str>, e: Cow<'a, str> },
}

/// All the different kind of keys we can use to decode a JWT
/// This key can be re-used so make sure you only initialize it once if you can for better performance
#[derive(Debug, Clone, PartialEq)]
pub struct DecodingKey<'a> {
    pub(crate) family: AlgorithmFamily,
    pub(crate) kind: DecodingKeyKind<'a>,
}

impl<'a> DecodingKey<'a> {
    /// If you're using HMAC, use this.
    pub fn from_secret(secret: &'a [u8]) -> Self {
        DecodingKey {
            family: AlgorithmFamily::Hmac,
            kind: DecodingKeyKind::SecretOrDer(Cow::Borrowed(secret)),
        }
    }

    /// If you're using HMAC with a base64 encoded, use this.
    pub fn from_base64_secret(secret: &str) -> Result<Self> {
        let out = base64::decode(&secret)?;
        Ok(DecodingKey {
            family: AlgorithmFamily::Hmac,
            kind: DecodingKeyKind::SecretOrDer(Cow::Owned(out)),
        })
    }

    /// If you are loading a public RSA key in a PEM format, use this.
    pub fn from_rsa_pem(key: &'a [u8]) -> Result<Self> {
        let pem_key = PemEncodedKey::new(key)?;
        let content = pem_key.as_rsa_key()?;
        Ok(DecodingKey {
            family: AlgorithmFamily::Rsa,
            kind: DecodingKeyKind::SecretOrDer(Cow::Owned(content.to_vec())),
        })
    }

    /// If you have (n, e) RSA public key components, use this.
    pub fn from_rsa_components(modulus: &'a str, exponent: &'a str) -> Self {
        DecodingKey {
            family: AlgorithmFamily::Rsa,
            kind: DecodingKeyKind::RsaModulusExponent {
                n: Cow::Borrowed(modulus),
                e: Cow::Borrowed(exponent),
            },
        }
    }

    /// If you have a ECDSA public key in PEM format, use this.
    pub fn from_ec_pem(key: &'a [u8]) -> Result<Self> {
        let pem_key = PemEncodedKey::new(key)?;
        let content = pem_key.as_ec_public_key()?;
        Ok(DecodingKey {
            family: AlgorithmFamily::Ec,
            kind: DecodingKeyKind::SecretOrDer(Cow::Owned(content.to_vec())),
        })
    }

    /// If you know what you're doing and have a RSA DER encoded public key, use this.
    pub fn from_rsa_der(der: &'a [u8]) -> Self {
        DecodingKey {
            family: AlgorithmFamily::Rsa,
            kind: DecodingKeyKind::SecretOrDer(Cow::Borrowed(der)),
        }
    }

    /// If you know what you're doing and have a RSA EC encoded public key, use this.
    pub fn from_ec_der(der: &'a [u8]) -> Self {
        DecodingKey {
            family: AlgorithmFamily::Ec,
            kind: DecodingKeyKind::SecretOrDer(Cow::Borrowed(der)),
        }
    }

    /// Convert self to `DecodingKey<'static>`.
    pub fn into_static(self) -> DecodingKey<'static> {
        use DecodingKeyKind::*;
        let DecodingKey { family, kind } = self;
        let static_kind = match kind {
            SecretOrDer(key) => SecretOrDer(Cow::Owned(key.into_owned())),
            RsaModulusExponent { n, e } => {
                RsaModulusExponent { n: Cow::Owned(n.into_owned()), e: Cow::Owned(e.into_owned()) }
            }
        };
        DecodingKey { family, kind: static_kind }
    }

    pub(crate) fn as_bytes(&self) -> &[u8] {
        match &self.kind {
            DecodingKeyKind::SecretOrDer(b) => &b,
            DecodingKeyKind::RsaModulusExponent { .. } => unreachable!(),
        }
    }
}

/// Decode and validate a JWT
///
/// If the token or its signature is invalid or the claims fail validation, it will return an error.
///
/// ```rust
/// use serde::{Deserialize, Serialize};
/// use jsonwebtoken::{decode, DecodingKey, Validation, Algorithm};
///
/// #[derive(Debug, Serialize, Deserialize)]
/// struct Claims {
///    sub: String,
///    company: String
/// }
///
/// let token = "a.jwt.token".to_string();
/// // Claims is a struct that implements Deserialize
/// let token_message = decode::<Claims>(&token, &DecodingKey::from_secret("secret".as_ref()), &Validation::new(Algorithm::HS256));
/// ```
pub fn decode<T: DeserializeOwned>(
    token: &str,
    key: &DecodingKey,
    validation: &Validation,
) -> Result<TokenData<T>> {
    for alg in &validation.algorithms {
        if key.family != alg.family() {
            return Err(new_error(ErrorKind::InvalidAlgorithm));
        }
    }

    let (signature, message) = expect_two!(token.rsplitn(2, '.'));
    let (claims, header) = expect_two!(message.rsplitn(2, '.'));
    let header = Header::from_encoded(header)?;

    if !validation.algorithms.contains(&header.alg) {
        return Err(new_error(ErrorKind::InvalidAlgorithm));
    }

    if !verify(signature, message, key, header.alg)? {
        return Err(new_error(ErrorKind::InvalidSignature));
    }

    let (decoded_claims, claims_map): (T, _) = from_jwt_part_claims(claims)?;
    validate(&claims_map, validation)?;

    Ok(TokenData { header, claims: decoded_claims })
}

/// Decode a JWT without any signature verification/validations.
///
/// NOTE: Do not use this unless you know what you are doing! If the token's signature is invalid, it will *not* return an error.
///
/// ```rust
/// use serde::{Deserialize, Serialize};
/// use jsonwebtoken::{dangerous_unsafe_decode, Validation, Algorithm};
///
/// #[derive(Debug, Serialize, Deserialize)]
/// struct Claims {
///     sub: String,
///     company: String
/// }
///
/// let token = "a.jwt.token".to_string();
/// // Claims is a struct that implements Deserialize
/// let token_message = dangerous_unsafe_decode::<Claims>(&token);
/// ```
pub fn dangerous_unsafe_decode<T: DeserializeOwned>(token: &str) -> Result<TokenData<T>> {
    let (_, message) = expect_two!(token.rsplitn(2, '.'));
    let (claims, header) = expect_two!(message.rsplitn(2, '.'));
    let header = Header::from_encoded(header)?;

    let (decoded_claims, _): (T, _) = from_jwt_part_claims(claims)?;

    Ok(TokenData { header, claims: decoded_claims })
}

/// Decode a JWT without any signature verification/validations and return its [Header](struct.Header.html).
///
/// If the token has an invalid format (ie 3 parts separated by a `.`), it will return an error.
///
/// ```rust
/// use jsonwebtoken::decode_header;
///
/// let token = "a.jwt.token".to_string();
/// let header = decode_header(&token);
/// ```
pub fn decode_header(token: &str) -> Result<Header> {
    let (_, message) = expect_two!(token.rsplitn(2, '.'));
    let (_, header) = expect_two!(message.rsplitn(2, '.'));
    Header::from_encoded(header)
}
<|endoftext|>


<commit_before>
use mouros_rust_bindings::mailbox::{Mailbox, MailboxRaw};
use mouros_rust_bindings::CVoid;
use mouros_rust_bindings::tasks;

use bindings::constants;
use bindings::message_dispatcher;

use core::ptr;
use core::convert::TryFrom;

use bindings::message_dispatcher::{MessageWrapper, MemManagement};

mod MsgTypes {
    pub const SET_PLAN: u32 = 0;
    pub const GET_PLAN: u32 = 1;
    pub const PLAN_REPLY: u32 = 2;
    pub const SET_STATE: u32 = 3;
    pub const GET_STATE: u32 = 4;
    pub const STATE_REPLY: u32 = 5;
    pub const RET_VAL: u32 = 6;
}

#[repr(C)]
pub struct spin_plan_data {
    pub channel_num: u8,
    pub spin_plan_leg_count: u32,
    pub plan_legs: [pwm_leg; 10usize],
}

#[repr(C)]
pub struct pwm_leg {
    pub duration_msecs: u32,
    pub target_pct: f32,
}

#[repr(C)]
pub struct spin_channel {
    pub channel_num: u8,
}

#[repr(C)]
pub struct ret_val {
    pub ret_val: i32,
}

mod SpinStates {
    pub const STOPPED: u32 = 0;
    pub const RUNNING: u32 = 1;
    pub const SPINNING_DOWN: u32 = 2;
}

#[repr(C)]
pub struct spin_state_set_data {
    pub channel_num: u8,
    pub state: u32,
}

#[repr(C)]
pub struct spin_state_data {
    pub channel_num: u8,
    pub state: u32,
    pub plan_time_elapsed_msecs: u32,
    pub output_val_pct: f32,
}

pub enum Message<'a> {
    SetSpinPlan(&'a mut spin_plan_data),
    GetSpinPlan(&'a mut spin_channel),
    SpinPlanReply(&'a mut spin_plan_data),
    SetSpinState(&'a mut spin_state_set_data),
    GetSpinState(&'a mut spin_channel),
    SpinStateReply(&'a mut spin_state_data),
    ReturnValue(&'a mut ret_val),
}

impl<'a> message_dispatcher::MemManagement for Message<'a> {
    fn alloc(msg_type: u32) -> *mut message_dispatcher::message {
        unsafe { get_alloc_fn()(msg_type) }
    }

    fn free(msg_ptr: *mut message_dispatcher::message) {
        unsafe { get_free_fn()(msg_ptr) }
    }
}

impl<'a> TryFrom<*mut message_dispatcher::message> for Message<'a> {
    type Error = ();

    fn try_from(raw_msg_ptr: *mut message_dispatcher::message) -> Result<Self, Self::Error> {
        unsafe {
            if raw_msg_ptr.is_null() || (*raw_msg_ptr).data.is_null() {
                return Err(());
            }

            match (*raw_msg_ptr).msg_type {
                MsgTypes::SET_PLAN => {
                    Ok(Message::SetSpinPlan(
                        &mut *((*raw_msg_ptr).data as *mut spin_plan_data),
                    ))
                }
                MsgTypes::GET_PLAN => {
                    Ok(Message::GetSpinPlan(
                        &mut *((*raw_msg_ptr).data as *mut spin_channel),
                    ))
                }
                MsgTypes::PLAN_REPLY => {
                    Ok(Message::SpinPlanReply(
                        &mut *((*raw_msg_ptr).data as *mut spin_plan_data),
                    ))
                }
                MsgTypes::SET_STATE => {
                    Ok(Message::SetSpinState(
                        &mut *((*raw_msg_ptr).data as *mut spin_state_set_data),
                    ))
                }
                MsgTypes::GET_STATE => {
                    Ok(Message::GetSpinState(
                        &mut *((*raw_msg_ptr).data as *mut spin_channel),
                    ))
                }
                MsgTypes::STATE_REPLY => {
                    Ok(Message::SpinStateReply(
                        &mut *((*raw_msg_ptr).data as *mut spin_state_data),
                    ))
                }
                MsgTypes::RET_VAL => {
                    Ok(Message::ReturnValue(
                        &mut *((*raw_msg_ptr).data as *mut ret_val),
                    ))
                }
                _ => {
                    Self::free(raw_msg_ptr);
                    Err(())
                }
            }
        }
    }
}

const NUM_CHANNELS: usize = 1;

enum SpinnerEvent<'a> {
    SetPlan(&'a spin_plan_data),
    GetPlan,
    SetState(&'a spin_state_set_data),
    GetState,
}

#[derive(PartialEq, Eq)]
enum ChannelState {
    Stopped,
    Running,
    Spindown,
}

#[derive(Default, Clone, Copy)]
struct PlanLeg {
    duration_msecs: u32,
    target_pct: f32,
}

struct Channel {
    id: u8,
    state: ChannelState,
    plan: [PlanLeg; constants::MAX_SPIN_PLAN_LEGS as usize],
    plan_len: usize,
    elapsed_time_msecs: u32,
    output_val_pct: f32,
}

impl Default for Channel {
    fn default() -> Channel {
        Channel {
            id: 0,
            state: ChannelState::Stopped,
            plan: [PlanLeg::default(); constants::MAX_SPIN_PLAN_LEGS as usize],
            plan_len: 0,
            elapsed_time_msecs: 0,
            output_val_pct: 0f32,
        }
    }
}

impl Channel {
    fn send_event(&mut self, trans_id: u32, event: SpinnerEvent) {
        match self.state {
            ChannelState::Stopped => {
                match event {
                    SpinnerEvent::SetPlan(data) => {
                        self.set_channel_plan(data);
                        self.send_return_val(trans_id, 0);
                    }
                    SpinnerEvent::GetPlan => {
                        self.send_spin_plan_reply(trans_id);
                    }
                    SpinnerEvent::SetState(data) => {
                        self.set_channel_state(data);
                        self.send_return_val(trans_id, 0);
                    }
                    SpinnerEvent::GetState => {
                        self.send_spin_state_reply(trans_id);
                    }
                }
            }
            ChannelState::Running => {
                match event {
                    SpinnerEvent::GetPlan => {
                        self.send_spin_plan_reply(trans_id);
                    }
                    SpinnerEvent::SetState(data) => {
                        self.set_channel_state(data);
                        self.send_return_val(trans_id, 0);
                    }
                    SpinnerEvent::GetState => {
                        self.send_spin_state_reply(trans_id);
                    }
                    _ => {
                        self.send_return_val(trans_id, 1);
                    }
                }
            }
            ChannelState::Spindown => {
                match event {
                    SpinnerEvent::GetPlan => {
                        self.send_spin_plan_reply(trans_id);
                    }
                    SpinnerEvent::GetState => {
                        self.send_spin_state_reply(trans_id);
                    }
                    _ => {
                        self.send_return_val(trans_id, 1);
                    }
                }
            }
        }
    }

    fn send_spin_plan_reply(&self, trans_id: u32) {
        let mut msg = if let Ok(msg) = MessageWrapper::new(trans_id, MsgTypes::PLAN_REPLY) {
            msg
        } else {
            return;
        };

        if let Message::SpinPlanReply(ref mut data) = *msg {
            data.channel_num = self.id;
            data.spin_plan_leg_count = self.plan_len as u32;
            for leg_idx in 0..self.plan_len {
                data.plan_legs[leg_idx].duration_msecs = self.plan[leg_idx].duration_msecs;
                data.plan_legs[leg_idx].target_pct = self.plan[leg_idx].target_pct;
            }
        } else {
            return;
        }

        get_outgoing_queue().write(msg.into());
    }

    fn send_spin_state_reply(&self, trans_id: u32) {
        let mut msg = if let Ok(msg) = MessageWrapper::new(trans_id, MsgTypes::STATE_REPLY) {
            msg
        } else {
            return;
        };

        if let Message::SpinStateReply(ref mut data) = *msg {
            data.channel_num = self.id;
            data.state = match self.state {
                ChannelState::Stopped => SpinStates::STOPPED,
                ChannelState::Running => SpinStates::RUNNING,
                ChannelState::Spindown => SpinStates::SPINNING_DOWN,
            };
            data.plan_time_elapsed_msecs = self.elapsed_time_msecs;
            data.output_val_pct = self.output_val_pct;

        } else {
            return;
        }

        get_outgoing_queue().write(msg.into());
    }

    fn send_return_val(&self, trans_id: u32, ret_val: i32) {
        let mut msg = if let Ok(msg) = MessageWrapper::new(trans_id, MsgTypes::RET_VAL) {
            msg
        } else {
            return;
        };

        if let Message::ReturnValue(ref mut data) = *msg {
            data.ret_val = ret_val;
        } else {
            return;
        }

        get_outgoing_queue().write(msg.into());
    }

    fn set_channel_state(&mut self, data: &spin_state_set_data) {
        critical!({
            if self.state == ChannelState::Running && data.state == SpinStates::STOPPED {
                self.state = ChannelState::Spindown;
            } else if self.state == ChannelState::Stopped && data.state == SpinStates::RUNNING {
                self.state = ChannelState::Running;
            }
        });
    }

    fn set_channel_plan(&mut self, data: &spin_plan_data) {
        critical!({
            if self.state != ChannelState::Stopped {
                return;
            }
        });

        self.plan_len = data.spin_plan_leg_count as usize;
        for leg_idx in 0..self.plan_len {
            self.plan[leg_idx].duration_msecs = data.plan_legs[leg_idx].duration_msecs;
            self.plan[leg_idx].target_pct = data.plan_legs[leg_idx].target_pct;
        }
    }
}

struct SpinnerContext {
    channels: [Channel; NUM_CHANNELS],
    subsystem_conf: &'static message_dispatcher::subsystem_message_conf,
}

static mut SPINNER_CTX: Option<SpinnerContext> = None;

fn get_channels() -> &'static mut [Channel] {
    unsafe {
        match SPINNER_CTX {
            Some(ref mut ctx) => &mut ctx.channels,
            None => panic!(),
        }
    }
}

fn get_incoming_queue() -> &'static mut Mailbox<*mut message_dispatcher::message> {
    unsafe {
        match SPINNER_CTX {
            Some(ref ctx) => &mut *ctx.subsystem_conf.incoming_msg_queue,
            None => panic!(),
        }
    }
}

fn get_outgoing_queue() -> &'static mut Mailbox<*mut message_dispatcher::message> {
    unsafe {
        match SPINNER_CTX {
            Some(ref ctx) => &mut *ctx.subsystem_conf.outgoing_msg_queue,
            None => panic!(),
        }
    }
}

fn get_outgoing_error_queue() -> &'static mut Mailbox<i32> {
    unsafe {
        match SPINNER_CTX {
            Some(ref ctx) => &mut *ctx.subsystem_conf.outgoing_err_queue,
            None => panic!(),
        }
    }
}

fn get_alloc_fn() -> unsafe extern "C" fn(msg_type_id: u32) -> *mut message_dispatcher::message {
    unsafe {
        match SPINNER_CTX {
            Some(ref ctx) => ctx.subsystem_conf.alloc_message.unwrap(),
            None => panic!(),
        }
    }
}

fn get_free_fn() -> unsafe extern "C" fn(msg: *mut message_dispatcher::message) {
    unsafe {
        match SPINNER_CTX {
            Some(ref ctx) => ctx.subsystem_conf.free_message.unwrap(),
            None => panic!(),
        }
    }
}

#[no_mangle]
pub extern "C" fn spinner_rust_init(conf: *mut message_dispatcher::subsystem_message_conf) {
    unsafe {
        if conf.is_null() || (*conf).incoming_msg_queue.is_null() ||
            (*conf).outgoing_msg_queue.is_null() ||
            (*conf).outgoing_err_queue.is_null() || (*conf).alloc_message.is_some() ||
            (*conf).free_message.is_some()
        {
            panic!();
        }

        SPINNER_CTX = Some(SpinnerContext {
            channels: [Channel::default(); NUM_CHANNELS],
            subsystem_conf: &*conf,
        });
    }
}

#[no_mangle]
pub extern "C" fn spinner_comm_loop(_params: *mut CVoid) {

    let channels = get_channels();
    let in_queue = get_incoming_queue();

    if let Some(msg_ptr) = in_queue.read() {
        if let Ok(msg) = MessageWrapper::try_from(msg_ptr) {

            match *msg {
                Message::SetSpinPlan(ref data) => {
                    let ch_num = data.channel_num as usize;
                    if ch_num < NUM_CHANNELS {
                        channels[ch_num].send_event(
                            msg.get_transaction_id(),
                            SpinnerEvent::SetPlan(data),
                        );
                    }
                }
                Message::GetSpinPlan(ref data) => {
                    let ch_num = data.channel_num as usize;
                    if ch_num < NUM_CHANNELS {
                        channels[ch_num].send_event(
                            msg.get_transaction_id(),
                            SpinnerEvent::GetPlan,
                        );
                    }
                }
                Message::SetSpinState(ref data) => {
                    let ch_num = data.channel_num as usize;
                    if ch_num < NUM_CHANNELS {
                        channels[ch_num].send_event(
                            msg.get_transaction_id(),
                            SpinnerEvent::SetState(data),
                        );
                    }
                }
                Message::GetSpinState(ref data) => {
                    let ch_num = data.channel_num as usize;
                    if ch_num < NUM_CHANNELS {
                        channels[ch_num].send_event(
                            msg.get_transaction_id(),
                            SpinnerEvent::GetState,
                        );
                    }
                }
                _ => {}
            }
        }

        return;
    }

    tasks::sleep(50);
}
<commit_msg>Aligned spinner submodule with changes in dispatcher<commit_after>
use mouros_rust_bindings::mailbox::Mailbox;
use mouros_rust_bindings::CVoid;
use mouros_rust_bindings::tasks;

use bindings::constants;
use bindings::message_dispatcher;

use core::convert::TryFrom;

use bindings::message_dispatcher::{MessageWrapper, MemManagement};

mod MsgTypes {
    pub const SET_PLAN: u32 = 0;
    pub const GET_PLAN: u32 = 1;
    pub const PLAN_REPLY: u32 = 2;
    pub const SET_STATE: u32 = 3;
    pub const GET_STATE: u32 = 4;
    pub const STATE_REPLY: u32 = 5;
    pub const RET_VAL: u32 = 6;
}

#[repr(C)]
pub struct spin_plan_data {
    pub channel_num: u8,
    pub spin_plan_leg_count: u32,
    pub plan_legs: [pwm_leg; 10usize],
}

#[repr(C)]
pub struct pwm_leg {
    pub duration_msecs: u32,
    pub target_pct: f32,
}

#[repr(C)]
pub struct spin_channel {
    pub channel_num: u8,
}

#[repr(C)]
pub struct ret_val {
    pub ret_val: i32,
}

mod SpinStates {
    pub const STOPPED: u32 = 0;
    pub const RUNNING: u32 = 1;
    pub const SPINNING_DOWN: u32 = 2;
}

#[repr(C)]
pub struct spin_state_set_data {
    pub channel_num: u8,
    pub state: u32,
}

#[repr(C)]
pub struct spin_state_data {
    pub channel_num: u8,
    pub state: u32,
    pub plan_time_elapsed_msecs: u32,
    pub output_val_pct: f32,
}

pub enum Message<'a> {
    SetSpinPlan(&'a mut spin_plan_data),
    GetSpinPlan(&'a mut spin_channel),
    SpinPlanReply(&'a mut spin_plan_data),
    SetSpinState(&'a mut spin_state_set_data),
    GetSpinState(&'a mut spin_channel),
    SpinStateReply(&'a mut spin_state_data),
    ReturnValue(&'a mut ret_val),
}

impl<'a> message_dispatcher::MemManagement for Message<'a> {
    fn alloc(msg_type: u32) -> *mut message_dispatcher::message {
        unsafe { get_alloc_fn()(msg_type) }
    }

    fn free(msg_ptr: *mut message_dispatcher::message) {
        unsafe { get_free_fn()(msg_ptr) }
    }
}

impl<'a> TryFrom<*mut message_dispatcher::message> for Message<'a> {
    type Error = ();

    fn try_from(raw_msg_ptr: *mut message_dispatcher::message) -> Result<Self, Self::Error> {
        unsafe {
            if raw_msg_ptr.is_null() || (*raw_msg_ptr).data.is_null() {
                return Err(());
            }

            match (*raw_msg_ptr).msg_type {
                MsgTypes::SET_PLAN => {
                    Ok(Message::SetSpinPlan(
                        &mut *((*raw_msg_ptr).data as *mut spin_plan_data),
                    ))
                }
                MsgTypes::GET_PLAN => {
                    Ok(Message::GetSpinPlan(
                        &mut *((*raw_msg_ptr).data as *mut spin_channel),
                    ))
                }
                MsgTypes::PLAN_REPLY => {
                    Ok(Message::SpinPlanReply(
                        &mut *((*raw_msg_ptr).data as *mut spin_plan_data),
                    ))
                }
                MsgTypes::SET_STATE => {
                    Ok(Message::SetSpinState(
                        &mut *((*raw_msg_ptr).data as *mut spin_state_set_data),
                    ))
                }
                MsgTypes::GET_STATE => {
                    Ok(Message::GetSpinState(
                        &mut *((*raw_msg_ptr).data as *mut spin_channel),
                    ))
                }
                MsgTypes::STATE_REPLY => {
                    Ok(Message::SpinStateReply(
                        &mut *((*raw_msg_ptr).data as *mut spin_state_data),
                    ))
                }
                MsgTypes::RET_VAL => {
                    Ok(Message::ReturnValue(
                        &mut *((*raw_msg_ptr).data as *mut ret_val),
                    ))
                }
                _ => {
                    Self::free(raw_msg_ptr);
                    Err(())
                }
            }
        }
    }
}

const NUM_CHANNELS: usize = 1;

enum SpinnerEvent<'a> {
    SetPlan(&'a spin_plan_data),
    GetPlan,
    SetState(&'a spin_state_set_data),
    GetState,
}

#[derive(PartialEq, Eq)]
enum ChannelState {
    Stopped,
    Running,
    Spindown,
}

#[derive(Default, Clone, Copy)]
struct PlanLeg {
    duration_msecs: u32,
    target_pct: f32,
}

struct Channel {
    id: u8,
    state: ChannelState,
    plan: [PlanLeg; constants::MAX_SPIN_PLAN_LEGS as usize],
    plan_len: usize,
    elapsed_time_msecs: u32,
    output_val_pct: f32,
}

impl Default for Channel {
    fn default() -> Channel {
        Channel {
            id: 0,
            state: ChannelState::Stopped,
            plan: [PlanLeg::default(); constants::MAX_SPIN_PLAN_LEGS as usize],
            plan_len: 0,
            elapsed_time_msecs: 0,
            output_val_pct: 0f32,
        }
    }
}

impl Channel {
    fn send_event(&mut self, trans_id: u32, event: SpinnerEvent) {
        match self.state {
            ChannelState::Stopped => {
                match event {
                    SpinnerEvent::SetPlan(data) => {
                        self.set_channel_plan(data);
                        self.send_return_val(trans_id, 0);
                    }
                    SpinnerEvent::GetPlan => {
                        self.send_spin_plan_reply(trans_id);
                    }
                    SpinnerEvent::SetState(data) => {
                        self.set_channel_state(data);
                        self.send_return_val(trans_id, 0);
                    }
                    SpinnerEvent::GetState => {
                        self.send_spin_state_reply(trans_id);
                    }
                }
            }
            ChannelState::Running => {
                match event {
                    SpinnerEvent::GetPlan => {
                        self.send_spin_plan_reply(trans_id);
                    }
                    SpinnerEvent::SetState(data) => {
                        self.set_channel_state(data);
                        self.send_return_val(trans_id, 0);
                    }
                    SpinnerEvent::GetState => {
                        self.send_spin_state_reply(trans_id);
                    }
                    _ => {
                        self.send_return_val(trans_id, 1);
                    }
                }
            }
            ChannelState::Spindown => {
                match event {
                    SpinnerEvent::GetPlan => {
                        self.send_spin_plan_reply(trans_id);
                    }
                    SpinnerEvent::GetState => {
                        self.send_spin_state_reply(trans_id);
                    }
                    _ => {
                        self.send_return_val(trans_id, 1);
                    }
                }
            }
        }
    }

    fn send_spin_plan_reply(&self, trans_id: u32) {
        let mut msg = if let Ok(msg) = MessageWrapper::new(trans_id, MsgTypes::PLAN_REPLY) {
            msg
        } else {
            return;
        };

        if let Message::SpinPlanReply(ref mut data) = *msg {
            data.channel_num = self.id;
            data.spin_plan_leg_count = self.plan_len as u32;
            for leg_idx in 0..self.plan_len {
                data.plan_legs[leg_idx].duration_msecs = self.plan[leg_idx].duration_msecs;
                data.plan_legs[leg_idx].target_pct = self.plan[leg_idx].target_pct;
            }
        } else {
            return;
        }

        get_outgoing_queue().write(msg.into());
    }

    fn send_spin_state_reply(&self, trans_id: u32) {
        let mut msg = if let Ok(msg) = MessageWrapper::new(trans_id, MsgTypes::STATE_REPLY) {
            msg
        } else {
            return;
        };

        if let Message::SpinStateReply(ref mut data) = *msg {
            data.channel_num = self.id;
            data.state = match self.state {
                ChannelState::Stopped => SpinStates::STOPPED,
                ChannelState::Running => SpinStates::RUNNING,
                ChannelState::Spindown => SpinStates::SPINNING_DOWN,
            };
            data.plan_time_elapsed_msecs = self.elapsed_time_msecs;
            data.output_val_pct = self.output_val_pct;

        } else {
            return;
        }

        get_outgoing_queue().write(msg.into());
    }

    fn send_return_val(&self, trans_id: u32, ret_val: i32) {
        let mut msg = if let Ok(msg) = MessageWrapper::new(trans_id, MsgTypes::RET_VAL) {
            msg
        } else {
            return;
        };

        if let Message::ReturnValue(ref mut data) = *msg {
            data.ret_val = ret_val;
        } else {
            return;
        }

        get_outgoing_queue().write(msg.into());
    }

    fn set_channel_state(&mut self, data: &spin_state_set_data) {
        critical!({
            if self.state == ChannelState::Running && data.state == SpinStates::STOPPED {
                self.state = ChannelState::Spindown;
            } else if self.state == ChannelState::Stopped && data.state == SpinStates::RUNNING {
                self.state = ChannelState::Running;
            }
        });
    }

    fn set_channel_plan(&mut self, data: &spin_plan_data) {
        critical!({
            if self.state != ChannelState::Stopped {
                return;
            }
        });

        self.plan_len = data.spin_plan_leg_count as usize;
        for leg_idx in 0..self.plan_len {
            self.plan[leg_idx].duration_msecs = data.plan_legs[leg_idx].duration_msecs;
            self.plan[leg_idx].target_pct = data.plan_legs[leg_idx].target_pct;
        }
    }
}

struct SpinnerContext {
    channels: [Channel; NUM_CHANNELS],
    subsystem_conf: &'static message_dispatcher::subsystem_message_conf,
}

static mut SPINNER_CTX: Option<SpinnerContext> = None;

fn get_channels() -> &'static mut [Channel] {
    unsafe {
        match SPINNER_CTX {
            Some(ref mut ctx) => &mut ctx.channels,
            None => panic!(),
        }
    }
}

fn get_incoming_queue() -> &'static mut Mailbox<'static, *mut message_dispatcher::message> {
    unsafe {
        match SPINNER_CTX {
            Some(ref ctx) => {
                &mut *(ctx.subsystem_conf.incoming_msg_queue as
                           *mut Mailbox<'static, *mut message_dispatcher::message>)
            }
            None => panic!(),
        }
    }
}

fn get_outgoing_queue() -> &'static mut Mailbox<'static, *mut message_dispatcher::message> {
    unsafe {
        match SPINNER_CTX {
            Some(ref ctx) => {
                &mut *(ctx.subsystem_conf.outgoing_msg_queue as
                           *mut Mailbox<'static, *mut message_dispatcher::message>)
            }
            None => panic!(),
        }
    }
}

fn get_outgoing_error_queue() -> &'static mut Mailbox<'static, i32> {
    unsafe {
        match SPINNER_CTX {
            Some(ref ctx) => {
                &mut *(ctx.subsystem_conf.outgoing_err_queue as *mut Mailbox<'static, i32>)
            }
            None => panic!(),
        }
    }
}

fn get_alloc_fn() -> unsafe extern "C" fn(msg_type_id: u32) -> *mut message_dispatcher::message {
    unsafe {
        match SPINNER_CTX {
            Some(ref ctx) => ctx.subsystem_conf.alloc_message.unwrap(),
            None => panic!(),
        }
    }
}

fn get_free_fn() -> unsafe extern "C" fn(msg: *mut message_dispatcher::message) {
    unsafe {
        match SPINNER_CTX {
            Some(ref ctx) => ctx.subsystem_conf.free_message.unwrap(),
            None => panic!(),
        }
    }
}

#[no_mangle]
pub extern "C" fn spinner_rust_init(conf: *mut message_dispatcher::subsystem_message_conf) {
    unsafe {
        if conf.is_null() || (*conf).incoming_msg_queue.is_null() ||
            (*conf).outgoing_msg_queue.is_null() ||
            (*conf).outgoing_err_queue.is_null() || (*conf).alloc_message.is_none() ||
            (*conf).free_message.is_none()
        {
            panic!();
        }

        SPINNER_CTX = Some(SpinnerContext {
            channels: [Channel::default(); NUM_CHANNELS],
            subsystem_conf: &*conf,
        });
    }
}

#[no_mangle]
pub extern "C" fn spinner_comm_loop(_params: *mut CVoid) {

    let channels = get_channels();
    let in_queue = get_incoming_queue();

    if let Some(msg_ptr) = in_queue.read() {
        if let Ok(msg) = MessageWrapper::try_from(msg_ptr) {

            match *msg {
                Message::SetSpinPlan(ref data) => {
                    let ch_num = data.channel_num as usize;
                    if ch_num < NUM_CHANNELS {
                        channels[ch_num].send_event(
                            msg.get_transaction_id(),
                            SpinnerEvent::SetPlan(data),
                        );
                    }
                }
                Message::GetSpinPlan(ref data) => {
                    let ch_num = data.channel_num as usize;
                    if ch_num < NUM_CHANNELS {
                        channels[ch_num].send_event(
                            msg.get_transaction_id(),
                            SpinnerEvent::GetPlan,
                        );
                    }
                }
                Message::SetSpinState(ref data) => {
                    let ch_num = data.channel_num as usize;
                    if ch_num < NUM_CHANNELS {
                        channels[ch_num].send_event(
                            msg.get_transaction_id(),
                            SpinnerEvent::SetState(data),
                        );
                    }
                }
                Message::GetSpinState(ref data) => {
                    let ch_num = data.channel_num as usize;
                    if ch_num < NUM_CHANNELS {
                        channels[ch_num].send_event(
                            msg.get_transaction_id(),
                            SpinnerEvent::GetState,
                        );
                    }
                }
                _ => {}
            }
        }

        return;
    }

    tasks::sleep(50);
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use aggregate::{Aggregate, AggregateCall};
use answer::Answer;
use data::Data;
use expr::Expr;
use query::{Query, SortDirection};
use row::Row;
use source::{Source, SourceError};

#[derive(Clone, Debug, PartialEq)]
pub enum ExecuteError {
    SourceError(String),
    InvalidOrderClause(Expr),
}

impl From<SourceError> for ExecuteError {
    fn from(e: SourceError) -> Self {
        ExecuteError::SourceError(e.description)
    }
}

struct Executor {
    query: Query,
    aggregate_calls: Vec<AggregateCall>,
    order_indices: Vec<(usize, SortDirection)>,
}

impl Executor {
    fn new(query: Query) -> Result<Self, ExecuteError> {
        let aggregates = query.select.iter()
            .filter_map(|expr| expr.get_aggregate_call())
            .collect();

        let mut order_indices = Vec::new();
        for sort_field in query.order.iter() {
            let position = query.select.iter().position(|select| select == &sort_field.expr);
            let index = match position {
                Some(i) => i,
                None => return Err(ExecuteError::InvalidOrderClause(sort_field.expr.clone())),
            };
            let direction = sort_field.direction.clone().unwrap_or(SortDirection::Asc);
            order_indices.push((index, direction));
        }

        Ok(Executor {
            query: query,
            aggregate_calls: aggregates,
            order_indices: order_indices,
        })
    }

    fn execute(&self, mut source: Source) -> Result<Answer, ExecuteError> {
        if let Some(condition) = self.query.condition.clone() {
            source = Box::new(source.filter(move |row| {
                match row {
                    &Ok(ref row) => condition.eval(row) == Data::Bool(true),
                    &Err(_) => true,
                }
            }));
        }

        let mut answer = if self.aggregate_calls.is_empty() {
            self.execute_non_aggregate(source)?
        } else {
            self.execute_aggregate(source)?
        };

        answer.sort(&self.order_indices);
        Ok(answer)
    }

    fn execute_non_aggregate(&self, source: Source) -> Result<Answer, ExecuteError> {
        let mut rows = Vec::new();
        for row in source {
            let row = row?;
            if !self.passes_condition(&row) {
                continue;
            }

            let output_row = self.query.select.iter()
                .map(|field| field.eval(&row))
                .collect();
            rows.push(output_row);
        }

        Ok(Answer {
            columns: self.get_columns(),
            rows: rows,
        })
    }

    fn execute_aggregate(&self, source: Source) -> Result<Answer, ExecuteError> {
        let aggregates = self.build_aggregates(source)?;
        let aggregate_rows = self.aggregates_to_rows(aggregates);

        let mut rows = Vec::new();
        for aggregate_row in aggregate_rows {
            let output_row = self.query.select.iter()
                .map(|field| field.eval(&aggregate_row))
                .collect();
            rows.push(output_row);
        }

        Ok(Answer {
            columns: self.get_columns(),
            rows: rows,
        })
    }

    fn build_aggregates(&self, source: Source) -> Result<HashMap<Vec<Data>, Vec<Aggregate>>, ExecuteError> {
        let mut groups = HashMap::new();
        for row in source {
            let row = row?;
            if !self.passes_condition(&row) {
                continue;
            }

            let group_aggregates = groups
                .entry(self.get_group(&row))
                .or_insert_with(|| self.make_aggregates());

            for (i, aggregate) in group_aggregates.iter_mut().enumerate() {
                aggregate.apply(self.aggregate_calls[i].argument.eval(&row));
            }
        }

        Ok(groups)
    }

    fn aggregates_to_rows(&self, aggregates: HashMap<Vec<Data>, Vec<Aggregate>>) -> Vec<Row> {
        let mut rows = Vec::with_capacity(aggregates.len());
        for (group, aggregates) in aggregates {
            let mut row = Row::new();
            for (i, aggregate) in aggregates.into_iter().enumerate() {
                let call = self.aggregate_calls[i].clone();
                row.fields.insert(Expr::AggregateCall(call), aggregate.final_value());
            }
            for (index, val) in group.iter().enumerate() {
                row.fields.insert(self.query.group[index].clone(), val.clone());
            }
            rows.push(row);
        }

        rows
    }

    fn passes_condition(&self, row: &Row) -> bool {
        match self.query.condition {
            Some(ref cond) => cond.eval(row) == Data::Bool(true),
            None => true,
        }
    }

    fn get_columns(&self) -> Vec<String> {
        self.query.select.iter()
            .map(|field| format!("{}", field))
            .collect()
    }

    fn get_group(&self, row: &Row) -> Vec<Data> {
        self.query.group.iter()
            .map(|field| field.eval(row))
            .collect()
    }

    fn make_aggregates(&self) -> Vec<Aggregate> {
        self.aggregate_calls.iter()
            .map(|call| call.function.aggregate())
            .collect()
    }
}

pub fn execute(query: Query, source: Source) -> Result<Answer, ExecuteError> {
    Executor::new(query)?.execute(source)
}

#[cfg(test)]
mod tests {
    use super::*;
    use aggregate::{AggregateCall, AggregateFunction};
    use data::Data;
    use expr::Expr;
    use query::OrderField;
    use row::make_rows;

    #[test]
    fn aggregate_query() {
        let source = make_rows(
            vec!["a"],
            vec![
                data_vec![1],
                data_vec![2],
                data_vec![3],
                data_vec![4],
                data_vec![5],
            ],
        );

        let call = AggregateCall{
            function: AggregateFunction::Sum,
            argument: Box::new(Expr::Column(String::from("a"))),
        };

        let query = Query {
            select: vec![Expr::AggregateCall(call)],
            from: String::new(),
            condition: None,
            group: vec![],
            order: vec![],
        };

        let actual = execute(query, Box::new(source.into_iter())).unwrap();
        let expected = Answer {
            columns: vec![String::from(r#"sum("a")"#)],
            rows: vec![data_vec![15]],
        };

        assert_eq!(expected, actual);
    }

    #[test]
    fn non_aggregate_query() {
        let source = make_rows(
            vec!["a"],
            vec![
                data_vec![1],
                data_vec![2],
                data_vec![3],
                data_vec![4],
                data_vec![5],
            ],
        );

        let query = Query {
            select: vec![Expr::Column(String::from("a"))],
            from: String::new(),
            condition: None,
            group: vec![],
            order: vec![],
        };

        let actual = execute(query, Box::new(source.clone().into_iter())).unwrap();
        let expected = Answer {
            columns: vec![String::from(r#""a""#)],
            rows: vec![
                data_vec![1],
                data_vec![2],
                data_vec![3],
                data_vec![4],
                data_vec![5],
            ],
        };

        assert_eq!(expected, actual);
    }

    #[test]
    fn invalid_order_clause() {
        let source = make_rows(
            vec!["a"],
            vec![],
        );

        let query = Query {
            select: vec![],
            from: String::new(),
            condition: None,
            group: vec![],
            order: vec![OrderField {
                expr: Expr::Column(String::from("a")),
                direction: None,
            }],
        };
        let actual = execute(query, Box::new(source.clone().into_iter()));
        let expected = Err(ExecuteError::InvalidOrderClause(Expr::Column(String::from("a"))));
        assert_eq!(expected, actual);
    }
}
<commit_msg>Remove redundant filter<commit_after>use std::collections::HashMap;
use aggregate::{Aggregate, AggregateCall};
use answer::Answer;
use data::Data;
use expr::Expr;
use query::{Query, SortDirection};
use row::Row;
use source::{Source, SourceError};

#[derive(Clone, Debug, PartialEq)]
pub enum ExecuteError {
    SourceError(String),
    InvalidOrderClause(Expr),
}

impl From<SourceError> for ExecuteError {
    fn from(e: SourceError) -> Self {
        ExecuteError::SourceError(e.description)
    }
}

struct Executor {
    query: Query,
    aggregate_calls: Vec<AggregateCall>,
    order_indices: Vec<(usize, SortDirection)>,
}

impl Executor {
    fn new(query: Query) -> Result<Self, ExecuteError> {
        let aggregates = query.select.iter()
            .filter_map(|expr| expr.get_aggregate_call())
            .collect();

        let mut order_indices = Vec::new();
        for sort_field in query.order.iter() {
            let position = query.select.iter().position(|select| select == &sort_field.expr);
            let index = match position {
                Some(i) => i,
                None => return Err(ExecuteError::InvalidOrderClause(sort_field.expr.clone())),
            };
            let direction = sort_field.direction.clone().unwrap_or(SortDirection::Asc);
            order_indices.push((index, direction));
        }

        Ok(Executor {
            query: query,
            aggregate_calls: aggregates,
            order_indices: order_indices,
        })
    }

    fn execute(&self, source: Source) -> Result<Answer, ExecuteError> {
        let mut answer = if self.aggregate_calls.is_empty() {
            self.execute_non_aggregate(source)?
        } else {
            self.execute_aggregate(source)?
        };

        answer.sort(&self.order_indices);
        Ok(answer)
    }

    fn execute_non_aggregate(&self, source: Source) -> Result<Answer, ExecuteError> {
        let mut rows = Vec::new();
        for row in source {
            let row = row?;
            if !self.passes_condition(&row) {
                continue;
            }

            let output_row = self.query.select.iter()
                .map(|field| field.eval(&row))
                .collect();
            rows.push(output_row);
        }

        Ok(Answer {
            columns: self.get_columns(),
            rows: rows,
        })
    }

    fn execute_aggregate(&self, source: Source) -> Result<Answer, ExecuteError> {
        let aggregates = self.build_aggregates(source)?;
        let aggregate_rows = self.aggregates_to_rows(aggregates);

        let mut rows = Vec::new();
        for aggregate_row in aggregate_rows {
            let output_row = self.query.select.iter()
                .map(|field| field.eval(&aggregate_row))
                .collect();
            rows.push(output_row);
        }

        Ok(Answer {
            columns: self.get_columns(),
            rows: rows,
        })
    }

    fn build_aggregates(&self, source: Source) -> Result<HashMap<Vec<Data>, Vec<Aggregate>>, ExecuteError> {
        let mut groups = HashMap::new();
        for row in source {
            let row = row?;
            if !self.passes_condition(&row) {
                continue;
            }

            let group_aggregates = groups
                .entry(self.get_group(&row))
                .or_insert_with(|| self.make_aggregates());

            for (i, aggregate) in group_aggregates.iter_mut().enumerate() {
                aggregate.apply(self.aggregate_calls[i].argument.eval(&row));
            }
        }

        Ok(groups)
    }

    fn aggregates_to_rows(&self, aggregates: HashMap<Vec<Data>, Vec<Aggregate>>) -> Vec<Row> {
        let mut rows = Vec::with_capacity(aggregates.len());
        for (group, aggregates) in aggregates {
            let mut row = Row::new();
            for (i, aggregate) in aggregates.into_iter().enumerate() {
                let call = self.aggregate_calls[i].clone();
                row.fields.insert(Expr::AggregateCall(call), aggregate.final_value());
            }
            for (index, val) in group.iter().enumerate() {
                row.fields.insert(self.query.group[index].clone(), val.clone());
            }
            rows.push(row);
        }

        rows
    }

    fn passes_condition(&self, row: &Row) -> bool {
        match self.query.condition {
            Some(ref cond) => cond.eval(row) == Data::Bool(true),
            None => true,
        }
    }

    fn get_columns(&self) -> Vec<String> {
        self.query.select.iter()
            .map(|field| format!("{}", field))
            .collect()
    }

    fn get_group(&self, row: &Row) -> Vec<Data> {
        self.query.group.iter()
            .map(|field| field.eval(row))
            .collect()
    }

    fn make_aggregates(&self) -> Vec<Aggregate> {
        self.aggregate_calls.iter()
            .map(|call| call.function.aggregate())
            .collect()
    }
}

pub fn execute(query: Query, source: Source) -> Result<Answer, ExecuteError> {
    Executor::new(query)?.execute(source)
}

#[cfg(test)]
mod tests {
    use super::*;
    use aggregate::{AggregateCall, AggregateFunction};
    use data::Data;
    use expr::Expr;
    use query::OrderField;
    use row::make_rows;

    #[test]
    fn aggregate_query() {
        let source = make_rows(
            vec!["a"],
            vec![
                data_vec![1],
                data_vec![2],
                data_vec![3],
                data_vec![4],
                data_vec![5],
            ],
        );

        let call = AggregateCall{
            function: AggregateFunction::Sum,
            argument: Box::new(Expr::Column(String::from("a"))),
        };

        let query = Query {
            select: vec![Expr::AggregateCall(call)],
            from: String::new(),
            condition: None,
            group: vec![],
            order: vec![],
        };

        let actual = execute(query, Box::new(source.into_iter())).unwrap();
        let expected = Answer {
            columns: vec![String::from(r#"sum("a")"#)],
            rows: vec![data_vec![15]],
        };

        assert_eq!(expected, actual);
    }

    #[test]
    fn non_aggregate_query() {
        let source = make_rows(
            vec!["a"],
            vec![
                data_vec![1],
                data_vec![2],
                data_vec![3],
                data_vec![4],
                data_vec![5],
            ],
        );

        let query = Query {
            select: vec![Expr::Column(String::from("a"))],
            from: String::new(),
            condition: None,
            group: vec![],
            order: vec![],
        };

        let actual = execute(query, Box::new(source.clone().into_iter())).unwrap();
        let expected = Answer {
            columns: vec![String::from(r#""a""#)],
            rows: vec![
                data_vec![1],
                data_vec![2],
                data_vec![3],
                data_vec![4],
                data_vec![5],
            ],
        };

        assert_eq!(expected, actual);
    }

    #[test]
    fn invalid_order_clause() {
        let source = make_rows(
            vec!["a"],
            vec![],
        );

        let query = Query {
            select: vec![],
            from: String::new(),
            condition: None,
            group: vec![],
            order: vec![OrderField {
                expr: Expr::Column(String::from("a")),
                direction: None,
            }],
        };
        let actual = execute(query, Box::new(source.clone().into_iter()));
        let expected = Err(ExecuteError::InvalidOrderClause(Expr::Column(String::from("a"))));
        assert_eq!(expected, actual);
    }
}
<|endoftext|>