<commit_before>import std::{io, term};
import io::writer_util;
import syntax::codemap;
import codemap::span;

export emit_warning, emit_error, emit_note;

tag diagnostictype {
    warning;
    error;
    note;
}

fn diagnosticstr(t: diagnostictype) -> str {
    alt t {
      warning. { "warning" }
      error. { "error" }
      note. { "note" }
    }
}

fn diagnosticcolor(t: diagnostictype) -> u8 {
    alt t {
      warning. { term::color_bright_yellow }
      error. { term::color_bright_red }
      note. { term::color_bright_green }
    }
}

fn print_diagnostic(topic: str, t: diagnostictype, msg: str) {
    if str::is_not_empty(topic) {
        io::stdout().write_str(#fmt["%s ", topic]);
    }
    if term::color_supported() {
        term::fg(io::stdout(), diagnosticcolor(t));
    }
    io::stdout().write_str(#fmt["%s:", diagnosticstr(t)]);
    if term::color_supported() {
        term::reset(io::stdout());
    }
    io::stdout().write_str(#fmt[" %s\n", msg]);
}

fn emit_diagnostic(cmsp: option<(codemap::codemap, span)>,
                   msg: str, t: diagnostictype) {
    alt cmsp {
      some((cm, sp)) {
        let ss = codemap::span_to_str(sp, cm);
        let lines = codemap::span_to_lines(sp, cm);
        print_diagnostic(ss, t, msg);
        highlight_lines(cm, sp, lines);
      }
      none. {
        print_diagnostic("", t, msg);
      }
    }
}

fn highlight_lines(cm: codemap::codemap, sp: span,
                   lines: @codemap::file_lines) {

    // If we're not looking at a real file then we can't re-open it to
    // pull out the lines
    if lines.name == "-" { ret; }

    // FIXME: reading in the entire file is the worst possible way to
    //        get access to the necessary lines.
    let file = alt io::read_whole_file_str(lines.name) {
      result::ok(file) { file }
      result::err(e) {
        emit_error(none, e);
        fail;
      }
    };
    let fm = codemap::get_filemap(cm, lines.name);

    // arbitrarily only print up to six lines of the error
    let max_lines = 6u;
    let elided = false;
    let display_lines = lines.lines;
    if vec::len(display_lines) > max_lines {
        display_lines = vec::slice(display_lines, 0u, max_lines);
        elided = true;
    }
    // Print the offending lines
    for line: uint in display_lines {
        io::stdout().write_str(#fmt["%s:%u ", fm.name, line + 1u]);
        let s = codemap::get_line(fm, line as int, file);
        if !str::ends_with(s, "\n") { s += "\n"; }
        io::stdout().write_str(s);
    }
    if elided {
        let last_line = display_lines[vec::len(display_lines) - 1u];
        let s = #fmt["%s:%u ", fm.name, last_line + 1u];
        let indent = str::char_len(s);
        let out = "";
        while indent > 0u { out += " "; indent -= 1u; }
        out += "...\n";
        io::stdout().write_str(out);
    }

    // If there's one line at fault we can easily point to the problem
    if vec::len(lines.lines) == 1u {
        let lo = codemap::lookup_char_pos(cm, sp.lo);
        let digits = 0u;
        let num = (lines.lines[0] + 1u) / 10u;

        // how many digits must be indent past?
        while num > 0u { num /= 10u; digits += 1u; }

        // indent past |name:## | and the 0-offset column location
        let left = str::char_len(fm.name) + digits + lo.col + 3u;
        let s = "";
        while left > 0u { str::push_char(s, ' '); left -= 1u; }

        s += "^";
        let hi = codemap::lookup_char_pos(cm, sp.hi);
        if hi.col != lo.col {
            // the ^ already takes up one space
            let width = hi.col - lo.col - 1u;
            while width > 0u { str::push_char(s, '~'); width -= 1u; }
        }
        io::stdout().write_str(s + "\n");
    }
}

fn emit_warning(cmsp: option<(codemap::codemap, span)>, msg: str) {
    emit_diagnostic(cmsp, msg, warning);
}
fn emit_error(cmsp: option<(codemap::codemap, span)>, msg: str) {
    emit_diagnostic(cmsp, msg, error);
}
fn emit_note(cmsp: option<(codemap::codemap, span)>, msg: str) {
    emit_diagnostic(cmsp, msg, note);
}
<commit_msg>rustc: Add diagnostic::handler iface and default impl<commit_after>import std::{io, term};
import io::writer_util;
import syntax::codemap;
import codemap::span;

export emit_warning, emit_error, emit_note;
export handler, codemap_handler;

iface handler {
    fn span_fatal(sp: span, msg: str) -> !;
    fn fatal(msg: str) -> !;
    fn span_err(sp: span, msg: str);
    fn err(msg: str);
    fn has_errors() -> bool;
    fn abort_if_errors();
    fn span_warn(sp: span, msg: str);
    fn warn(msg: str);
    fn span_note(sp: span, msg: str);
    fn note(msg: str);
    fn span_bug(sp: span, msg: str) -> !;
    fn bug(msg: str) -> !;
    fn span_unimpl(sp: span, msg: str) -> !;
    fn unimpl(msg: str) -> !;
}

type codemap_t = @{
    cm: codemap::codemap,
    mutable err_count: uint
};

impl codemap_handler of handler for codemap_t {
    fn span_fatal(sp: span, msg: str) -> ! {
        emit_error(some((self.cm, sp)), msg);
        fail;
    }
    fn fatal(msg: str) -> ! {
        emit_error(none, msg);
        fail;
    }
    fn span_err(sp: span, msg: str) {
        emit_error(some((self.cm, sp)), msg);
        self.err_count += 1u;
    }
    fn err(msg: str) {
        emit_error(none, msg);
        self.err_count += 1u;
    }
    fn has_errors() -> bool { self.err_count > 0u }
    fn abort_if_errors() {
        if self.err_count > 0u {
            self.fatal("aborting due to previous errors");
        }
    }
    fn span_warn(sp: span, msg: str) {
        emit_warning(some((self.cm, sp)), msg);
    }
    fn warn(msg: str) {
        emit_warning(none, msg);
    }
    fn span_note(sp: span, msg: str) {
        emit_note(some((self.cm, sp)), msg);
    }
    fn note(msg: str) {
        emit_note(none, msg);
    }
    fn span_bug(sp: span, msg: str) -> ! {
        self.span_fatal(sp, #fmt["internal compiler error %s", msg]);
    }
    fn bug(msg: str) -> ! {
        self.fatal(#fmt["internal compiler error %s", msg]);
    }
    fn span_unimpl(sp: span, msg: str) -> ! {
        self.span_bug(sp, "unimplemented " + msg);
    }
    fn unimpl(msg: str) -> ! { self.bug("unimplemented " + msg); }
}

fn mk_codemap_handler(cm: codemap::codemap) -> handler {
    @{
        cm: cm,
        mutable err_count: 0u,
    } as handler
}

tag diagnostictype {
    warning;
    error;
    note;
}

fn diagnosticstr(t: diagnostictype) -> str {
    alt t {
      warning. { "warning" }
      error. { "error" }
      note. { "note" }
    }
}

fn diagnosticcolor(t: diagnostictype) -> u8 {
    alt t {
      warning. { term::color_bright_yellow }
      error. { term::color_bright_red }
      note. { term::color_bright_green }
    }
}

fn print_diagnostic(topic: str, t: diagnostictype, msg: str) {
    if str::is_not_empty(topic) {
        io::stdout().write_str(#fmt["%s ", topic]);
    }
    if term::color_supported() {
        term::fg(io::stdout(), diagnosticcolor(t));
    }
    io::stdout().write_str(#fmt["%s:", diagnosticstr(t)]);
    if term::color_supported() {
        term::reset(io::stdout());
    }
    io::stdout().write_str(#fmt[" %s\n", msg]);
}

fn emit_diagnostic(cmsp: option<(codemap::codemap, span)>,
                   msg: str, t: diagnostictype) {
    alt cmsp {
      some((cm, sp)) {
        let ss = codemap::span_to_str(sp, cm);
        let lines = codemap::span_to_lines(sp, cm);
        print_diagnostic(ss, t, msg);
        highlight_lines(cm, sp, lines);
      }
      none. {
        print_diagnostic("", t, msg);
      }
    }
}

fn highlight_lines(cm: codemap::codemap, sp: span,
                   lines: @codemap::file_lines) {

    // If we're not looking at a real file then we can't re-open it to
    // pull out the lines
    if lines.name == "-" { ret; }

    // FIXME: reading in the entire file is the worst possible way to
    //        get access to the necessary lines.
    let file = alt io::read_whole_file_str(lines.name) {
      result::ok(file) { file }
      result::err(e) {
        emit_error(none, e);
        fail;
      }
    };
    let fm = codemap::get_filemap(cm, lines.name);

    // arbitrarily only print up to six lines of the error
    let max_lines = 6u;
    let elided = false;
    let display_lines = lines.lines;
    if vec::len(display_lines) > max_lines {
        display_lines = vec::slice(display_lines, 0u, max_lines);
        elided = true;
    }
    // Print the offending lines
    for line: uint in display_lines {
        io::stdout().write_str(#fmt["%s:%u ", fm.name, line + 1u]);
        let s = codemap::get_line(fm, line as int, file);
        if !str::ends_with(s, "\n") { s += "\n"; }
        io::stdout().write_str(s);
    }
    if elided {
        let last_line = display_lines[vec::len(display_lines) - 1u];
        let s = #fmt["%s:%u ", fm.name, last_line + 1u];
        let indent = str::char_len(s);
        let out = "";
        while indent > 0u { out += " "; indent -= 1u; }
        out += "...\n";
        io::stdout().write_str(out);
    }

    // If there's one line at fault we can easily point to the problem
    if vec::len(lines.lines) == 1u {
        let lo = codemap::lookup_char_pos(cm, sp.lo);
        let digits = 0u;
        let num = (lines.lines[0] + 1u) / 10u;

        // how many digits must be indent past?
        while num > 0u { num /= 10u; digits += 1u; }

        // indent past |name:## | and the 0-offset column location
        let left = str::char_len(fm.name) + digits + lo.col + 3u;
        let s = "";
        while left > 0u { str::push_char(s, ' '); left -= 1u; }

        s += "^";
        let hi = codemap::lookup_char_pos(cm, sp.hi);
        if hi.col != lo.col {
            // the ^ already takes up one space
            let width = hi.col - lo.col - 1u;
            while width > 0u { str::push_char(s, '~'); width -= 1u; }
        }
        io::stdout().write_str(s + "\n");
    }
}

fn emit_warning(cmsp: option<(codemap::codemap, span)>, msg: str) {
    emit_diagnostic(cmsp, msg, warning);
}
fn emit_error(cmsp: option<(codemap::codemap, span)>, msg: str) {
    emit_diagnostic(cmsp, msg, error);
}
fn emit_note(cmsp: option<(codemap::codemap, span)>, msg: str) {
    emit_diagnostic(cmsp, msg, note);
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::path::Path;
use std::fs::OpenOptions;
use std::io::Write;

pub fn gen_schemata_modfile(modfile_path: &Path, proto_path: &PathBuf) {
    let mut f = OpenOptions::new()
        .create(true)
        .write(true)
        .append(true)
        .open(modfile_path)
        .unwrap();

    write!(f, "pub mod {};\n", proto_path.file_stem().unwrap().to_str().unwrap()).unwrap();
}

pub fn append_schemata_modfile(modfile_path: &Path, msgdefs: &Vec<String>) {
    let mut f = OpenOptions::new()
        .create(true)
        .write(true)
        .append(true)
        .open(modfile_path)
        .unwrap();

    write!(f, "{}", format_msgdefs(msgdefs)).unwrap();
}

pub fn gen_protob_file(protob_path: &Path, msgdefs: &Vec<String>) {
    let mut f = OpenOptions::new()
        .create(true)
        .write(true)
        .append(true)
        .open(protob_path)
        .unwrap();

    write!(&mut f, "
mod schemata;

use protobuf::Message;
use protobuf::CodedInputStream;

use std::io::Read;
use std::io::StdinLock;

{}

pub fn process_bytes(read: &mut StdinLock) {{
    let mut stream = CodedInputStream::new(read);

    {}
}}
", format_msgdefs(msgdefs), format_mergefrom_calls(msgdefs)).unwrap();
}

fn format_msgdefs(msgdefs: &Vec<String>) -> String {
    let mut ret = Vec::new();

    for m in msgdefs {
        ret.push(format!("use schemata::{};", m));
    }
    ret.join("\n")
}

fn format_mergefrom_calls(msgdefs: &Vec<String>) -> String {
    let mut ret = Vec::new();

    for m in msgdefs {
        let split = m.split("::");
        let vec = split.collect::<Vec<&str>>();
        ret.push(format!("{}::new().merge_from(&mut stream).unwrap();", vec.last().unwrap()));
    }
    ret.join("\n")
}
<commit_msg>Format generated code better<commit_after>use std::path::PathBuf;
use std::path::Path;
use std::fs::OpenOptions;
use std::io::Write;

pub fn gen_schemata_modfile(modfile_path: &Path, proto_path: &PathBuf) {
    let mut f = OpenOptions::new()
        .create(true)
        .write(true)
        .append(true)
        .open(modfile_path)
        .unwrap();

    write!(f, "pub mod {};\n", proto_path.file_stem().unwrap().to_str().unwrap()).unwrap();
}

pub fn append_schemata_modfile(modfile_path: &Path, msgdefs: &Vec<String>) {
    let mut f = OpenOptions::new()
        .create(true)
        .write(true)
        .append(true)
        .open(modfile_path)
        .unwrap();

    write!(f, "\n").unwrap();
    write!(f, "{}", format_msgdefs(msgdefs)).unwrap();
}

pub fn gen_protob_file(protob_path: &Path, msgdefs: &Vec<String>) {
    let mut f = OpenOptions::new()
        .create(true)
        .write(true)
        .append(true)
        .open(protob_path)
        .unwrap();

    write!(&mut f, "mod schemata;

use protobuf::Message;
use protobuf::CodedInputStream;

use std::io::Read;
use std::io::StdinLock;

{}

pub fn process_bytes(read: &mut Read) {{
    let mut stream = CodedInputStream::new(read);

{}
}}
", format_msgdefs(msgdefs), format_mergefrom_calls(msgdefs)).unwrap();
}

fn format_msgdefs(msgdefs: &Vec<String>) -> String {
    let mut ret = Vec::new();

    for m in msgdefs {
        ret.push(format!("use schemata::{};", m));
    }
    ret.join("\n")
}

fn format_mergefrom_calls(msgdefs: &Vec<String>) -> String {
    let mut ret = Vec::new();

    for m in msgdefs {
        let split = m.split("::");
        let vec = split.collect::<Vec<&str>>();
        ret.push(format!("\tmatch {}::new().merge_from(&mut stream) {{
        Ok(x) => println!(\"{{:?}}\", x),
        Err(e) => panic!(e),
    }};", vec.last().unwrap()));
    }
    ret.join("\n")
}
<|endoftext|>


<commit_before>//! The main entry point for the Space API server.
//!
//! Running this code starts a HTTP server instance. The default port is 3000, but you can set your
//! own favorite port by exporting the `PORT` environment variable.

extern crate rustc_serialize;
extern crate iron;
extern crate spaceapi;

pub mod datastore;
pub mod redis_store;

use std::net::Ipv4Addr;
use std::sync::Mutex;
use std::sync::Arc;

use rustc_serialize::json::{Json, ToJson};
use iron::{Request, Response, IronResult, Iron, Set};
use iron::{status, headers, middleware};
use iron::modifiers::Header;

pub use datastore::DataStore;
use spaceapi::utils::Optional;
use spaceapi::SensorTemplate::{PeopleNowPresentSensorTemplate, TemperatureSensorTemplate};

/// A specification of a sensor.
///
/// The ``sensor`` field contains the static data of a sensor and the
/// ``data_key`` says how to find the sensor value in the datastore.
#[derive(Debug)]
pub struct SensorSpec {
    sensor: spaceapi::SensorTemplate,
    data_key: String,
    data_type: SensorValueType,
}

/// All possible value types a sensor can have.
#[derive(Debug)]
pub enum SensorValueType {
    Int,
    Float,
    Bool,
}

/// The actual sensor values.
#[derive(Debug)]
pub enum SensorValue {
    Int(i64),
    Float(f64),
    Bool(bool),
}

/// A Space API server instance.
///
/// You can create a new instance using the ``new`` constructor method by
/// passing it the host, the port, the ``Status`` object and a datastore.
///
/// The ``SpaceapiServer`` includes a web server through
/// [Hyper](http://hyper.rs/hyper/hyper/server/index.html). Simply call the ``serve`` method.
pub struct SpaceapiServer {
    host: Ipv4Addr,
    port: u16,
    status: spaceapi::Status,
    datastore: Arc<Mutex<Box<DataStore>>>,
    sensors: Vec<SensorSpec>
}

impl SpaceapiServer {

    pub fn new(host: Ipv4Addr, port: u16, status: spaceapi::Status, datastore: Arc<Mutex<Box<DataStore>>>) -> SpaceapiServer {
        SpaceapiServer {
            host: host,
            port: port,
            status: status,
            datastore: datastore,
            sensors: vec![],
        }
    }

    /// Start a HTTP server listening on ``self.host:self.port``.
    ///
    /// This call is blocking. It can be interrupted with SIGINT (Ctrl+C).
    pub fn serve(self) {
        let host = self.host;
        let port = self.port;
        println!("Starting HTTP server on http://{}:{}...", host, port);
        Iron::new(self).http((host, port)).unwrap();
    }

    /// Register a new sensor.
    ///
    /// The first argument is a ``spaceapi::Sensor`` instance containing all static data. The
    /// second argument specifies how to get the actual sensor value from the datastore. And the
    /// third argument specifies the data type of the value.
    pub fn register_sensor(&mut self, sensor: spaceapi::SensorTemplate, data_key: String, data_type: SensorValueType) {
        self.sensors.push(
            SensorSpec { sensor: sensor, data_key: data_key, data_type: data_type }
        );
    }

    fn build_response_json(&self) -> Json {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Prepare sensor vector
        let mut temperature_sensors: Vec<spaceapi::TemperatureSensor> = Vec::new();
        let mut people_now_present_sensors: Vec<spaceapi::PeopleNowPresentSensor> = Vec::new();

        // Process registered sensors
        if !self.sensors.is_empty() {

            // Get access to datastore
            let datastore_clone = self.datastore.clone();
            let datastore_lock = datastore_clone.lock().unwrap();

            // Add sensor data
            for sensor_spec in &self.sensors {

                // Retrieve sensor value
                let value: Option<SensorValue> = match datastore_lock.retrieve(&sensor_spec.data_key) {
                    Ok(v) => {
                        match sensor_spec.data_type {
                            SensorValueType::Float => match v.parse::<f64>() {
                                Ok(i) => Some(SensorValue::Float(i)),
                                Err(_) => None,
                            },
                            SensorValueType::Int => match v.parse::<i64>() {
                                Ok(i) => Some(SensorValue::Int(i)),
                                Err(_) => None,
                            },
                            SensorValueType::Bool => None,  // TODO
                        }
                    },
                    Err(_) => None,
                };

                // If value is available, save sensor data
                if value.is_some() {
                    match sensor_spec.sensor {

                        // Create temperature sensor instance
                        TemperatureSensorTemplate { ref unit, ref location, ref name, ref description } => {
                            let sensor = spaceapi::TemperatureSensor {
                                unit: (*unit).clone(),
                                location: (*location).clone(),
                                name: (*name).clone(),
                                description: (*description).clone(),
                                value: match value.unwrap() {
                                    SensorValue::Float(v) => v,
                                    _ => unreachable!(),
                                },
                            };
                            temperature_sensors.push(sensor);
                        },

                        // Create people now present sensor instance
                        PeopleNowPresentSensorTemplate { ref location, ref name, ref names, ref description } => {
                            let sensor = spaceapi::PeopleNowPresentSensor {
                                location: (*location).clone(),
                                name: (*name).clone(),
                                names: (*names).clone(),
                                description: (*description).clone(),
                                value: match value.unwrap() {
                                    SensorValue::Int(v) => v,
                                    _ => unreachable!(),
                                },
                            };
                            people_now_present_sensors.push(sensor);
                        },

                    }
                }

            }

        }

        // Add sensors to status object
        status_copy.sensors = Optional::Value(spaceapi::Sensors {
            people_now_present: match people_now_present_sensors.is_empty() {
                true => Optional::Absent,
                false => Optional::Value(people_now_present_sensors),
            },
            temperature: match temperature_sensors.is_empty() {
                true => Optional::Absent,
                false => Optional::Value(temperature_sensors),
            },
        });

        // Serialize to JSON
        status_copy.to_json()
    }

}

impl middleware::Handler for SpaceapiServer {

    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        // Get response body
        let body = self.build_response_json().to_string();

        // Create response
        let mut response = Response::with((status::Ok, body));

        // Set headers
        response.set_mut(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())));
        response.set_mut(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])));
        response.set_mut(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }
}

#[cfg(test)]
mod test {
    extern crate spaceapi;
    extern crate rustc_serialize;

    use std::net::Ipv4Addr;
    use std::sync::{Mutex,Arc};
    use rustc_serialize::json::Json;
    use spaceapi::Optional;
    use super::SpaceapiServer;
    use super::datastore::DataStore;
    use super::redis_store::RedisStore;

    fn get_test_data() -> Json {
        // Create minimal status object
        let status = spaceapi::Status::new(
            "ourspace".to_string(),
            "https://example.com/logo.png".to_string(),
            "https://example.com/".to_string(),
            spaceapi::Location {
                address: Optional::Value("Street 1, Zürich, Switzerland".to_string()),
                lat: 47.123,
                lon: 8.88,
            },
            spaceapi::Contact {
                irc: Optional::Absent,
                twitter: Optional::Absent,
                foursquare: Optional::Absent,
                email: Optional::Value("hi@example.com".to_string()),
            },
            vec![
                "email".to_string(),
                "twitter".to_string(),
            ],
        );

        // Create datastore (TODO: Create dummy store for testing?)
        let datastore = Arc::new(Mutex::new(Box::new(RedisStore::new().unwrap()) as Box<DataStore>));

        // Initialize server
        let server = SpaceapiServer::new(Ipv4Addr::new(127, 0, 0, 1), 3001, status, datastore);

        // Build JSON
        server.build_response_json()
    }

    #[test]
    /// Verify that the result is a JSON object.
    fn verify_json_obj() {
        let json = get_test_data();
        assert!(json.is_object());
    }

    #[test]
    /// Verify that the result has the correct keys.
    fn verify_json_keys() {
        let json = get_test_data();
        let status = json.as_object().unwrap();  // We get back a BTreeMap<String, Json>
        let keys: Vec<String> = status.keys().cloned().collect();  // Collect the keys
        assert_eq!(keys, ["api", "contact", "issue_report_channels", "location",
                          "logo", "sensors", "space", "state", "url"]);
    }

    #[test]
    /// Verify static data
    fn verify_json_static_data() {
        let json = get_test_data();
        let status = json.as_object().unwrap();  // We get back a BTreeMap<String, Json>

        // Strings
        assert_eq!(status.get("api").unwrap().as_string().unwrap(), "0.13");
        assert_eq!(status.get("space").unwrap().as_string().unwrap(), "ourspace");
        assert_eq!(status.get("url").unwrap().as_string().unwrap(), "https://example.com/");
        assert_eq!(status.get("logo").unwrap().as_string().unwrap(), "https://example.com/logo.png");

        // Channels
        let channels: &Vec<Json> = status.get("issue_report_channels").unwrap().as_array().unwrap();
        let channel_values: Vec<String> = channels.iter()
                                                  .cloned()
                                                  .map(|c| c.as_string().unwrap().to_string())
                                                  .collect();
        assert_eq!(vec!["email", "twitter"], channel_values);
    }

    #[test]
    /// Verify location
    fn verify_json_location() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let location = status.get("location").unwrap().as_object().unwrap();

        // Verify data
        let address = location.get("address").unwrap().as_string().unwrap();
        assert_eq!("Street 1, Zürich, Switzerland".to_string(), address);
        assert_eq!(47.123, location.get("lat").unwrap().as_f64().unwrap());
        assert_eq!(8.88, location.get("lon").unwrap().as_f64().unwrap());
    }

    #[test]
    /// Verify contact
    fn verify_json_contact() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let contact = status.get("contact").unwrap().as_object().unwrap();

        // Verify data
        let email = contact.get("email").unwrap().as_string().unwrap();
        assert_eq!("hi@example.com".to_string(), email);
    }

    /* TODO: Update
    #[test]
    /// Verify sensor data
    fn verify_json_sensors() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let sensors = status.get("sensors").unwrap().as_object().unwrap();
        let temperature_sensor = sensors.get("temperature").unwrap()
                                        .as_array().unwrap()[0]  // List of sensors
                                        .as_object().unwrap();  // Sensor object
        let people_sensor = sensors.get("people_now_present").unwrap()  // List of sensors
                                        .as_array().unwrap()[0]  // Sensor object
                                        .as_object().unwrap();

        // Verify temperature sensor
        let temp_location = temperature_sensor.get("location").unwrap().as_string().unwrap();
        let temp_name = temperature_sensor.get("name").unwrap().as_string().unwrap();
        let temp_unit = temperature_sensor.get("unit").unwrap().as_string().unwrap();
        let temp_value = temperature_sensor.get("value").unwrap().as_f64().unwrap();
        assert_eq!("Basement".to_string(), temp_location);
        assert_eq!("Raspberry CPU".to_string(), temp_name);
        assert_eq!("°C".to_string(), temp_unit);
        assert_eq!(42.5, temp_value);

        // Verify peoplesensor
        let people_location = people_sensor.get("location").unwrap().as_string().unwrap();
        let people_value = people_sensor.get("value").unwrap().as_u64().unwrap();
        assert_eq!("Hackerspace".to_string(), people_location);
        assert_eq!(23, people_value);
    }
    */

}
<commit_msg>Moved sensor data fetching into separate impl<commit_after>//! The main entry point for the Space API server.
//!
//! Running this code starts a HTTP server instance. The default port is 3000, but you can set your
//! own favorite port by exporting the `PORT` environment variable.

extern crate rustc_serialize;
extern crate iron;
extern crate spaceapi;

pub mod datastore;
pub mod redis_store;

use std::net::Ipv4Addr;
use std::sync::{Mutex, Arc};

use rustc_serialize::json::{Json, ToJson};
use iron::{Request, Response, IronResult, Iron, Set};
use iron::{status, headers, middleware};
use iron::modifiers::Header;

pub use datastore::DataStore;
use spaceapi::utils::Optional;
use spaceapi::SensorTemplate::{PeopleNowPresentSensorTemplate, TemperatureSensorTemplate};

/// A specification of a sensor.
///
/// The ``sensor`` field contains the static data of a sensor and the
/// ``data_key`` says how to find the sensor value in the datastore.
#[derive(Debug)]
pub struct SensorSpec {
    sensor: spaceapi::SensorTemplate,
    data_key: String,
    data_type: SensorValueType,
}

/// All possible value types a sensor can have.
#[derive(Debug)]
pub enum SensorValueType {
    Int,
    Float,
    Bool,
}

/// The actual sensor values.
#[derive(Debug)]
pub enum SensorValue {
    Int(i64),
    Float(f64),
    Bool(bool),
}

/// A Space API server instance.
///
/// You can create a new instance using the ``new`` constructor method by
/// passing it the host, the port, the ``Status`` object and a datastore.
///
/// The ``SpaceapiServer`` includes a web server through
/// [Hyper](http://hyper.rs/hyper/hyper/server/index.html). Simply call the ``serve`` method.
pub struct SpaceapiServer {
    host: Ipv4Addr,
    port: u16,
    status: spaceapi::Status,
    datastore: Arc<Mutex<Box<DataStore>>>,
    sensors: Vec<SensorSpec>
}

impl SpaceapiServer {

    pub fn new(host: Ipv4Addr, port: u16, status: spaceapi::Status, datastore: Arc<Mutex<Box<DataStore>>>) -> SpaceapiServer {
        SpaceapiServer {
            host: host,
            port: port,
            status: status,
            datastore: datastore,
            sensors: vec![],
        }
    }

    /// Start a HTTP server listening on ``self.host:self.port``.
    ///
    /// This call is blocking. It can be interrupted with SIGINT (Ctrl+C).
    pub fn serve(self) {
        let host = self.host;
        let port = self.port;
        println!("Starting HTTP server on http://{}:{}...", host, port);
        Iron::new(self).http((host, port)).unwrap();
    }

    /// Register a new sensor.
    ///
    /// The first argument is a ``spaceapi::Sensor`` instance containing all static data. The
    /// second argument specifies how to get the actual sensor value from the datastore. And the
    /// third argument specifies the data type of the value.
    pub fn register_sensor(&mut self, sensor: spaceapi::SensorTemplate, data_key: String, data_type: SensorValueType) {
        self.sensors.push(
            SensorSpec { sensor: sensor, data_key: data_key, data_type: data_type }
        );
    }

    fn build_response_json(&self) -> Json {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Prepare sensor vector
        let mut temperature_sensors: Vec<spaceapi::TemperatureSensor> = Vec::new();
        let mut people_now_present_sensors: Vec<spaceapi::PeopleNowPresentSensor> = Vec::new();

        // Process registered sensors
        if !self.sensors.is_empty() {

            // Get access to datastore
            let datastore_clone = self.datastore.clone();

            // Add sensor data
            for sensor_spec in &self.sensors {

                let value = sensor_spec.get_sensor_value(&datastore_clone);

                // If value is available, save sensor data
                if value.is_some() {
                    match sensor_spec.sensor {

                        // Create temperature sensor instance
                        TemperatureSensorTemplate { ref unit, ref location, ref name, ref description } => {
                            let sensor = spaceapi::TemperatureSensor {
                                unit: (*unit).clone(),
                                location: (*location).clone(),
                                name: (*name).clone(),
                                description: (*description).clone(),
                                value: match value.unwrap() {
                                    SensorValue::Float(v) => v,
                                    _ => unreachable!(),
                                },
                            };
                            temperature_sensors.push(sensor);
                        },

                        // Create people now present sensor instance
                        PeopleNowPresentSensorTemplate { ref location, ref name, ref names, ref description } => {
                            let sensor = spaceapi::PeopleNowPresentSensor {
                                location: (*location).clone(),
                                name: (*name).clone(),
                                names: (*names).clone(),
                                description: (*description).clone(),
                                value: match value.unwrap() {
                                    SensorValue::Int(v) => v,
                                    _ => unreachable!(),
                                },
                            };
                            people_now_present_sensors.push(sensor);
                        },

                    }
                }

            }

        }

        // Add sensors to status object
        status_copy.sensors = Optional::Value(spaceapi::Sensors {
            people_now_present: match people_now_present_sensors.is_empty() {
                true => Optional::Absent,
                false => Optional::Value(people_now_present_sensors),
            },
            temperature: match temperature_sensors.is_empty() {
                true => Optional::Absent,
                false => Optional::Value(temperature_sensors),
            },
        });

        // Serialize to JSON
        status_copy.to_json()
    }

}

trait SensorDataFetcher {
    fn get_sensor_value(&self, datastore: &Arc<Mutex<Box<DataStore>>>) -> Option<SensorValue>;
}

impl SensorDataFetcher for SensorSpec {

    /// Retrieve sensor value from the datastore.
    fn get_sensor_value(&self, datastore: &Arc<Mutex<Box<DataStore>>>) -> Option<SensorValue> {
        let datastore_lock = datastore.lock().unwrap();
        match datastore_lock.retrieve(&self.data_key) {
            Ok(v) => {
                match self.data_type {
                    SensorValueType::Float => match v.parse::<f64>() {
                        Ok(i) => Some(SensorValue::Float(i)),
                        Err(_) => None,
                    },
                    SensorValueType::Int => match v.parse::<i64>() {
                        Ok(i) => Some(SensorValue::Int(i)),
                        Err(_) => None,
                    },
                    SensorValueType::Bool => None,  // TODO
                }
            },
            Err(_) => None,
        }
    }

}

impl middleware::Handler for SpaceapiServer {

    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        // Get response body
        let body = self.build_response_json().to_string();

        // Create response
        let mut response = Response::with((status::Ok, body));

        // Set headers
        response.set_mut(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())));
        response.set_mut(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])));
        response.set_mut(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }
}

#[cfg(test)]
mod test {
    extern crate spaceapi;
    extern crate rustc_serialize;

    use std::net::Ipv4Addr;
    use std::sync::{Mutex,Arc};
    use rustc_serialize::json::Json;
    use spaceapi::utils::Optional;
    use super::SpaceapiServer;
    use super::datastore::DataStore;
    use super::redis_store::RedisStore;

    fn get_test_data() -> Json {
        // Create minimal status object
        let status = spaceapi::Status::new(
            "ourspace".to_string(),
            "https://example.com/logo.png".to_string(),
            "https://example.com/".to_string(),
            spaceapi::Location {
                address: Optional::Value("Street 1, Zürich, Switzerland".to_string()),
                lat: 47.123,
                lon: 8.88,
            },
            spaceapi::Contact {
                irc: Optional::Absent,
                twitter: Optional::Absent,
                foursquare: Optional::Absent,
                email: Optional::Value("hi@example.com".to_string()),
            },
            vec![
                "email".to_string(),
                "twitter".to_string(),
            ],
        );

        // Create datastore (TODO: Create dummy store for testing?)
        let datastore = Arc::new(Mutex::new(Box::new(RedisStore::new().unwrap()) as Box<DataStore>));

        // Initialize server
        let server = SpaceapiServer::new(Ipv4Addr::new(127, 0, 0, 1), 3001, status, datastore);

        // Build JSON
        server.build_response_json()
    }

    #[test]
    /// Verify that the result is a JSON object.
    fn verify_json_obj() {
        let json = get_test_data();
        assert!(json.is_object());
    }

    #[test]
    /// Verify that the result has the correct keys.
    fn verify_json_keys() {
        let json = get_test_data();
        let status = json.as_object().unwrap();  // We get back a BTreeMap<String, Json>
        let keys: Vec<String> = status.keys().cloned().collect();  // Collect the keys
        assert_eq!(keys, ["api", "contact", "issue_report_channels", "location",
                          "logo", "sensors", "space", "state", "url"]);
    }

    #[test]
    /// Verify static data
    fn verify_json_static_data() {
        let json = get_test_data();
        let status = json.as_object().unwrap();  // We get back a BTreeMap<String, Json>

        // Strings
        assert_eq!(status.get("api").unwrap().as_string().unwrap(), "0.13");
        assert_eq!(status.get("space").unwrap().as_string().unwrap(), "ourspace");
        assert_eq!(status.get("url").unwrap().as_string().unwrap(), "https://example.com/");
        assert_eq!(status.get("logo").unwrap().as_string().unwrap(), "https://example.com/logo.png");

        // Channels
        let channels: &Vec<Json> = status.get("issue_report_channels").unwrap().as_array().unwrap();
        let channel_values: Vec<String> = channels.iter()
                                                  .cloned()
                                                  .map(|c| c.as_string().unwrap().to_string())
                                                  .collect();
        assert_eq!(vec!["email", "twitter"], channel_values);
    }

    #[test]
    /// Verify location
    fn verify_json_location() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let location = status.get("location").unwrap().as_object().unwrap();

        // Verify data
        let address = location.get("address").unwrap().as_string().unwrap();
        assert_eq!("Street 1, Zürich, Switzerland".to_string(), address);
        assert_eq!(47.123, location.get("lat").unwrap().as_f64().unwrap());
        assert_eq!(8.88, location.get("lon").unwrap().as_f64().unwrap());
    }

    #[test]
    /// Verify contact
    fn verify_json_contact() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let contact = status.get("contact").unwrap().as_object().unwrap();

        // Verify data
        let email = contact.get("email").unwrap().as_string().unwrap();
        assert_eq!("hi@example.com".to_string(), email);
    }

    /* TODO: Update
    #[test]
    /// Verify sensor data
    fn verify_json_sensors() {
        let json = get_test_data();
        let status = json.as_object().unwrap();
        let sensors = status.get("sensors").unwrap().as_object().unwrap();
        let temperature_sensor = sensors.get("temperature").unwrap()
                                        .as_array().unwrap()[0]  // List of sensors
                                        .as_object().unwrap();  // Sensor object
        let people_sensor = sensors.get("people_now_present").unwrap()  // List of sensors
                                        .as_array().unwrap()[0]  // Sensor object
                                        .as_object().unwrap();

        // Verify temperature sensor
        let temp_location = temperature_sensor.get("location").unwrap().as_string().unwrap();
        let temp_name = temperature_sensor.get("name").unwrap().as_string().unwrap();
        let temp_unit = temperature_sensor.get("unit").unwrap().as_string().unwrap();
        let temp_value = temperature_sensor.get("value").unwrap().as_f64().unwrap();
        assert_eq!("Basement".to_string(), temp_location);
        assert_eq!("Raspberry CPU".to_string(), temp_name);
        assert_eq!("°C".to_string(), temp_unit);
        assert_eq!(42.5, temp_value);

        // Verify peoplesensor
        let people_location = people_sensor.get("location").unwrap().as_string().unwrap();
        let people_value = people_sensor.get("value").unwrap().as_u64().unwrap();
        assert_eq!("Hackerspace".to_string(), people_location);
        assert_eq!(23, people_value);
    }
    */

}
<|endoftext|>


<commit_before>// USAGE EXAMPLES:
//
//   cargo run rotate
//   cargo run rotate -d 0123
//   cargo run rotate -d '\../.\/../\./..X' -s 4 -r 1
//   cargo run rotate --data "0-1|X.2.3" --size 3 --rotate=-1
//   DATA="\..×.\S×魔.☆×→→→→" SIZE=4 ROTATE=10 cargo run rotate
//
// PROBLEM: Rotate Matrix
//   Given an image represented by an NxN matrix, where each pixel in
//   the image is [represented by a Unicode character], write [functions]
//   to rotate the image by 90 [and 180] degrees.
//   Can you do this in place?
//
// EXAMPLES:
//   "01  == CW ===> "20
//    23" == CW ===>  31"
//
//   "01  == FLIP => "32
//    23" == FLIP =>  10"
//
//   "01  == CCW ==> "13
//    23" == CCW ==>  02"
//
//   "0-1  == CW ===> "2|0
//    |X.  == CW ===>  .X-
//    2.3" == CW ===>  3.1"
//
//   "0-1  == FLIP => "3.2
//    .X.  == FLIP =>  .X|
//    2.3" == FLIP =>  1-0"
//
//   "0-1  == CCW ==> "1.3
//    .X.  == CCW ==>  -X.
//    2.3" == CCW ==>  0|2"
//
// Cracking the Coding Interview, 6th Edition, Page 91
// Interview Questions 1.7 [modifications in brackets]

// time complexity, O(N), loop over data
// space complexity, O(N), copy data into vector
pub fn run(string: String, size: i64, rotate: i64) {
  // O(N), loop over data
  let mut data = string.chars().collect::<Vec<_>>();
  // O(1)
  let window_size = if size < 0 {
    (data.len() as f64).sqrt() as usize
  } else {
    size as usize
  };
  // O(1)
  // correct negative values with double % call
  match (4 + rotate % 4) % 4 {
    // O(N), loop over data
    1 => rotate_cw(&mut data, window_size),
    2 => flip(&mut data, window_size),
    3 => rotate_ccw(&mut data, window_size),
    // O(1)
    _ => (),
  }
  // O(N), loop over data
  print_data(&data, window_size);
}

// time complexity, O(N), loop over data
// space complexity, O(1), iterator does not copy data
fn print_data(data: &Vec<char>, window_size: usize) {
  // O(N)
  if window_size < 1 {
    return;
  }
  // O(N), loop over data
  for (i, c) in data.iter().enumerate() {
    // O(1)
    if i % window_size == 0 && i != 0 {
      // O(1)
      println!();
    }
    // O(1)
    print!("{}", c);
  }
  println!();
}

// time complexity, O(1), vector operation
// space complexity, O(1), vector operation
fn read(data: &mut Vec<char>, width: usize, x: usize, y: usize) -> char {
  // O(1), vector operation
  return data[y * width + x];
}

// time complexity, O(1), vector operation
// space complexity, O(1), vector operation
fn blit(
  data: &mut Vec<char>,
  width: usize,
  x: usize,
  y: usize,
  pixel: char
) {
  // O(1), vector operation
  data[y * width + x] = pixel;
}

// time complexity, O(1), vector operation
// space complexity, O(1), vector operation
fn replace(
  data: &mut Vec<char>,
  width: usize,
  x: usize,
  y: usize,
  pixel: char
) -> char {
  // O(1), vector operations
  let result = read(data, width, x, y);
  blit(data, width, x, y, pixel);
  return result;
}

// time complexity, O(N), loop over data
// space complexity, O(1), scalar bookkeeping variables
fn rotate_cw(data: &mut Vec<char>, window_size: usize) {
  // O(1)
  let half_width = (window_size + 1) / 2;
  let half_height = window_size / 2;
  // O(sqrt(N)), loop in x direction of data
  for x in 0..half_width {
    // O(sqrt(N)), loop in y direction of data
    for y in 0..half_height {
      // O(1)
      let inv_x = window_size - x - 1;
      let inv_y = window_size - y - 1;
      // O(1), vector operations
      let mut c = read(data, window_size, x, y);
      c = replace(data, window_size, inv_y,     x, c);
      c = replace(data, window_size, inv_x, inv_y, c);
      c = replace(data, window_size,     y, inv_x, c);
      blit(data, window_size, x, y, c);
    }
  }
}

// time complexity, O(N), loop over data
// space complexity, O(1), scalar bookkeeping variables
fn flip(data: &mut Vec<char>, window_size: usize) {
  // O(1)
  let length = window_size * window_size;
  let half_length = length / 2;
  // O(N), loop over data
  for i in 0..half_length {
    // O(1)
    let inv_i = length - i - 1;
    // O(1), vector operations
    let c = data[i];
    data[i] = data[inv_i];
    data[inv_i] = c;
  }
}

// time complexity, O(N), loop over data
// space complexity, O(1), scalar bookkeeping variables
fn rotate_ccw(data: &mut Vec<char>, window_size: usize) {
  // O(1)
  let half_width = (window_size + 1) / 2;
  let half_height = window_size / 2;
  // O(sqrt(N)), loop in x direction of data
  for x in 0..half_width {
    // O(sqrt(N)), loop in y direction of data
    for y in 0..half_height {
      // O(1)
      let inv_x = window_size - x - 1;
      let inv_y = window_size - y - 1;
      // O(1), vector operations
      let mut c = read(data, window_size, x, y);
      c = replace(data, window_size,     y, inv_x, c);
      c = replace(data, window_size, inv_x, inv_y, c);
      c = replace(data, window_size, inv_y,     x, c);
      blit(data, window_size, x, y, c);
    }
  }
}

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

  #[test]
  fn run_ok() {
    run("1".to_string(), 1, 3);
    run("1".to_string(), -1, 0);
    run("0123".to_string(), 2, 0);
    run("0123".to_string(), -1, -1);
    run("0-1|X.2.3".to_string(), 3, 90);
    run("0-1|X.2.3".to_string(), -1, -103);
  }

  #[test]
  fn returns_expected_even() {
    let mut input = "0123".to_string().chars().collect::<Vec<_>>();
    let original = "0123".to_string().chars().collect::<Vec<_>>();
    let cw = "2031".to_string().chars().collect::<Vec<_>>();
    let flipped = "3210".to_string().chars().collect::<Vec<_>>();
    let ccw = "1302".to_string().chars().collect::<Vec<_>>();
    rotate_cw(&mut input, 2);
    assert_eq!(input, cw);
    rotate_cw(&mut input, 2);
    assert_eq!(input, flipped);
    rotate_cw(&mut input, 2);
    assert_eq!(input, ccw);
    rotate_cw(&mut input, 2);
    assert_eq!(input, original);
    rotate_ccw(&mut input, 2);
    assert_eq!(input, ccw);
    rotate_ccw(&mut input, 2);
    assert_eq!(input, flipped);
    rotate_ccw(&mut input, 2);
    assert_eq!(input, cw);
    rotate_ccw(&mut input, 2);
    assert_eq!(input, original);
    flip(&mut input, 2);
    assert_eq!(input, flipped);
    flip(&mut input, 2);
    assert_eq!(input, original);
  }

  #[test]
  fn returns_expected_odd() {
    let mut input = "0-1|X.2.3".to_string().chars().collect::<Vec<_>>();
    let original = "0-1|X.2.3".to_string().chars().collect::<Vec<_>>();
    let cw = "2|0.X-3.1".to_string().chars().collect::<Vec<_>>();
    let flipped = "3.2.X|1-0".to_string().chars().collect::<Vec<_>>();
    let ccw = "1.3-X.0|2".to_string().chars().collect::<Vec<_>>();
    rotate_cw(&mut input, 3);
    assert_eq!(input, cw);
    rotate_cw(&mut input, 3);
    assert_eq!(input, flipped);
    rotate_cw(&mut input, 3);
    assert_eq!(input, ccw);
    rotate_cw(&mut input, 3);
    assert_eq!(input, original);
    rotate_ccw(&mut input, 3);
    assert_eq!(input, ccw);
    rotate_ccw(&mut input, 3);
    assert_eq!(input, flipped);
    rotate_ccw(&mut input, 3);
    assert_eq!(input, cw);
    rotate_ccw(&mut input, 3);
    assert_eq!(input, original);
    flip(&mut input, 3);
    assert_eq!(input, flipped);
    flip(&mut input, 3);
    assert_eq!(input, original);
  }
}

<commit_msg>Added some unused string-type alternative routines to the rotate solution.<commit_after>// USAGE EXAMPLES:
//
//   cargo run rotate
//   cargo run rotate -d 0123
//   cargo run rotate -d '\../.\/../\./..X' -s 4 -r 1
//   cargo run rotate --data "0-1|X.2.3" --size 3 --rotate=-1
//   DATA="\..×.\S×魔.☆×→→→→" SIZE=4 ROTATE=10 cargo run rotate
//
// PROBLEM: Rotate Matrix
//   Given an image represented by an NxN matrix, where each pixel in
//   the image is [represented by a Unicode character], write [functions]
//   to rotate the image by 90 [and 180] degrees.
//   Can you do this in place?
//
// EXAMPLES:
//   "01  == CW ===> "20
//    23" == CW ===>  31"
//
//   "01  == FLIP => "32
//    23" == FLIP =>  10"
//
//   "01  == CCW ==> "13
//    23" == CCW ==>  02"
//
//   "0-1  == CW ===> "2|0
//    |X.  == CW ===>  .X-
//    2.3" == CW ===>  3.1"
//
//   "0-1  == FLIP => "3.2
//    .X.  == FLIP =>  .X|
//    2.3" == FLIP =>  1-0"
//
//   "0-1  == CCW ==> "1.3
//    .X.  == CCW ==>  -X.
//    2.3" == CCW ==>  0|2"
//
// Cracking the Coding Interview, 6th Edition, Page 91
// Interview Questions 1.7 [modifications in brackets]

// time complexity, O(N), loop over data
// space complexity, O(N), copy data into vector
pub fn run(string: String, size: i64, rotate: i64) {
  // O(N), loop over data
  let mut data = string.chars().collect::<Vec<_>>();
  // O(1)
  let window_size = if size < 0 {
    (data.len() as f64).sqrt() as usize
  } else {
    size as usize
  };
  // O(1)
  // correct negative values with double % call
  match (4 + rotate % 4) % 4 {
    // O(N), loop over data
    1 => rotate_cw(&mut data, window_size),
    2 => flip(&mut data, window_size),
    3 => rotate_ccw(&mut data, window_size),
    // O(1)
    _ => (),
  }
  // O(N), loop over data
  print_data(&data, window_size);
}

// time complexity, O(N), loop over data
// space complexity, O(1), iterator does not copy data
fn print_data(data: &Vec<char>, window_size: usize) {
  // O(N)
  if window_size < 1 {
    return;
  }
  // O(N), loop over data
  for (i, c) in data.iter().enumerate() {
    // O(1)
    if i % window_size == 0 && i != 0 {
      // O(1)
      println!();
    }
    // O(1)
    print!("{}", c);
  }
  // O(1)
  println!();
}

// time complexity, O(N), loop over data
// space complexity, O(N), create map of character indices
// This works fine, but Vec<char> is better than string for
// blitting operations.  See _blit_string() below.
fn _print_data_string(
  data: String,
  window_size: usize
) {
  // O(N), loop over data
  let indices = data
    .char_indices()
    .map(|(i,_)| i)
    .chain([data.len()])
    .collect::<Vec<_>>();
  // O(sqrt(N)), loop in y direction of data
  for i in 0..window_size {
    // O(1)
    let start = indices[i * window_size];
    // O(1)
    let end   = indices[(i + 1) * window_size];
    // O(1)
    println!("{}", &data[start..end]);
  }
}

// time complexity, O(1), vector operation
// space complexity, O(1), vector operation
fn read(data: &mut Vec<char>, width: usize, x: usize, y: usize) -> char {
  // O(1), vector operation
  return data[y * width + x];
}

// time complexity, O(1), vector operation
// space complexity, O(1), vector operation
fn blit(
  data: &mut Vec<char>,
  width: usize,
  x: usize,
  y: usize,
  pixel: char
) {
  // O(1), vector operation
  data[y * width + x] = pixel;
}

// time complexity, O(N), loop over data
// space complexity, O(1), string copy, but not all at once
// String uses less memory than Vec<char>.
// However, String blit is O(N) where Vec<char> blit is O(1).
// Therefore, Vec<char> is the correct data type for heavy blitting.
// To convert from Vec<char> to String, use:
//   vector.iter().collect::<String>();
fn _blit_string(
  data: &mut String,
  width: usize,
  x: usize,
  y: usize,
  pixel: char
) {
  // O(N), loop over data
  let range = data
    .char_indices()
    .nth(y * width + x)
    .map(|(i, c)| i..i + c.len_utf8())
    .unwrap();
  // O(N), string copy
  data.replace_range(range, &pixel.to_string());
}

// time complexity, O(1), vector operation
// space complexity, O(1), vector operation
fn replace(
  data: &mut Vec<char>,
  width: usize,
  x: usize,
  y: usize,
  pixel: char
) -> char {
  // O(1), vector operations
  let result = read(data, width, x, y);
  blit(data, width, x, y, pixel);
  return result;
}

// time complexity, O(N), loop over data
// space complexity, O(1), scalar bookkeeping variables
fn rotate_cw(data: &mut Vec<char>, window_size: usize) {
  // O(1)
  let half_width = (window_size + 1) / 2;
  let half_height = window_size / 2;
  // O(sqrt(N)), loop in x direction of data
  for x in 0..half_width {
    // O(sqrt(N)), loop in y direction of data
    for y in 0..half_height {
      // O(1)
      let inv_x = window_size - x - 1;
      let inv_y = window_size - y - 1;
      // O(1), vector operations
      let mut c = read(data, window_size, x, y);
      c = replace(data, window_size, inv_y,     x, c);
      c = replace(data, window_size, inv_x, inv_y, c);
      c = replace(data, window_size,     y, inv_x, c);
      blit(data, window_size, x, y, c);
    }
  }
}

// time complexity, O(N), loop over data
// space complexity, O(1), scalar bookkeeping variables
fn flip(data: &mut Vec<char>, window_size: usize) {
  // O(1)
  let length = window_size * window_size;
  let half_length = length / 2;
  // O(N), loop over data
  for i in 0..half_length {
    // O(1)
    let inv_i = length - i - 1;
    // O(1), vector operations
    let c = data[i];
    data[i] = data[inv_i];
    data[inv_i] = c;
  }
}

// time complexity, O(N), loop over data
// space complexity, O(1), scalar bookkeeping variables
fn rotate_ccw(data: &mut Vec<char>, window_size: usize) {
  // O(1)
  let half_width = (window_size + 1) / 2;
  let half_height = window_size / 2;
  // O(sqrt(N)), loop in x direction of data
  for x in 0..half_width {
    // O(sqrt(N)), loop in y direction of data
    for y in 0..half_height {
      // O(1)
      let inv_x = window_size - x - 1;
      let inv_y = window_size - y - 1;
      // O(1), vector operations
      let mut c = read(data, window_size, x, y);
      c = replace(data, window_size,     y, inv_x, c);
      c = replace(data, window_size, inv_x, inv_y, c);
      c = replace(data, window_size, inv_y,     x, c);
      blit(data, window_size, x, y, c);
    }
  }
}

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

  #[test]
  fn run_ok() {
    run("1".to_string(), 1, 3);
    run("1".to_string(), -1, 0);
    run("0123".to_string(), 2, 0);
    run("0123".to_string(), -1, -1);
    run("0-1|X.2.3".to_string(), 3, 90);
    run("0-1|X.2.3".to_string(), -1, -103);
  }

  #[test]
  fn returns_expected_even() {
    let mut input = "0123".to_string().chars().collect::<Vec<_>>();
    let original = "0123".to_string().chars().collect::<Vec<_>>();
    let cw = "2031".to_string().chars().collect::<Vec<_>>();
    let flipped = "3210".to_string().chars().collect::<Vec<_>>();
    let ccw = "1302".to_string().chars().collect::<Vec<_>>();
    rotate_cw(&mut input, 2);
    assert_eq!(input, cw);
    rotate_cw(&mut input, 2);
    assert_eq!(input, flipped);
    rotate_cw(&mut input, 2);
    assert_eq!(input, ccw);
    rotate_cw(&mut input, 2);
    assert_eq!(input, original);
    rotate_ccw(&mut input, 2);
    assert_eq!(input, ccw);
    rotate_ccw(&mut input, 2);
    assert_eq!(input, flipped);
    rotate_ccw(&mut input, 2);
    assert_eq!(input, cw);
    rotate_ccw(&mut input, 2);
    assert_eq!(input, original);
    flip(&mut input, 2);
    assert_eq!(input, flipped);
    flip(&mut input, 2);
    assert_eq!(input, original);
  }

  #[test]
  fn returns_expected_odd() {
    let mut input = "0-1|X.2.3".to_string().chars().collect::<Vec<_>>();
    let original = "0-1|X.2.3".to_string().chars().collect::<Vec<_>>();
    let cw = "2|0.X-3.1".to_string().chars().collect::<Vec<_>>();
    let flipped = "3.2.X|1-0".to_string().chars().collect::<Vec<_>>();
    let ccw = "1.3-X.0|2".to_string().chars().collect::<Vec<_>>();
    rotate_cw(&mut input, 3);
    assert_eq!(input, cw);
    rotate_cw(&mut input, 3);
    assert_eq!(input, flipped);
    rotate_cw(&mut input, 3);
    assert_eq!(input, ccw);
    rotate_cw(&mut input, 3);
    assert_eq!(input, original);
    rotate_ccw(&mut input, 3);
    assert_eq!(input, ccw);
    rotate_ccw(&mut input, 3);
    assert_eq!(input, flipped);
    rotate_ccw(&mut input, 3);
    assert_eq!(input, cw);
    rotate_ccw(&mut input, 3);
    assert_eq!(input, original);
    flip(&mut input, 3);
    assert_eq!(input, flipped);
    flip(&mut input, 3);
    assert_eq!(input, original);
  }
}

<|endoftext|>


<commit_before>extern crate rna_transcription as dna;

#[test]
fn test_valid_dna_input() {
    assert!(dna::DNA::new("GCTA").is_ok());
}

#[test]
#[ignore]
fn test_valid_rna_input() {
    assert!(dna::RNA::new("CGAU").is_ok());
}

#[test]
#[ignore]
fn test_invalid_dna_input() {
    // Invalid character
    assert!(dna::DNA::new("X").is_err());
    // Valid nucleotide, but invalid in context
    assert!(dna::DNA::new("U").is_err());
    // Longer string with contained errors
    assert!(dna::DNA::new("ACGTUXXCTTAA").is_err());
}

#[test]
#[ignore]
fn test_invalid_rna_input() {
    // Invalid character
    assert!(dna::RNA::new("X").is_err());
    // Valid nucleotide, but invalid in context
    assert!(dna::RNA::new("T").is_err());
    // Longer string with contained errors
    assert!(dna::RNA::new("ACGUTTXCUUAA").is_err());
}

#[test]
#[ignore]
fn test_acid_equals_acid() {
    assert_eq!(dna::DNA::new("CGA").unwrap(), dna::DNA::new("CGA").unwrap());
    assert_ne!(dna::DNA::new("CGA").unwrap(), dna::DNA::new("AGC").unwrap());
    assert_eq!(dna::RNA::new("CGA").unwrap(), dna::RNA::new("CGA").unwrap());
    assert_ne!(dna::RNA::new("CGA").unwrap(), dna::RNA::new("AGC").unwrap());
}

#[test]
#[ignore]
fn test_transcribes_cytosine_guanine() {
    assert_eq!(
        dna::RNA::new("G").unwrap(),
        dna::DNA::new("C").unwrap().to_rna()
    );
}

#[test]
#[ignore]
fn test_transcribes_guanine_cytosine() {
    assert_eq!(
        dna::RNA::new("C").unwrap(),
        dna::DNA::new("G").unwrap().to_rna()
    );
}

#[test]
#[ignore]
fn test_transcribes_adenine_uracil() {
    assert_eq!(
        dna::RNA::new("U").unwrap(),
        dna::DNA::new("A").unwrap().to_rna()
    );
}

#[test]
#[ignore]
fn test_transcribes_thymine_to_adenine() {
    assert_eq!(
        dna::RNA::new("A").unwrap(),
        dna::DNA::new("T").unwrap().to_rna()
    );
}

#[test]
#[ignore]
fn test_transcribes_all_dna_to_rna() {
    assert_eq!(
        dna::RNA::new("UGCACCAGAAUU").unwrap(),
        dna::DNA::new("ACGTGGTCTTAA").unwrap().to_rna()
    )
}
<commit_msg>rna-transcription: Added checks for the value of Err to the test_invalid_dna_input test<commit_after>extern crate rna_transcription as dna;

#[test]
fn test_valid_dna_input() {
    assert!(dna::DNA::new("GCTA").is_ok());
}

#[test]
#[ignore]
fn test_valid_rna_input() {
    assert!(dna::RNA::new("CGAU").is_ok());
}

#[test]
#[ignore]
fn test_invalid_dna_input() {
    // Invalid character
    assert_eq!(dna::DNA::new("X").err(), Some(0));
    // Valid nucleotide, but invalid in context
    assert_eq!(dna::DNA::new("U").err(), Some(0));
    // Longer string with contained errors
    assert_eq!(dna::DNA::new("ACGTUXXCTTAA").err(), Some(4));
}

#[test]
#[ignore]
fn test_invalid_rna_input() {
    // Invalid character
    assert!(dna::RNA::new("X").is_err());
    // Valid nucleotide, but invalid in context
    assert!(dna::RNA::new("T").is_err());
    // Longer string with contained errors
    assert!(dna::RNA::new("ACGUTTXCUUAA").is_err());
}

#[test]
#[ignore]
fn test_acid_equals_acid() {
    assert_eq!(dna::DNA::new("CGA").unwrap(), dna::DNA::new("CGA").unwrap());
    assert_ne!(dna::DNA::new("CGA").unwrap(), dna::DNA::new("AGC").unwrap());
    assert_eq!(dna::RNA::new("CGA").unwrap(), dna::RNA::new("CGA").unwrap());
    assert_ne!(dna::RNA::new("CGA").unwrap(), dna::RNA::new("AGC").unwrap());
}

#[test]
#[ignore]
fn test_transcribes_cytosine_guanine() {
    assert_eq!(
        dna::RNA::new("G").unwrap(),
        dna::DNA::new("C").unwrap().to_rna()
    );
}

#[test]
#[ignore]
fn test_transcribes_guanine_cytosine() {
    assert_eq!(
        dna::RNA::new("C").unwrap(),
        dna::DNA::new("G").unwrap().to_rna()
    );
}

#[test]
#[ignore]
fn test_transcribes_adenine_uracil() {
    assert_eq!(
        dna::RNA::new("U").unwrap(),
        dna::DNA::new("A").unwrap().to_rna()
    );
}

#[test]
#[ignore]
fn test_transcribes_thymine_to_adenine() {
    assert_eq!(
        dna::RNA::new("A").unwrap(),
        dna::DNA::new("T").unwrap().to_rna()
    );
}

#[test]
#[ignore]
fn test_transcribes_all_dna_to_rna() {
    assert_eq!(
        dna::RNA::new("UGCACCAGAAUU").unwrap(),
        dna::DNA::new("ACGTGGTCTTAA").unwrap().to_rna()
    )
}
<|endoftext|>


<commit_before>extern crate rand;

use std::io::prelude::*;
use std::fs::File;
use std::io::BufWriter;
use std::f32;
use rand::Rng;

// Terminals
#[allow(unused_variables)]
fn expr_x(x:f32, y:f32) -> f32 {
    return x;
}

#[allow(unused_variables)]
fn expr_y(x:f32, y:f32) -> f32 {
    return y;
}

// Single

fn expr_sin(e: f32) -> f32 {
    return f32::sin(f32::consts::PI * e);
}

fn expr_cos(e: f32) -> f32 {
    return f32::cos(f32::consts::PI * e);
}

fn expr_negate(e: f32) -> f32 {
    return -e;
}

fn expr_sqrt(e: f32) -> f32 {
    if e < 0.0 {
        return -f32::sqrt(-e);
    } else {
        return f32::sqrt(e);
    }
}

// Double

fn expr_arith_mean(e1: f32, e2: f32) -> f32 {
    return (e1 + e2) / 2.0;
}

fn expr_geo_mean(e1: f32, e2: f32) -> f32 {
    return expr_sqrt(e1 * e2);
}

fn expr_mult(e1: f32, e2: f32) -> f32 {
    return e1*e2;
}

fn expr_max(e1: f32, e2: f32) -> f32 {
    if e1 > e2 {
        return e1;
    } else {
        return e2;
    }
}

fn expr_min(e1: f32, e2: f32) -> f32 {
    if e1 > e2 {
        return e2;
    } else {
        return e1;
    }
}

type ExprTerminal = fn(f32, f32) -> f32;
type ExprSingle = fn(f32) -> f32;
type ExprDouble = fn(f32, f32) -> f32;

enum Expression {
    Terminal {
        expr: ExprTerminal
    },
    Single {
        expr: ExprSingle,
        e : Box<Expression>
    },
    Double {
        expr: ExprDouble,
        e1 : Box<Expression>,
        e2 : Box<Expression>
    }
}

fn build_expression(depth: i32, rng: &mut rand::ThreadRng) -> Box<Expression> {
    let terminals: [ExprTerminal; 2] = [expr_x, expr_y];
    let singles: [ExprSingle; 4] = [expr_sin, expr_cos, expr_negate, expr_sqrt];
    let doubles: [ExprDouble; 5] = [expr_arith_mean, expr_geo_mean, expr_mult, expr_min, expr_max];
    if depth == 1 {
        let f = terminals[rng.gen_range(0, 2)];
        let e = Box::new(Expression::Terminal { expr: f });
        return e;
    } else {
        let i = rng.gen_range(0, 4 + 5);
        if i < 4 {
            let e1 = build_expression(depth - 1, rng);
            let e = Box::new(Expression::Single { expr: singles[i], e: e1 });
            return e;
        } else {
            let e1 = build_expression(depth - 1, rng);
            let e2 = build_expression(depth - 1, rng);
            let e = Box::new(Expression::Double { expr: doubles[i - 4], e1: e1, e2: e2 });
            return e;
        }
    }
}

fn eval_expression(expression: &Box<Expression>, x: f32, y: f32) -> f32 {
    return match **expression {
        Expression::Terminal { expr }  => expr(x,y),
        Expression::Single {expr, ref e} => expr(eval_expression(e, x, y)),
        Expression::Double {expr, ref e1, ref e2} => expr(eval_expression(e1, x, y), eval_expression(e2, x, y))
    }
}

fn emit_greyscale(scale: i32, expr: Box<Expression>) {
    let size: usize = 2*(scale as usize) + 1;
    let mut output = BufWriter::new(File::create("test.pgm").unwrap());
    // So apparently the size of arrays in rust have to be a compile time
    // constant at the moment. Hardcode the value because whatever.
    write!(output, "P5 {} {} 255\n", size, size).unwrap();
    for xi in -scale .. (scale + 1) {
        for yi in -scale .. (scale + 1) {
            let x = xi as f32 / scale as f32;
            let y = yi as f32 / scale as f32;
            let intensity = (127.5 + 127.5*eval_expression(&expr, x, y)/2.0) as u8;
            let buf: [u8; 1] = [intensity];
            output.write(&buf).unwrap();
        }
    }
}

fn main() {
    let mut rng : rand::ThreadRng = rand::thread_rng();
    let expr = build_expression(10, &mut rng);
    emit_greyscale(150, expr);
}
<commit_msg>Test out depth 15 creation. Runs on the same order as the ada version. A bit slower, but considering I'm pretty sure everything is one level of indirection too much on my evaluation function since I have to take a reference to the box so that I can dereference it twice that's not bad.<commit_after>extern crate rand;

use std::io::prelude::*;
use std::fs::File;
use std::io::BufWriter;
use std::f32;
use rand::Rng;

// Terminals
#[allow(unused_variables)]
fn expr_x(x:f32, y:f32) -> f32 {
    return x;
}

#[allow(unused_variables)]
fn expr_y(x:f32, y:f32) -> f32 {
    return y;
}

// Single

fn expr_sin(e: f32) -> f32 {
    return f32::sin(f32::consts::PI * e);
}

fn expr_cos(e: f32) -> f32 {
    return f32::cos(f32::consts::PI * e);
}

fn expr_negate(e: f32) -> f32 {
    return -e;
}

fn expr_sqrt(e: f32) -> f32 {
    if e < 0.0 {
        return -f32::sqrt(-e);
    } else {
        return f32::sqrt(e);
    }
}

// Double

fn expr_arith_mean(e1: f32, e2: f32) -> f32 {
    return (e1 + e2) / 2.0;
}

fn expr_geo_mean(e1: f32, e2: f32) -> f32 {
    return expr_sqrt(e1 * e2);
}

fn expr_mult(e1: f32, e2: f32) -> f32 {
    return e1*e2;
}

fn expr_max(e1: f32, e2: f32) -> f32 {
    if e1 > e2 {
        return e1;
    } else {
        return e2;
    }
}

fn expr_min(e1: f32, e2: f32) -> f32 {
    if e1 > e2 {
        return e2;
    } else {
        return e1;
    }
}

type ExprTerminal = fn(f32, f32) -> f32;
type ExprSingle = fn(f32) -> f32;
type ExprDouble = fn(f32, f32) -> f32;

enum Expression {
    Terminal {
        expr: ExprTerminal
    },
    Single {
        expr: ExprSingle,
        e : Box<Expression>
    },
    Double {
        expr: ExprDouble,
        e1 : Box<Expression>,
        e2 : Box<Expression>
    }
}

fn build_expression(depth: i32, rng: &mut rand::ThreadRng) -> Box<Expression> {
    let terminals: [ExprTerminal; 2] = [expr_x, expr_y];
    let singles: [ExprSingle; 4] = [expr_sin, expr_cos, expr_negate, expr_sqrt];
    let doubles: [ExprDouble; 5] = [expr_arith_mean, expr_geo_mean, expr_mult, expr_min, expr_max];
    if depth == 1 {
        let f = terminals[rng.gen_range(0, 2)];
        let e = Box::new(Expression::Terminal { expr: f });
        return e;
    } else {
        let i = rng.gen_range(0, 4 + 5);
        if i < 4 {
            let e1 = build_expression(depth - 1, rng);
            let e = Box::new(Expression::Single { expr: singles[i], e: e1 });
            return e;
        } else {
            let e1 = build_expression(depth - 1, rng);
            let e2 = build_expression(depth - 1, rng);
            let e = Box::new(Expression::Double { expr: doubles[i - 4], e1: e1, e2: e2 });
            return e;
        }
    }
}

fn eval_expression(expression: &Box<Expression>, x: f32, y: f32) -> f32 {
    return match **expression {
        Expression::Terminal { expr }  => expr(x,y),
        Expression::Single {expr, ref e} => expr(eval_expression(e, x, y)),
        Expression::Double {expr, ref e1, ref e2} => expr(eval_expression(e1, x, y), eval_expression(e2, x, y))
    }
}

fn emit_greyscale(scale: i32, expr: Box<Expression>) {
    let size: usize = 2*(scale as usize) + 1;
    let mut output = BufWriter::new(File::create("test.pgm").unwrap());
    // So apparently the size of arrays in rust have to be a compile time
    // constant at the moment. Hardcode the value because whatever.
    write!(output, "P5 {} {} 255\n", size, size).unwrap();
    for xi in -scale .. (scale + 1) {
        for yi in -scale .. (scale + 1) {
            let x = xi as f32 / scale as f32;
            let y = yi as f32 / scale as f32;
            let intensity = (127.5 + 127.5*eval_expression(&expr, x, y)/2.0) as u8;
            let buf: [u8; 1] = [intensity];
            output.write(&buf).unwrap();
        }
    }
}

fn main() {
    let mut rng : rand::ThreadRng = rand::thread_rng();
    let expr = build_expression(15, &mut rng);
    emit_greyscale(150, expr);
}
<|endoftext|>


<commit_before>use super::{AppearsInFromClause, Plus, QuerySource};
use crate::backend::Backend;
use crate::backend::DieselReserveSpecialization;
use crate::expression::grouped::Grouped;
use crate::expression::nullable::Nullable;
use crate::expression::SelectableExpression;
use crate::prelude::*;
use crate::query_builder::*;
use crate::query_dsl::InternalJoinDsl;
use crate::result::QueryResult;
use crate::sql_types::BoolOrNullableBool;
use crate::util::TupleAppend;

/// A query source representing the join between two tables
pub struct Join<Left: QuerySource, Right: QuerySource, Kind> {
    left: FromClause<Left>,
    right: FromClause<Right>,
    kind: Kind,
}

impl<Left, Right, Kind> Clone for Join<Left, Right, Kind>
where
    Left: QuerySource,
    FromClause<Left>: Clone,
    Right: QuerySource,
    FromClause<Right>: Clone,
    Kind: Clone,
{
    fn clone(&self) -> Self {
        Self {
            left: self.left.clone(),
            right: self.right.clone(),
            kind: self.kind.clone(),
        }
    }
}

impl<Left, Right, Kind> Copy for Join<Left, Right, Kind>
where
    Left: QuerySource,
    FromClause<Left>: Copy,
    Right: QuerySource,
    FromClause<Right>: Copy,
    Kind: Copy,
{
}

impl<Left, Right, Kind> std::fmt::Debug for Join<Left, Right, Kind>
where
    Left: QuerySource,
    FromClause<Left>: std::fmt::Debug,
    Right: QuerySource,
    FromClause<Right>: std::fmt::Debug,
    Kind: std::fmt::Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Join")
            .field("left", &self.left)
            .field("right", &self.right)
            .field("kind", &self.kind)
            .finish()
    }
}

impl<Left, Right, Kind> QueryId for Join<Left, Right, Kind>
where
    Left: QueryId + QuerySource + 'static,
    Right: QueryId + QuerySource + 'static,
    Kind: QueryId,
{
    type QueryId = Join<Left, Right, Kind::QueryId>;

    const HAS_STATIC_QUERY_ID: bool =
        Left::HAS_STATIC_QUERY_ID && Right::HAS_STATIC_QUERY_ID && Kind::HAS_STATIC_QUERY_ID;
}

#[derive(Debug, Clone, Copy, QueryId)]
#[doc(hidden)]
/// A query source representing the join between two tables with an explicit
/// `ON` given. `Join` should usually be referenced instead, as all "type
/// safety" traits are implemented in terms of `Join` implementing them.
pub struct JoinOn<Join, On> {
    join: Join,
    on: On,
}

impl<Left, Right, Kind> Join<Left, Right, Kind>
where
    Left: QuerySource,
    Right: QuerySource,
{
    pub(crate) fn new(left: Left, right: Right, kind: Kind) -> Self {
        Join {
            left: FromClause::new(left),
            right: FromClause::new(right),
            kind,
        }
    }

    pub(crate) fn on<On>(self, on: On) -> JoinOn<Self, On> {
        JoinOn { join: self, on: on }
    }
}

impl<Left, Right> QuerySource for Join<Left, Right, Inner>
where
    Left: QuerySource + AppendSelection<Right::DefaultSelection>,
    Right: QuerySource,
    Left::Output: SelectableExpression<Self>,
    Self: Clone,
{
    type FromClause = Self;
    type DefaultSelection = Left::Output;

    fn from_clause(&self) -> Self::FromClause {
        self.clone()
    }

    fn default_selection(&self) -> Self::DefaultSelection {
        self.left
            .source
            .append_selection(self.right.source.default_selection())
    }
}

impl<Left, Right> QuerySource for Join<Left, Right, LeftOuter>
where
    Left: QuerySource + AppendSelection<Nullable<Right::DefaultSelection>>,
    Right: QuerySource,
    Left::Output: SelectableExpression<Self>,
    Self: Clone,
{
    type FromClause = Self;
    type DefaultSelection = Left::Output;

    fn from_clause(&self) -> Self::FromClause {
        self.clone()
    }

    fn default_selection(&self) -> Self::DefaultSelection {
        self.left
            .source
            .append_selection(self.right.source.default_selection().nullable())
    }
}

#[derive(Debug, Clone, Copy)]
pub struct OnKeyword;

impl<DB: Backend> nodes::MiddleFragment<DB> for OnKeyword {
    fn push_sql(&self, mut pass: AstPass<'_, '_, DB>) {
        pass.push_sql(" ON ");
    }
}

impl<Join, On> QuerySource for JoinOn<Join, On>
where
    Join: QuerySource,
    On: AppearsOnTable<Join::FromClause> + Clone,
    On::SqlType: BoolOrNullableBool,
    Join::DefaultSelection: SelectableExpression<Self>,
{
    type FromClause = Grouped<nodes::InfixNode<Join::FromClause, On, OnKeyword>>;
    type DefaultSelection = Join::DefaultSelection;

    fn from_clause(&self) -> Self::FromClause {
        Grouped(nodes::InfixNode::new(
            self.join.from_clause(),
            self.on.clone(),
            OnKeyword,
        ))
    }

    fn default_selection(&self) -> Self::DefaultSelection {
        self.join.default_selection()
    }
}

impl<Left, Right, Kind, DB> QueryFragment<DB> for Join<Left, Right, Kind>
where
    DB: Backend + DieselReserveSpecialization,
    Left: QuerySource,
    Left::FromClause: QueryFragment<DB>,
    Right: QuerySource,
    Right::FromClause: QueryFragment<DB>,
    Kind: QueryFragment<DB>,
{
    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        self.left.from_clause.walk_ast(out.reborrow())?;
        self.kind.walk_ast(out.reborrow())?;
        out.push_sql(" JOIN ");
        self.right.from_clause.walk_ast(out.reborrow())?;
        Ok(())
    }
}

/// Indicates that two tables can be joined without an explicit `ON` clause.
///
/// Implementations of this trait are generated by invoking [`joinable!`].
/// Implementing this trait means that you can call
/// `left_table.inner_join(right_table)`, without supplying the `ON` clause
/// explicitly. To join two tables which do not implement this trait, you will
/// need to call [`.on`].
///
/// See [`joinable!`] and [`inner_join`] for usage examples.
///
/// [`joinable!`]: crate::joinable!
/// [`.on`]: crate::query_dsl::JoinOnDsl::on()
/// [`inner_join`]: crate::query_dsl::QueryDsl::inner_join()
pub trait JoinTo<T> {
    #[doc(hidden)]
    type FromClause;
    #[doc(hidden)]
    type OnClause;
    #[doc(hidden)]
    fn join_target(rhs: T) -> (Self::FromClause, Self::OnClause);
}

#[doc(hidden)]
/// Used to ensure the sql type of `left.join(mid).join(right)` is
/// `(Left, Mid, Right)` and not `((Left, Mid), Right)`. This needs
/// to be separate from `TupleAppend` because we still want to keep
/// the column lists (which are tuples) separate.
pub trait AppendSelection<Selection> {
    type Output;

    fn append_selection(&self, selection: Selection) -> Self::Output;
}

impl<T: Table, Selection> AppendSelection<Selection> for T {
    type Output = (T::AllColumns, Selection);

    fn append_selection(&self, selection: Selection) -> Self::Output {
        (T::all_columns(), selection)
    }
}

impl<Left, Mid, Selection, Kind> AppendSelection<Selection> for Join<Left, Mid, Kind>
where
    Left: QuerySource,
    Mid: QuerySource,
    Self: QuerySource,
    <Self as QuerySource>::DefaultSelection: TupleAppend<Selection>,
{
    type Output = <<Self as QuerySource>::DefaultSelection as TupleAppend<Selection>>::Output;

    fn append_selection(&self, selection: Selection) -> Self::Output {
        self.default_selection().tuple_append(selection)
    }
}

impl<Join, On, Selection> AppendSelection<Selection> for JoinOn<Join, On>
where
    Join: AppendSelection<Selection>,
{
    type Output = Join::Output;

    fn append_selection(&self, selection: Selection) -> Self::Output {
        self.join.append_selection(selection)
    }
}

#[doc(hidden)]
#[derive(Debug, Clone, Copy, Default, QueryId)]
pub struct Inner;

impl<DB> QueryFragment<DB> for Inner
where
    DB: Backend + DieselReserveSpecialization,
{
    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        out.push_sql(" INNER");
        Ok(())
    }
}

#[doc(hidden)]
#[derive(Debug, Clone, Copy, Default, QueryId)]
pub struct LeftOuter;

impl<DB> QueryFragment<DB> for LeftOuter
where
    DB: Backend + DieselReserveSpecialization,
{
    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        out.push_sql(" LEFT OUTER");
        Ok(())
    }
}

impl<Left, Mid, Right, Kind> JoinTo<Right> for Join<Left, Mid, Kind>
where
    Left: JoinTo<Right> + QuerySource,
    Mid: QuerySource,
{
    type FromClause = <Left as JoinTo<Right>>::FromClause;
    type OnClause = Left::OnClause;

    fn join_target(rhs: Right) -> (Self::FromClause, Self::OnClause) {
        Left::join_target(rhs)
    }
}

impl<Join, On, Right> JoinTo<Right> for JoinOn<Join, On>
where
    Join: JoinTo<Right>,
{
    type FromClause = Join::FromClause;
    type OnClause = Join::OnClause;

    fn join_target(rhs: Right) -> (Self::FromClause, Self::OnClause) {
        Join::join_target(rhs)
    }
}

impl<T, Left, Right, Kind> AppearsInFromClause<T> for Join<Left, Right, Kind>
where
    Left: AppearsInFromClause<T> + QuerySource,
    Right: AppearsInFromClause<T> + QuerySource,
    Left::Count: Plus<Right::Count>,
{
    type Count = <Left::Count as Plus<Right::Count>>::Output;
}

impl<T, Join, On> AppearsInFromClause<T> for JoinOn<Join, On>
where
    Join: AppearsInFromClause<T>,
{
    type Count = Join::Count;
}

#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub struct OnClauseWrapper<Source, On> {
    pub(crate) source: Source,
    pub(crate) on: On,
}

impl<Source, On> OnClauseWrapper<Source, On> {
    pub fn new(source: Source, on: On) -> Self {
        OnClauseWrapper { source, on }
    }
}

impl<Lhs, Rhs, On> JoinTo<OnClauseWrapper<Rhs, On>> for Lhs
where
    Lhs: Table,
{
    type FromClause = Rhs;
    type OnClause = On;

    fn join_target(rhs: OnClauseWrapper<Rhs, On>) -> (Self::FromClause, Self::OnClause) {
        (rhs.source, rhs.on)
    }
}

impl<Lhs, Rhs, On> JoinTo<Rhs> for OnClauseWrapper<Lhs, On>
where
    Lhs: JoinTo<Rhs>,
{
    type FromClause = <Lhs as JoinTo<Rhs>>::FromClause;
    type OnClause = <Lhs as JoinTo<Rhs>>::OnClause;

    fn join_target(rhs: Rhs) -> (Self::FromClause, Self::OnClause) {
        <Lhs as JoinTo<Rhs>>::join_target(rhs)
    }
}

impl<Rhs, Kind, On1, On2, Lhs> InternalJoinDsl<Rhs, Kind, On1> for OnClauseWrapper<Lhs, On2>
where
    Lhs: InternalJoinDsl<Rhs, Kind, On1>,
{
    type Output = OnClauseWrapper<<Lhs as InternalJoinDsl<Rhs, Kind, On1>>::Output, On2>;

    fn join(self, rhs: Rhs, kind: Kind, on: On1) -> Self::Output {
        OnClauseWrapper {
            source: self.source.join(rhs, kind, on),
            on: self.on,
        }
    }
}

impl<Qs, On> QueryDsl for OnClauseWrapper<Qs, On> {}

#[doc(hidden)]
/// Convert any joins in a `FROM` clause into an inner join.
///
/// This trait is used to determine whether
/// `Nullable<T>: SelectableExpression<SomeJoin>`. We consider it to be
/// selectable if `T: SelectableExpression<InnerJoin>`. Since `SomeJoin`
/// may be deeply nested, we need to recursively change any appearances of
/// `LeftOuter` to `Inner` in order to perform this check.
pub trait ToInnerJoin {
    type InnerJoin;
}

impl<Left, Right, Kind> ToInnerJoin for Join<Left, Right, Kind>
where
    Left: ToInnerJoin + QuerySource,
    Left::InnerJoin: QuerySource,
    Right: ToInnerJoin + QuerySource,
    Right::InnerJoin: QuerySource,
{
    type InnerJoin = Join<Left::InnerJoin, Right::InnerJoin, Inner>;
}

impl<Join, On> ToInnerJoin for JoinOn<Join, On>
where
    Join: ToInnerJoin,
{
    type InnerJoin = JoinOn<Join::InnerJoin, On>;
}

impl<From> ToInnerJoin for SelectStatement<FromClause<From>>
where
    From: ToInnerJoin + QuerySource,
    From::InnerJoin: QuerySource,
{
    type InnerJoin = SelectStatement<FromClause<From::InnerJoin>>;
}

impl<T: Table> ToInnerJoin for T {
    type InnerJoin = T;
}
<commit_msg>Prototype skipping the `SelectableExpression` check for the `DefaultSelection` type of joins<commit_after>use super::{AppearsInFromClause, Plus, QuerySource};
use crate::backend::Backend;
use crate::backend::DieselReserveSpecialization;
use crate::expression::grouped::Grouped;
use crate::expression::nullable::Nullable;
use crate::expression::SelectableExpression;
use crate::expression::ValidGrouping;
use crate::prelude::*;
use crate::query_builder::*;
use crate::query_dsl::InternalJoinDsl;
use crate::result::QueryResult;
use crate::sql_types::BoolOrNullableBool;
use crate::util::TupleAppend;

/// A query source representing the join between two tables
pub struct Join<Left: QuerySource, Right: QuerySource, Kind> {
    left: FromClause<Left>,
    right: FromClause<Right>,
    kind: Kind,
}

impl<Left, Right, Kind> Clone for Join<Left, Right, Kind>
where
    Left: QuerySource,
    FromClause<Left>: Clone,
    Right: QuerySource,
    FromClause<Right>: Clone,
    Kind: Clone,
{
    fn clone(&self) -> Self {
        Self {
            left: self.left.clone(),
            right: self.right.clone(),
            kind: self.kind.clone(),
        }
    }
}

impl<Left, Right, Kind> Copy for Join<Left, Right, Kind>
where
    Left: QuerySource,
    FromClause<Left>: Copy,
    Right: QuerySource,
    FromClause<Right>: Copy,
    Kind: Copy,
{
}

impl<Left, Right, Kind> std::fmt::Debug for Join<Left, Right, Kind>
where
    Left: QuerySource,
    FromClause<Left>: std::fmt::Debug,
    Right: QuerySource,
    FromClause<Right>: std::fmt::Debug,
    Kind: std::fmt::Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Join")
            .field("left", &self.left)
            .field("right", &self.right)
            .field("kind", &self.kind)
            .finish()
    }
}

impl<Left, Right, Kind> QueryId for Join<Left, Right, Kind>
where
    Left: QueryId + QuerySource + 'static,
    Right: QueryId + QuerySource + 'static,
    Kind: QueryId,
{
    type QueryId = Join<Left, Right, Kind::QueryId>;

    const HAS_STATIC_QUERY_ID: bool =
        Left::HAS_STATIC_QUERY_ID && Right::HAS_STATIC_QUERY_ID && Kind::HAS_STATIC_QUERY_ID;
}

#[derive(Debug, Clone, Copy, QueryId)]
#[doc(hidden)]
/// A query source representing the join between two tables with an explicit
/// `ON` given. `Join` should usually be referenced instead, as all "type
/// safety" traits are implemented in terms of `Join` implementing them.
pub struct JoinOn<Join, On> {
    join: Join,
    on: On,
}

impl<Left, Right, Kind> Join<Left, Right, Kind>
where
    Left: QuerySource,
    Right: QuerySource,
{
    pub(crate) fn new(left: Left, right: Right, kind: Kind) -> Self {
        Join {
            left: FromClause::new(left),
            right: FromClause::new(right),
            kind,
        }
    }

    pub(crate) fn on<On>(self, on: On) -> JoinOn<Self, On> {
        JoinOn { join: self, on: on }
    }
}

// TODO: figure out where to put this thing
// and make really sure that it cannot leak into the
// public api at all
#[derive(Debug, QueryId, Copy, Clone)]
pub struct SkipSelectableExpressionWrapper<T>(T);

impl<DB, T> QueryFragment<DB> for SkipSelectableExpressionWrapper<T>
where
    T: QueryFragment<DB>,
    DB: Backend,
{
    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        self.0.walk_ast(pass)
    }
}

impl<GB, T> ValidGrouping<GB> for SkipSelectableExpressionWrapper<T>
where
    T: ValidGrouping<GB>,
{
    type IsAggregate = T::IsAggregate;
}

impl<QS, T> SelectClauseExpression<QS> for SkipSelectableExpressionWrapper<T>
where
    T: SelectClauseExpression<QS>,
{
    type Selection = T::Selection;

    type SelectClauseSqlType = T::SelectClauseSqlType;
}

impl<QS, T> SelectableExpression<QS> for SkipSelectableExpressionWrapper<T> where
    Self: AppearsOnTable<QS>
{
}
impl<QS, T> AppearsOnTable<QS> for SkipSelectableExpressionWrapper<T> where Self: Expression {}
impl<T> Expression for SkipSelectableExpressionWrapper<T>
where
    T: Expression,
{
    type SqlType = T::SqlType;
}

impl<Left, Right> QuerySource for Join<Left, Right, Inner>
where
    Left: QuerySource + AppendSelection<Right::DefaultSelection>,
    Right: QuerySource,
    Left::Output: Expression,
    Self: Clone,
{
    type FromClause = Self;
    // combining two valid selectable expressions for both tables will always yield a
    // valid selectable expressions for the whole join, so no need to check that here
    // again. These checked turned out to be quite expensive in terms of compile time
    // so we use a wrapper type to just skip the check and forward other more relevant
    // trait implementations to the inner type
    type DefaultSelection = SkipSelectableExpressionWrapper<Left::Output>;

    fn from_clause(&self) -> Self::FromClause {
        self.clone()
    }

    fn default_selection(&self) -> Self::DefaultSelection {
        SkipSelectableExpressionWrapper(
            self.left
                .source
                .append_selection(self.right.source.default_selection()),
        )
    }
}

impl<Left, Right> QuerySource for Join<Left, Right, LeftOuter>
where
    Left: QuerySource + AppendSelection<Nullable<Right::DefaultSelection>>,
    Right: QuerySource,
    Left::Output: SelectableExpression<Self>,
    Self: Clone,
{
    type FromClause = Self;
    // TODO: we want to do the same as for the Inner join impl here
    type DefaultSelection = Left::Output;

    fn from_clause(&self) -> Self::FromClause {
        self.clone()
    }

    fn default_selection(&self) -> Self::DefaultSelection {
        self.left
            .source
            .append_selection(self.right.source.default_selection().nullable())
    }
}

#[derive(Debug, Clone, Copy)]
pub struct OnKeyword;

impl<DB: Backend> nodes::MiddleFragment<DB> for OnKeyword {
    fn push_sql(&self, mut pass: AstPass<'_, '_, DB>) {
        pass.push_sql(" ON ");
    }
}

impl<Join, On> QuerySource for JoinOn<Join, On>
where
    Join: QuerySource,
    On: AppearsOnTable<Join::FromClause> + Clone,
    On::SqlType: BoolOrNullableBool,
    Join::DefaultSelection: SelectableExpression<Self>,
{
    type FromClause = Grouped<nodes::InfixNode<Join::FromClause, On, OnKeyword>>;
    type DefaultSelection = Join::DefaultSelection;

    fn from_clause(&self) -> Self::FromClause {
        Grouped(nodes::InfixNode::new(
            self.join.from_clause(),
            self.on.clone(),
            OnKeyword,
        ))
    }

    fn default_selection(&self) -> Self::DefaultSelection {
        self.join.default_selection()
    }
}

impl<Left, Right, Kind, DB> QueryFragment<DB> for Join<Left, Right, Kind>
where
    DB: Backend + DieselReserveSpecialization,
    Left: QuerySource,
    Left::FromClause: QueryFragment<DB>,
    Right: QuerySource,
    Right::FromClause: QueryFragment<DB>,
    Kind: QueryFragment<DB>,
{
    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        self.left.from_clause.walk_ast(out.reborrow())?;
        self.kind.walk_ast(out.reborrow())?;
        out.push_sql(" JOIN ");
        self.right.from_clause.walk_ast(out.reborrow())?;
        Ok(())
    }
}

/// Indicates that two tables can be joined without an explicit `ON` clause.
///
/// Implementations of this trait are generated by invoking [`joinable!`].
/// Implementing this trait means that you can call
/// `left_table.inner_join(right_table)`, without supplying the `ON` clause
/// explicitly. To join two tables which do not implement this trait, you will
/// need to call [`.on`].
///
/// See [`joinable!`] and [`inner_join`] for usage examples.
///
/// [`joinable!`]: crate::joinable!
/// [`.on`]: crate::query_dsl::JoinOnDsl::on()
/// [`inner_join`]: crate::query_dsl::QueryDsl::inner_join()
pub trait JoinTo<T> {
    #[doc(hidden)]
    type FromClause;
    #[doc(hidden)]
    type OnClause;
    #[doc(hidden)]
    fn join_target(rhs: T) -> (Self::FromClause, Self::OnClause);
}

#[doc(hidden)]
/// Used to ensure the sql type of `left.join(mid).join(right)` is
/// `(Left, Mid, Right)` and not `((Left, Mid), Right)`. This needs
/// to be separate from `TupleAppend` because we still want to keep
/// the column lists (which are tuples) separate.
pub trait AppendSelection<Selection> {
    type Output;

    fn append_selection(&self, selection: Selection) -> Self::Output;
}

impl<T: Table, Selection> AppendSelection<Selection> for T {
    type Output = (T::AllColumns, Selection);

    fn append_selection(&self, selection: Selection) -> Self::Output {
        (T::all_columns(), selection)
    }
}

impl<Left, Mid, Selection, Kind> AppendSelection<Selection> for Join<Left, Mid, Kind>
where
    Left: QuerySource,
    Mid: QuerySource,
    Self: QuerySource,
    <Self as QuerySource>::DefaultSelection: TupleAppend<Selection>,
{
    type Output = <<Self as QuerySource>::DefaultSelection as TupleAppend<Selection>>::Output;

    fn append_selection(&self, selection: Selection) -> Self::Output {
        self.default_selection().tuple_append(selection)
    }
}

impl<Join, On, Selection> AppendSelection<Selection> for JoinOn<Join, On>
where
    Join: AppendSelection<Selection>,
{
    type Output = Join::Output;

    fn append_selection(&self, selection: Selection) -> Self::Output {
        self.join.append_selection(selection)
    }
}

#[doc(hidden)]
#[derive(Debug, Clone, Copy, Default, QueryId)]
pub struct Inner;

impl<DB> QueryFragment<DB> for Inner
where
    DB: Backend + DieselReserveSpecialization,
{
    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        out.push_sql(" INNER");
        Ok(())
    }
}

#[doc(hidden)]
#[derive(Debug, Clone, Copy, Default, QueryId)]
pub struct LeftOuter;

impl<DB> QueryFragment<DB> for LeftOuter
where
    DB: Backend + DieselReserveSpecialization,
{
    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        out.push_sql(" LEFT OUTER");
        Ok(())
    }
}

impl<Left, Mid, Right, Kind> JoinTo<Right> for Join<Left, Mid, Kind>
where
    Left: JoinTo<Right> + QuerySource,
    Mid: QuerySource,
{
    type FromClause = <Left as JoinTo<Right>>::FromClause;
    type OnClause = Left::OnClause;

    fn join_target(rhs: Right) -> (Self::FromClause, Self::OnClause) {
        Left::join_target(rhs)
    }
}

impl<Join, On, Right> JoinTo<Right> for JoinOn<Join, On>
where
    Join: JoinTo<Right>,
{
    type FromClause = Join::FromClause;
    type OnClause = Join::OnClause;

    fn join_target(rhs: Right) -> (Self::FromClause, Self::OnClause) {
        Join::join_target(rhs)
    }
}

impl<T, Left, Right, Kind> AppearsInFromClause<T> for Join<Left, Right, Kind>
where
    Left: AppearsInFromClause<T> + QuerySource,
    Right: AppearsInFromClause<T> + QuerySource,
    Left::Count: Plus<Right::Count>,
{
    type Count = <Left::Count as Plus<Right::Count>>::Output;
}

impl<T, Join, On> AppearsInFromClause<T> for JoinOn<Join, On>
where
    Join: AppearsInFromClause<T>,
{
    type Count = Join::Count;
}

#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub struct OnClauseWrapper<Source, On> {
    pub(crate) source: Source,
    pub(crate) on: On,
}

impl<Source, On> OnClauseWrapper<Source, On> {
    pub fn new(source: Source, on: On) -> Self {
        OnClauseWrapper { source, on }
    }
}

impl<Lhs, Rhs, On> JoinTo<OnClauseWrapper<Rhs, On>> for Lhs
where
    Lhs: Table,
{
    type FromClause = Rhs;
    type OnClause = On;

    fn join_target(rhs: OnClauseWrapper<Rhs, On>) -> (Self::FromClause, Self::OnClause) {
        (rhs.source, rhs.on)
    }
}

impl<Lhs, Rhs, On> JoinTo<Rhs> for OnClauseWrapper<Lhs, On>
where
    Lhs: JoinTo<Rhs>,
{
    type FromClause = <Lhs as JoinTo<Rhs>>::FromClause;
    type OnClause = <Lhs as JoinTo<Rhs>>::OnClause;

    fn join_target(rhs: Rhs) -> (Self::FromClause, Self::OnClause) {
        <Lhs as JoinTo<Rhs>>::join_target(rhs)
    }
}

impl<Rhs, Kind, On1, On2, Lhs> InternalJoinDsl<Rhs, Kind, On1> for OnClauseWrapper<Lhs, On2>
where
    Lhs: InternalJoinDsl<Rhs, Kind, On1>,
{
    type Output = OnClauseWrapper<<Lhs as InternalJoinDsl<Rhs, Kind, On1>>::Output, On2>;

    fn join(self, rhs: Rhs, kind: Kind, on: On1) -> Self::Output {
        OnClauseWrapper {
            source: self.source.join(rhs, kind, on),
            on: self.on,
        }
    }
}

impl<Qs, On> QueryDsl for OnClauseWrapper<Qs, On> {}

#[doc(hidden)]
/// Convert any joins in a `FROM` clause into an inner join.
///
/// This trait is used to determine whether
/// `Nullable<T>: SelectableExpression<SomeJoin>`. We consider it to be
/// selectable if `T: SelectableExpression<InnerJoin>`. Since `SomeJoin`
/// may be deeply nested, we need to recursively change any appearances of
/// `LeftOuter` to `Inner` in order to perform this check.
pub trait ToInnerJoin {
    type InnerJoin;
}

impl<Left, Right, Kind> ToInnerJoin for Join<Left, Right, Kind>
where
    Left: ToInnerJoin + QuerySource,
    Left::InnerJoin: QuerySource,
    Right: ToInnerJoin + QuerySource,
    Right::InnerJoin: QuerySource,
{
    type InnerJoin = Join<Left::InnerJoin, Right::InnerJoin, Inner>;
}

impl<Join, On> ToInnerJoin for JoinOn<Join, On>
where
    Join: ToInnerJoin,
{
    type InnerJoin = JoinOn<Join::InnerJoin, On>;
}

impl<From> ToInnerJoin for SelectStatement<FromClause<From>>
where
    From: ToInnerJoin + QuerySource,
    From::InnerJoin: QuerySource,
{
    type InnerJoin = SelectStatement<FromClause<From::InnerJoin>>;
}

impl<T: Table> ToInnerJoin for T {
    type InnerJoin = T;
}
<|endoftext|>