<commit_before>//! Handles the IPC (Inter-process Communication) protocol used by the renderer client and server.
//!
//! This is the common "language" between client/server. It defines the protocol for connection and
//! for sending messages back and forth.

mod async_ipc_receiver;
mod messages;
mod protocol;

pub use messages::*;
pub use protocol::*;

use std::io;
use std::future::Future;

use thiserror::Error;
use serde::{Serialize, Deserialize};
use tokio::sync::Mutex;
use ipc_channel::ipc::{self, IpcOneShotServer, IpcSender, IpcError};

use crate::renderer_client::ClientId;

use async_ipc_receiver::AsyncIpcReceiver;

#[derive(Debug, Error)]
#[error(transparent)]
pub enum ConnectionError {
    IpcChannelError(#[from] ipc_channel::Error),
    IOError(#[from] io::Error),
    JoinError(#[from] tokio::task::JoinError),
}

/// Represents either a sender from the connection handshake or a response
#[derive(Debug, Serialize, Deserialize)]
enum HandshakeResponse {
    /// Represents that the handshake has been completed successfully.
    ///
    /// Provides the sender that the client should use to send further requests to the server. This
    /// message is only ever sent **once** for each client at the beginning when the connection is
    /// first established.
    HandshakeFinish(IpcSender<(ClientId, ClientRequest)>),

    /// A response from the server sent in response to a request
    Response(ClientId, ServerResponse),
}

/// Represents the client side of the IPC connection
#[derive(Debug)]
pub struct ClientConnection {
    sender: Mutex<IpcSender<(ClientId, ClientRequest)>>,
    receiver: AsyncIpcReceiver<HandshakeResponse>,
}

impl ClientConnection {
    pub async fn new<S, F>(send_ipc_oneshot_name: S) -> Result<Self, ConnectionError>
        where S: FnOnce(String) -> F,
              F: Future<Output=io::Result<()>>,
    {
        // Send the oneshot token to the server which will then respond with its own oneshot token
        let (server, server_name) = IpcOneShotServer::new()?;
        send_ipc_oneshot_name(server_name).await?;

        let (receiver, response): (_, HandshakeResponse) = tokio::task::spawn_blocking(|| {
            server.accept()
        }).await??;

        let sender = match response {
            HandshakeResponse::HandshakeFinish(sender) => sender,
            _ => unreachable!("bug: server did not send back Sender at the end of handshake"),
        };

        let sender = Mutex::new(sender);
        let receiver = AsyncIpcReceiver::new(receiver);

        Ok(Self {sender, receiver})
    }

    /// Sends a request to the server via IPC
    pub async fn send(&self, id: ClientId, req: ClientRequest) -> Result<(), ipc_channel::Error> {
        self.sender.lock().await.send((id, req))
    }

    /// Waits for a response from the server via IPC
    pub async fn recv(&self) -> Result<(ClientId, ServerResponse), IpcError> {
        let response = self.receiver.recv().await?;
        match response {
            HandshakeResponse::Response(id, response) => Ok((id, response)),
            _ => unreachable!("bug: server did not send response after request"),
        }
    }
}

/// Represents the server side of the IPC connection
#[derive(Debug)]
pub struct ServerConnection {
    sender: Mutex<IpcSender<HandshakeResponse>>,
    receiver: AsyncIpcReceiver<(ClientId, ClientRequest)>,
}

impl ServerConnection {
    /// Establishes a connection to the client by reading from stdin
    #[cfg(all(not(any(feature = "test", test)), target_os = "macos"))]
    pub async fn connect_stdin() -> Result<Self, ConnectionError> {
        use tokio::io::{self, AsyncBufReadExt};

        let stdin = io::stdin();
        let mut reader = io::BufReader::new(stdin);

        let mut oneshot_name = String::new();
        reader.read_line(&mut oneshot_name).await?;
        if oneshot_name.is_empty() {
            panic!("bug: unexpected EOF when reading oneshot server name");
        }

        // Remove the trailing newline
        assert_eq!(oneshot_name.pop(), Some('\n'));
        let conn = ServerConnection::connect(oneshot_name)?;

        Ok(conn)
    }

    /// Establishes a connection with the IPC channel oneshot server with the given name
    pub fn connect(oneshot_name: String) -> Result<Self, ConnectionError> {
        let (server_sender, receiver) = ipc::channel()?;
        let sender = IpcSender::connect(oneshot_name)?;

        // Finish handshake by giving client a sender it can use to send messages to the server
        sender.send(HandshakeResponse::HandshakeFinish(server_sender))?;

        let sender = Mutex::new(sender);
        let receiver = AsyncIpcReceiver::new(receiver);

        Ok(Self {sender, receiver})
    }

    /// Returns the next request, waiting until one is available
    pub async fn recv(&self) -> Result<(ClientId, ClientRequest), IpcError> {
        self.receiver.recv().await
    }

    /// Sends a response to the client
    ///
    /// This should only ever be done in response to a request
    pub async fn send(&self, id: ClientId, res: ServerResponse) -> Result<(), ipc_channel::Error> {
        self.sender.lock().await
            .send(HandshakeResponse::Response(id, res))
    }
}
<commit_msg>Changing if+panic into assertion<commit_after>//! Handles the IPC (Inter-process Communication) protocol used by the renderer client and server.
//!
//! This is the common "language" between client/server. It defines the protocol for connection and
//! for sending messages back and forth.

mod async_ipc_receiver;
mod messages;
mod protocol;

pub use messages::*;
pub use protocol::*;

use std::io;
use std::future::Future;

use thiserror::Error;
use serde::{Serialize, Deserialize};
use tokio::sync::Mutex;
use ipc_channel::ipc::{self, IpcOneShotServer, IpcSender, IpcError};

use crate::renderer_client::ClientId;

use async_ipc_receiver::AsyncIpcReceiver;

#[derive(Debug, Error)]
#[error(transparent)]
pub enum ConnectionError {
    IpcChannelError(#[from] ipc_channel::Error),
    IOError(#[from] io::Error),
    JoinError(#[from] tokio::task::JoinError),
}

/// Represents either a sender from the connection handshake or a response
#[derive(Debug, Serialize, Deserialize)]
enum HandshakeResponse {
    /// Represents that the handshake has been completed successfully.
    ///
    /// Provides the sender that the client should use to send further requests to the server. This
    /// message is only ever sent **once** for each client at the beginning when the connection is
    /// first established.
    HandshakeFinish(IpcSender<(ClientId, ClientRequest)>),

    /// A response from the server sent in response to a request
    Response(ClientId, ServerResponse),
}

/// Represents the client side of the IPC connection
#[derive(Debug)]
pub struct ClientConnection {
    sender: Mutex<IpcSender<(ClientId, ClientRequest)>>,
    receiver: AsyncIpcReceiver<HandshakeResponse>,
}

impl ClientConnection {
    pub async fn new<S, F>(send_ipc_oneshot_name: S) -> Result<Self, ConnectionError>
        where S: FnOnce(String) -> F,
              F: Future<Output=io::Result<()>>,
    {
        // Send the oneshot token to the server which will then respond with its own oneshot token
        let (server, server_name) = IpcOneShotServer::new()?;
        send_ipc_oneshot_name(server_name).await?;

        let (receiver, response): (_, HandshakeResponse) = tokio::task::spawn_blocking(|| {
            server.accept()
        }).await??;

        let sender = match response {
            HandshakeResponse::HandshakeFinish(sender) => sender,
            _ => unreachable!("bug: server did not send back Sender at the end of handshake"),
        };

        let sender = Mutex::new(sender);
        let receiver = AsyncIpcReceiver::new(receiver);

        Ok(Self {sender, receiver})
    }

    /// Sends a request to the server via IPC
    pub async fn send(&self, id: ClientId, req: ClientRequest) -> Result<(), ipc_channel::Error> {
        self.sender.lock().await.send((id, req))
    }

    /// Waits for a response from the server via IPC
    pub async fn recv(&self) -> Result<(ClientId, ServerResponse), IpcError> {
        let response = self.receiver.recv().await?;
        match response {
            HandshakeResponse::Response(id, response) => Ok((id, response)),
            _ => unreachable!("bug: server did not send response after request"),
        }
    }
}

/// Represents the server side of the IPC connection
#[derive(Debug)]
pub struct ServerConnection {
    sender: Mutex<IpcSender<HandshakeResponse>>,
    receiver: AsyncIpcReceiver<(ClientId, ClientRequest)>,
}

impl ServerConnection {
    /// Establishes a connection to the client by reading from stdin
    #[cfg(all(not(any(feature = "test", test)), target_os = "macos"))]
    pub async fn connect_stdin() -> Result<Self, ConnectionError> {
        use tokio::io::{self, AsyncBufReadExt};

        let stdin = io::stdin();
        let mut reader = io::BufReader::new(stdin);

        let mut oneshot_name = String::new();
        reader.read_line(&mut oneshot_name).await?;
        assert!(!oneshot_name.is_empty(), "bug: unexpected EOF when reading oneshot server name");

        // Remove the trailing newline
        assert_eq!(oneshot_name.pop(), Some('\n'));
        let conn = ServerConnection::connect(oneshot_name)?;

        Ok(conn)
    }

    /// Establishes a connection with the IPC channel oneshot server with the given name
    pub fn connect(oneshot_name: String) -> Result<Self, ConnectionError> {
        let (server_sender, receiver) = ipc::channel()?;
        let sender = IpcSender::connect(oneshot_name)?;

        // Finish handshake by giving client a sender it can use to send messages to the server
        sender.send(HandshakeResponse::HandshakeFinish(server_sender))?;

        let sender = Mutex::new(sender);
        let receiver = AsyncIpcReceiver::new(receiver);

        Ok(Self {sender, receiver})
    }

    /// Returns the next request, waiting until one is available
    pub async fn recv(&self) -> Result<(ClientId, ClientRequest), IpcError> {
        self.receiver.recv().await
    }

    /// Sends a response to the client
    ///
    /// This should only ever be done in response to a request
    pub async fn send(&self, id: ClientId, res: ServerResponse) -> Result<(), ipc_channel::Error> {
        self.sender.lock().await
            .send(HandshakeResponse::Response(id, res))
    }
}
<|endoftext|>


<commit_before>extern crate serialize;

use std::io::{File, Open, Append, Read, ReadWrite};
use std::io::{BufferedReader, BufferedWriter};
use std::path::BytesContainer;
use self::serialize::base64::{STANDARD, FromBase64, ToBase64};

pub type ReaderResult<T, E> = Result<T, E>;

pub struct Reader {
    path: Path,

    read_buffer: BufferedReader<File>,

    write_buffer: BufferedWriter<File>,
}

pub trait ReaderFile {

    fn create(&self) -> Box<File>;

    fn open(&self) -> Box<File>;

    fn insert_string(&mut self, String);

    fn encode_record(&self, String) -> String;

    fn decode_record(&self, String) -> String; //TODO Maybe change this to JSON later?
}

impl Reader {
    pub fn new(apath: Path) -> Reader {
        Reader {
            path: apath.clone(),
            read_buffer: {
                match File::open_mode(&apath.clone(), Open, Read) {
                    Ok(file)    => { BufferedReader::new(file) },
                    Err(..)     => { panic!("Failed to create a read buffer to file path."); }
                }
            },
            write_buffer: {
                match File::open_mode(&apath.clone(), Append, ReadWrite) {
                    Ok(file)    => { BufferedWriter::new(file) },
                    Err(..)     => { panic!("Failed to create a write buffer to file path."); }
                }
            }
        }
    }

    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for line_iter in self.read_buffer.lines() {
        //    println!("{}", line_iter.unwrap());
        //    let line = String::from_str(file.read_line().ok().expect("Nothing to read.").trim());
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    fn insert_str(&mut self, item: &str) {
        //self.insert(item.as_bytes());
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
    }

    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
    }

}

impl ReaderFile for Reader {

    fn create(&self) -> Box<File> {
        match File::create(&self.path) {
            Ok(file)    => box file,
            Err(..)     => { panic!("Unable to create file at {}", &self.path.display()); },
        }
    }

    fn open(&self) -> Box<File> {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => box file,
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(item.as_slice());
    }

    fn encode_record(&self, item: String) -> String {
        item.container_as_bytes().to_base64(STANDARD)
    }

    fn decode_record(&self, item: String) -> String {
        match item.as_slice().from_base64() {
            Ok(vec) => {
                match String::from_utf8(vec) {
                    Ok(e)       => e,
                    Err(..)  => panic!("Invalid UTF-8 sequence."),
                }
            }
            Err(..) => panic!("Corrupt data, unable to decode."),
        }
    }
}

#[test]
fn test_open_file() {
    let reader = Reader::new(Path::new("tests/base-test.txt"));
}

//#[test]
fn test_create_file() {
    use std::io::fs::PathExtensions;
    let reader = Reader::new(Path::new("tests/base-test-created.txt"));
    reader.create();
    let path = Path::new("tests/base-test-created.txt");
    assert!(path.is_file());
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_encode_string() {
    let reader = setup();
    let expected = "dGhpcyBpcyBhIGxpbmU=";
    let result = reader.encode_record("this is a line".to_string());
    assert_eq![expected, result];
}

#[test]
fn test_decode_string() {
    let reader = setup();
    let expected = "this is a line";
    let result = reader.decode_record("dGhpcyBpcyBhIGxpbmU=".to_string());
    assert_eq![expected, result];
}

#[allow(dead_code, unused_must_use)]
fn setup() -> Reader {
    let mut file = File::create(&Path::new("tests/base-test.txt")).ok().expect("fooo");
    file.write_str("10 11\n20 21\n");
    Reader::new(Path::new("tests/base-test.txt"))
}
<commit_msg>Removed create() added check and create in new()<commit_after>extern crate serialize;

use std::io::{File, Open, Append, Read, ReadWrite};
use std::io::fs::PathExtensions;
use std::io::{BufferedReader, BufferedWriter};
use std::path::BytesContainer;
use self::serialize::base64::{STANDARD, FromBase64, ToBase64};

pub type ReaderResult<T, E> = Result<T, E>;

pub struct Reader {

    path: Path,

    read_buffer: BufferedReader<File>,

    write_buffer: BufferedWriter<File>,

}

pub trait ReaderFile {

    fn open(&self) -> Box<File>;

    fn insert_string(&mut self, String);

    fn encode_record(&self, String) -> String;

    fn decode_record(&self, String) -> String; //TODO Maybe change this to JSON later?

}

impl Reader {

    pub fn new(apath: Path) -> Reader {
        Reader {
            path: {
                if !apath.exists() { File::create(&apath.clone()); }
                apath.clone()
            },
            read_buffer: {
                match File::open_mode(&apath.clone(), Open, Read) {
                    Ok(file)    => { BufferedReader::new(file) },
                    Err(..)     => { panic!("Failed to create a read buffer to file path."); }
                }
            },
            write_buffer: {
                match File::open_mode(&apath.clone(), Append, ReadWrite) {
                    Ok(file)    => { BufferedWriter::new(file) },
                    Err(..)     => { panic!("Failed to create a write buffer to file path."); }
                }
            }
        }
    }

    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for line_iter in self.read_buffer.lines() {
        //    println!("{}", line_iter.unwrap());
        //    let line = String::from_str(file.read_line().ok().expect("Nothing to read.").trim());
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    fn insert_str(&mut self, item: &str) {
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
    }

    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
    }

}

impl ReaderFile for Reader {

    fn open(&self) -> Box<File> {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => box file,
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(item.as_slice());
    }

    fn encode_record(&self, item: String) -> String {
        item.container_as_bytes().to_base64(STANDARD)
    }

    fn decode_record(&self, item: String) -> String {
        match item.as_slice().from_base64() {
            Ok(vec) => {
                match String::from_utf8(vec) {
                    Ok(e)       => e,
                    Err(..)  => panic!("Invalid UTF-8 sequence."),
                }
            }
            Err(..) => panic!("Corrupt data, unable to decode."),
        }
    }

}

#[test]
fn test_open_file() {
    let reader = Reader::new(Path::new("tests/base-test.txt"));
}

#[test]
fn test_create_file() {
    use std::io::fs;
    use std::io::fs::PathExtensions;
    let path = Path::new("tests/base-test-created.txt");
    assert!(!path.exists());
    let reader = Reader::new(path.clone());
    assert!(path.exists());
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_encode_string() {
    let reader = setup();
    let expected = "dGhpcyBpcyBhIGxpbmU=";
    let result = reader.encode_record("this is a line".to_string());
    assert_eq![expected, result];
}

#[test]
fn test_decode_string() {
    let reader = setup();
    let expected = "this is a line";
    let result = reader.decode_record("dGhpcyBpcyBhIGxpbmU=".to_string());
    assert_eq![expected, result];
}

#[allow(dead_code, unused_must_use)]
fn setup() -> Reader {
    use std::io::fs;

    let mut file = File::create(&Path::new("tests/base-test.txt")).ok().expect("fooo");
    file.write_str("10 11\n20 21\n");

    let p = Path::new("tests/base-test-created.txt");
    if p.exists() {
        fs::unlink(&p);
    }

    Reader::new(Path::new("tests/base-test.txt"))
}
<|endoftext|>


<commit_before>#![allow(unused)]

macro_rules! log {
    (target: $target:expr, $lvl:expr, $($arg:tt)+) => {
        let _ = $target;
        let _ = log!($lvl, $($arg)+);
    };
    ($lvl:expr, $($arg:tt)+) => {{
        let _ = $lvl;
        let _ = format_args!($($arg)+);
    }};
}
macro_rules! error {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
macro_rules! warn {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
macro_rules! info {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
macro_rules! debug {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
macro_rules! trace {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
<commit_msg>Remove trailing semis<commit_after>#![allow(unused)]

macro_rules! log {
    (target: $target:expr, $lvl:expr, $($arg:tt)+) => {
        let _ = $target;
        let _ = log!($lvl, $($arg)+);
    }
    ($lvl:expr, $($arg:tt)+) => {
        let _ = $lvl;
        let _ = format_args!($($arg)+);
    }
}
macro_rules! error {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); }
    ($($arg:tt)*) => { log!("", $($arg)*); }
}
macro_rules! warn {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); }
    ($($arg:tt)*) => { log!("", $($arg)*); }
}
macro_rules! info {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); }
    ($($arg:tt)*) => { log!("", $($arg)*); }
}
macro_rules! debug {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); }
    ($($arg:tt)*) => { log!("", $($arg)*); }
}
macro_rules! trace {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); }
    ($($arg:tt)*) => { log!("", $($arg)*); }
}
<|endoftext|>


<commit_before>#![recursion_limit = "256"]
// http://stackoverflow.com/questions/25877285/how-to-disable-unused-code-warnings-in-rust
// https://users.rust-lang.org/t/turning-off-compiler-warning-messages/4975/2
#![allow(non_snake_case)]

mod api;
mod files;

use serde_derive::Serialize;

use dotenv::dotenv;
use std::env;

use actix_web::{guard, middleware, web, App, Error as ActixError, HttpResponse, HttpServer};

use typed_html::elements::FlowContent;
use typed_html::types::Metadata;
use typed_html::{dom::DOMTree, html, text, OutputType};

use tinytemplate::TinyTemplate;

use deadpool_postgres::{Manager, ManagerConfig, Pool, RecyclingMethod};
use tokio_postgres::NoTls;

use std::path::Path;

static TEMPLATE: &str = "Hello {name}!";
#[derive(Serialize)]
struct Context {
    name: String,
}

#[derive(Serialize, Debug)]
struct TemplateContext {
    parent: String,
    name: String,
    content: String,
    items: Vec<String>,
}

use std::path;
use std::process::Command;

async fn template(ssr: web::Path<bool>) -> Result<HttpResponse, ActixError> {
    let s2 = getStr();
    let s: String = if *ssr { s2.to_owned() } else { "".to_owned() };
    let context = TemplateContext {
        parent: "index".to_owned(),
        name: "Roman".to_owned(),
        content: s,
        items: vec!["One", "Two", "Three"]
            .iter()
            .map(|s| s.to_string())
            .collect(),
    };

    let doc: DOMTree<String> = doc(
        html!(

"Hello Kitty"

                            "She is not a cat. She is a human girl."

                        { (0..3).map(|_| html!(

                                "Her name is Kitty White."

                        )) }

                            "We still don't know how she eats."

"Hello Kitty"

                        "DYNAMIC_CONTENT"

                ),
        context,
    );
    let mut doc_str = "<!doctype html>".to_owned() + &doc.to_string();

    // https://users.rust-lang.org/t/how-to-create-a-macro-from-dynamic-content/5079
    doc_str = doc_str.replacen("DYNAMIC_CONTENT", &s2, 1);

    Ok(HttpResponse::Ok().content_type("text/html").body(doc_str))
}

fn doc<T: OutputType + 'static + Send>(
    tree: Box<dyn FlowContent<T>>,
    context: TemplateContext,
) -> DOMTree<T> {
    let TemplateContext { name, items, .. } = context;
    html!(

                <title>"Hello Kitty"</title>
                <meta charset="utf-8" />
                <meta name="viewport" content="width=device-width, initial-scale=1.0" />
                <link rel="icon" href="/favicon.ico?v=1" />
                <link href="/styles/normalize.css" rel="stylesheet" type="text/css" media="all" />
                <link href="/styles/style.css" rel="stylesheet" type="text/css" media="all" />
                <base href="/"></base>
                <meta name=Metadata::Author content="Not Sanrio Co., Ltd" />

{text!("{}", name)}

"Here are your items:"

                    {
                     items.iter().map(|item| html!(

{text!("{}", item)}

                     ))
                    }

                 { tree }

"Try going to ""/hello/YourName"

    )
}

use std::fs;
use std::fs::OpenOptions;
use std::io::prelude::*;

fn getStr() -> String {
    fs::copy(
        "../client/src/elm/Main.elm",
        "../client/src/elm/Main.elm.bak",
    )
    .expect("file not copied");
    let stdout: Vec<u8>;
    {
        let mut main_file = OpenOptions::new()
            .append(true)
            .open("../client/src/elm/Main.elm")
            .expect("file not opened");

        let str1 = format!(
            r#"
            view : Html Msg
            view =
                viewWithModel <|
                    Model [] HomeRoute <|
                        Flags "" {time} ""
            "#,
            time = time::OffsetDateTime::unix_epoch().second()
        );

        main_file
            .write_all(str1.as_bytes())
            .expect("file content not saved");

        stdout = Command::new("node")
            .current_dir(&path::Path::new("../client"))
            .arg("./node_modules/elm-static-html/index.js")
            .arg("-f")
            .arg("src/elm/Main.elm")
            .output()
            .expect("elm-static-html command failed to start")
            .stdout;
    }
    fs::rename(
        "../client/src/elm/Main.elm.bak",
        "../client/src/elm/Main.elm",
    )
    .expect("file not renamed");

    String::from_utf8_lossy(&*stdout)
        .lines()
        .skip_while(|x| x.find(r#"id="content""#).is_none())
        .collect()
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Error: NotPresent
    // Chaning to specific file, bc `strace ./target/debug/rustommerce` shown,
    // that dotenv searches up for .env till it reaches /
    // https://galenguyer.com/blog/2020/05/19/docker-rust-notpresent
    let my_path = env::current_dir().map(|a| a.join("../.env"))?;
    dotenv::from_path(my_path.as_path());

    env::set_var("RUST_LOG", "actix_web=info");
    env_logger::init();
    let endpoint = format!("127.0.0.1:{}", env::var("SERVER_PORT")?);

    let connection_string = format!(
        "postgres://{}:{}@{}:{}/{}",
        &env::var("DBUSER")?,
        &env::var("DBPASS")?,
        &env::var("DBHOST")?,
        &env::var("DBPORT")?,
        &env::var("DBNAME")?,
    );
    // Idea for parse from
    // https://github.com/OneSignal/L3-37/blob/2031639d1f3a7aa00a5a741b87b464e19d995d21/l337-postgres/src/lib.rs#L217
    let pg_config: tokio_postgres::Config = connection_string.parse()?;
    let mgr_config = ManagerConfig {
        recycling_method: RecyclingMethod::Fast,
    };
    let mgr = Manager::from_config(pg_config, NoTls, mgr_config);
    let pool = Pool::new(mgr, 16);

    let mut tt = TinyTemplate::new();
    tt.add_template("hello", TEMPLATE)?;

    let context = Context {
        name: "TinyTemplate".to_string(),
    };

    let rendered = tt.render("hello", &context)?;
    println!("{}", rendered);

    let sys = actix_rt::System::new("app");
    HttpServer::new(move || {
        App::new()
            .data(pool.clone())
            .wrap(middleware::Logger::default())
            .service(web::resource("/template/{ssr}").route(web::get().to(template)))
            .service(web::resource("/userInformation").route(web::get().to(api::user_information)))
            .service(web::resource("/dataSets").route(web::get().to(api::data_sets)))
            .service(web::resource("/dataSets/{url}").route(web::get().to(api::data_set)))
            .service(
                web::resource("/dataSetsCategories")
                    .route(web::get().to(api::data_sets_categories)),
            )
            .service(
                web::resource("/dataSetsCategories/{url}")
                    .route(web::get().to(api::data_set_category)),
            )
            .service(web::resource("/favicon").route(web::get().to(files::favicon)))
            .service(web::resource("/styles/{file:.*}").route(web::get().to(files::styles)))
            .service(web::resource("/js/{file:.*}").route(web::get().to(files::js)))
            .default_service(
                // 404 for GET request
                web::resource("")
                    .route(web::get().to(files::index))
                    // all requests that are not `GET`
                    .route(
                        web::route()
                            .guard(guard::Not(guard::Get()))
                            .to(HttpResponse::MethodNotAllowed),
                    ),
            )
    })
    .bind(&endpoint)?
    .run();
    // If you do not return `Ok(())` but just `.run()`, this will happend:
    // When main returns `Result<(), Box<dyn std::error::Error + 'static + Send + Sync>> instead of
    // `io::Result<()>`, there is error and `into()` is needed.
    // expected struct `std::boxed::Box`, found struct `std::io::Error`
    // https://users.rust-lang.org/t/boxing-errors-in-result-throws-type-mismatch/36692/2
    //.map_err(|e| e.into())

    println!("Server running at {:?}", endpoint);
    let _ = sys.run();

    Ok(())
}
<commit_msg>server: cleaning<commit_after>#![recursion_limit = "256"]
// http://stackoverflow.com/questions/25877285/how-to-disable-unused-code-warnings-in-rust
// https://users.rust-lang.org/t/turning-off-compiler-warning-messages/4975/2
#![allow(non_snake_case)]

mod api;
mod files;

use serde_derive::Serialize;

use dotenv;
use std::env;

use actix_web::{guard, middleware, web, App, Error as ActixError, HttpResponse, HttpServer};

use typed_html::elements::FlowContent;
use typed_html::types::Metadata;
use typed_html::{dom::DOMTree, html, text, OutputType};

use tinytemplate::TinyTemplate;

use deadpool_postgres::{Manager, ManagerConfig, Pool, RecyclingMethod};
use tokio_postgres::NoTls;

static TEMPLATE: &str = "Hello {name}!";
#[derive(Serialize)]
struct Context {
    name: String,
}

#[derive(Serialize, Debug)]
struct TemplateContext {
    parent: String,
    name: String,
    content: String,
    items: Vec<String>,
}

use std::path;
use std::process::Command;

async fn template(ssr: web::Path<bool>) -> Result<HttpResponse, ActixError> {
    let s2 = getStr();
    let s: String = if *ssr { s2.to_owned() } else { "".to_owned() };
    let context = TemplateContext {
        parent: "index".to_owned(),
        name: "Roman".to_owned(),
        content: s,
        items: vec!["One", "Two", "Three"]
            .iter()
            .map(|s| s.to_string())
            .collect(),
    };

    let doc: DOMTree<String> = doc(
        html!(

"Hello Kitty"

                            "She is not a cat. She is a human girl."

                        { (0..3).map(|_| html!(

                                "Her name is Kitty White."

                        )) }

                            "We still don't know how she eats."

"Hello Kitty"

                        "DYNAMIC_CONTENT"

                ),
        context,
    );
    let mut doc_str = "<!doctype html>".to_owned() + &doc.to_string();

    // https://users.rust-lang.org/t/how-to-create-a-macro-from-dynamic-content/5079
    doc_str = doc_str.replacen("DYNAMIC_CONTENT", &s2, 1);

    Ok(HttpResponse::Ok().content_type("text/html").body(doc_str))
}

fn doc<T: OutputType + 'static + Send>(
    tree: Box<dyn FlowContent<T>>,
    context: TemplateContext,
) -> DOMTree<T> {
    let TemplateContext { name, items, .. } = context;
    html!(

                <title>"Hello Kitty"</title>
                <meta charset="utf-8" />
                <meta name="viewport" content="width=device-width, initial-scale=1.0" />
                <link rel="icon" href="/favicon.ico?v=1" />
                <link href="/styles/normalize.css" rel="stylesheet" type="text/css" media="all" />
                <link href="/styles/style.css" rel="stylesheet" type="text/css" media="all" />
                <base href="/"></base>
                <meta name=Metadata::Author content="Not Sanrio Co., Ltd" />

{text!("{}", name)}

"Here are your items:"

                    {
                     items.iter().map(|item| html!(

{text!("{}", item)}

                     ))
                    }

                 { tree }

"Try going to ""/hello/YourName"

    )
}

use std::fs;
use std::fs::OpenOptions;
use std::io::prelude::*;

fn getStr() -> String {
    fs::copy(
        "../client/src/elm/Main.elm",
        "../client/src/elm/Main.elm.bak",
    )
    .expect("file not copied");
    let stdout: Vec<u8>;
    {
        let mut main_file = OpenOptions::new()
            .append(true)
            .open("../client/src/elm/Main.elm")
            .expect("file not opened");

        let str1 = format!(
            r#"
            view : Html Msg
            view =
                viewWithModel <|
                    Model [] HomeRoute <|
                        Flags "" {time} ""
            "#,
            time = time::OffsetDateTime::unix_epoch().second()
        );

        main_file
            .write_all(str1.as_bytes())
            .expect("file content not saved");

        stdout = Command::new("node")
            .current_dir(&path::Path::new("../client"))
            .arg("./node_modules/elm-static-html/index.js")
            .arg("-f")
            .arg("src/elm/Main.elm")
            .output()
            .expect("elm-static-html command failed to start")
            .stdout;
    }
    fs::rename(
        "../client/src/elm/Main.elm.bak",
        "../client/src/elm/Main.elm",
    )
    .expect("file not renamed");

    String::from_utf8_lossy(&*stdout)
        .lines()
        .skip_while(|x| x.find(r#"id="content""#).is_none())
        .collect()
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Error: NotPresent
    // Chaning to specific file, bc `strace ./target/debug/rustommerce` shown,
    // that dotenv searches up for .env till it reaches /
    // https://galenguyer.com/blog/2020/05/19/docker-rust-notpresent
    let my_path = env::current_dir().map(|a| a.join("../.env"))?;
    dotenv::from_path(my_path.as_path())?;

    env::set_var("RUST_LOG", "actix_web=info");
    env_logger::init();
    let endpoint = format!("127.0.0.1:{}", env::var("SERVER_PORT")?);

    let connection_string = format!(
        "postgres://{}:{}@{}:{}/{}",
        &env::var("DBUSER")?,
        &env::var("DBPASS")?,
        &env::var("DBHOST")?,
        &env::var("DBPORT")?,
        &env::var("DBNAME")?,
    );
    // Idea for parse from
    // https://github.com/OneSignal/L3-37/blob/2031639d1f3a7aa00a5a741b87b464e19d995d21/l337-postgres/src/lib.rs#L217
    let pg_config: tokio_postgres::Config = connection_string.parse()?;
    let mgr_config = ManagerConfig {
        recycling_method: RecyclingMethod::Fast,
    };
    let mgr = Manager::from_config(pg_config, NoTls, mgr_config);
    let pool = Pool::new(mgr, 16);

    let mut tt = TinyTemplate::new();
    tt.add_template("hello", TEMPLATE)?;

    let context = Context {
        name: "TinyTemplate".to_string(),
    };

    let rendered = tt.render("hello", &context)?;
    println!("{}", rendered);

    let sys = actix_rt::System::new("app");
    HttpServer::new(move || {
        App::new()
            .data(pool.clone())
            .wrap(middleware::Logger::default())
            .service(web::resource("/template/{ssr}").route(web::get().to(template)))
            .service(web::resource("/userInformation").route(web::get().to(api::user_information)))
            .service(web::resource("/dataSets").route(web::get().to(api::data_sets)))
            .service(web::resource("/dataSets/{url}").route(web::get().to(api::data_set)))
            .service(
                web::resource("/dataSetsCategories")
                    .route(web::get().to(api::data_sets_categories)),
            )
            .service(
                web::resource("/dataSetsCategories/{url}")
                    .route(web::get().to(api::data_set_category)),
            )
            .service(web::resource("/favicon").route(web::get().to(files::favicon)))
            .service(web::resource("/styles/{file:.*}").route(web::get().to(files::styles)))
            .service(web::resource("/js/{file:.*}").route(web::get().to(files::js)))
            .default_service(
                // 404 for GET request
                web::resource("")
                    .route(web::get().to(files::index))
                    // all requests that are not `GET`
                    .route(
                        web::route()
                            .guard(guard::Not(guard::Get()))
                            .to(HttpResponse::MethodNotAllowed),
                    ),
            )
    })
    .bind(&endpoint)?
    .run();
    // If you do not return `Ok(())` but just `.run()`, this will happend:
    // When main returns `Result<(), Box<dyn std::error::Error + 'static + Send + Sync>> instead of
    // `io::Result<()>`, there is error and `into()` is needed.
    // expected struct `std::boxed::Box`, found struct `std::io::Error`
    // https://users.rust-lang.org/t/boxing-errors-in-result-throws-type-mismatch/36692/2
    //.map_err(|e| e.into())

    println!("Server running at {:?}", endpoint);
    let _ = sys.run();

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use super::*;

/// Collects information about available network interfaces.
///
/// A system agnostic [`interfaces`] function is available in the parent module
/// and should be the preferred choice in general.
///
/// This function is a wrapper around [`getifaddrs`][1] macOS call.
///
/// [1]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/getifaddrs.3.html
///
/// [`interfaces`]: super::interfaces
pub fn interfaces() -> std::io::Result<impl Iterator<Item = Interface>> {
    // Note that the this function is implemented nearly identically to the
    // Linux one. However, despite identical structure names (except for the
    // MAC address structure), their memory layout is completely different and
    // the code cannot (or rather: it should not) be shared.
    let mut addrs = std::mem::MaybeUninit::uninit();

    // SAFETY: `getifaddrs` [1] returns a pointer (through an output parameter)
    // so there is no potential of unsafety here and the function is marked as
    // such because it operates on raw pointers.
    //
    // [1]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/getifaddrs.3.html
    let code = unsafe {
        libc::getifaddrs(addrs.as_mut_ptr())
    };
    if code != 0 {
        return Err(std::io::Error::from_raw_os_error(code));
    }

    // SAFETY: We check return code above. If there was no error, `getifaddrs`
    // should initialized the `addrs` variable to a correct value.
    let addrs = unsafe {
        addrs.assume_init()
    };

    let mut ifaces = std::collections::HashMap::new();

    let mut addr_iter = addrs;
    // SAFETY: We iterate over the linked list of addresses until we hit the
    // last entry. The validity of the `addr_iter` pointer is ensured by:
    //
    //   * Starting at the value reported by the `getifaddrs` call.
    //   * Always moving to the entry pointed by the `ifa_next` field (at the
    //     end of the loop).
    while let Some(addr) = unsafe { addr_iter.as_ref() } {
        use std::os::unix::ffi::OsStrExt as _;

        // We advance the iterator immediately to avoid getting stuck because of
        // the `continue` statements in the code below.
        addr_iter = addr.ifa_next;

        // SAFETY: `ifa_ddr` is not guaranteed to be not null, so we have to
        // verify it. But if it is not null, it is guaranteed to point to valid
        // address instance.
        let family = match unsafe { addr.ifa_addr.as_ref() } {
            Some(addr) => addr.sa_family,
            None => continue,
        };

        // SAFETY: `ifa_name` is a string with interface name. While Apple docs
        // do not mention whether it is null-terminated, it is a safe bet to
        // assume so given the similarity to the Linux version of `getifaddrs`.
        let name = std::ffi::OsStr::from_bytes(unsafe {
            std::ffi::CStr::from_ptr(addr.ifa_name)
        }.to_bytes());

        let entry = ifaces.entry(name).or_insert(Interface {
            name: name.to_os_string(),
            ip_addrs: Vec::new(),
            mac_addr: None,
        });

        match i32::from(family) {
            libc::AF_INET => {
                // SAFETY: For `AF_INET` family the `ifa_addr` field is instance
                // of the IPv4 address [1, 2]. Again, the documentation on this
                // is quite bad.
                //
                // [1]: https://developer.apple.com/documentation/kernel/sockaddr_in
                // [2]: https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/netinet/in.h#L394-L403
                let ipv4_addr_u32 = unsafe {
                    *(addr.ifa_addr as *const libc::sockaddr_in)
                }.sin_addr.s_addr;

                // Unlike on Linux, Apple documentation does not say anything
                // whatsoever about the endianness of the address value [1, 2].
                // We give them the benefit of a doubt and assume that they do
                // a sane thing and follow the Linux convention here.
                //
                // Hence, we have to convert from network endian (big endian)
                // order to what the Rust IPv4 type constructor expects (host
                // endian).
                //
                // [1]: https://developer.apple.com/documentation/kernel/in_addr_t
                // [2]: https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/sys/_types/_in_addr_t.h#L31
                let ipv4_addr_u32 = u32::from_be(ipv4_addr_u32);

                let ipv4_addr = std::net::Ipv4Addr::from(ipv4_addr_u32);
                entry.ip_addrs.push(ipv4_addr.into());
            }
            libc::AF_INET6 => {
                // SAFETY: For `AF_INET6` family the `ifa_addr` field is an
                // instance of the IPv6 address [1, 2]. The comment on the
                // `sin6_family` field confirms it (unlike for `AF_INET`). Thus,
                // the case is safe.
                //
                // [1]: https://developer.apple.com/documentation/kernel/sockaddr_in6
                // [2]: https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/netinet6/in6.h#L181-L188
                let ipv6_addr_octets = unsafe {
                    *(addr.ifa_addr as *const libc::sockaddr_in6)
                }.sin6_addr.s6_addr;

                let ipv6_addr = std::net::Ipv6Addr::from(ipv6_addr_octets);
                entry.ip_addrs.push(ipv6_addr.into());
            }
            libc::AF_LINK => {
                // SAFETY: For `AF_LINK` family the `ifa_addr` field is an
                // instance of a link-level address [1, 2] (whatever that means
                // exactly). Again, the comment on the `sdl_family` field seems
                // to confirm this and the cast is safe.
                //
                // [1]: https://developer.apple.com/documentation/kernel/sockaddr_dl
                // [2]: https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/net/if_dl.h#L95-L110
                let sockaddr = unsafe {
                    *(addr.ifa_addr as *const libc::sockaddr_dl)
                };

                // Like on Linux, MAC address should always have 6 8-bit octets.
                // It is not clear whether the `sdl_alen` value can be different
                // but we check just to be sure and skip if the assumption does
                // not hold.
                if sockaddr.sdl_alen != 6 {
                    // TODO: Consider logging an error.
                    continue;
                }

                // SAFETY: The original `sdl_data` is typed as `i8` (because it
                // contains the name) but the actual address bytes should be in-
                // terpreted as normal bytes (verified empirically). Validity of
                // indexing is ensured by the `sdl_alen` check above.
                let mac_addr = unsafe {
                    let data = sockaddr.sdl_data.as_ptr()
                        .offset(isize::from(sockaddr.sdl_nlen))
                        .cast::<u8>();

                    MacAddr::from([
                        *data.offset(0),
                        *data.offset(1),
                        *data.offset(2),
                        *data.offset(3),
                        *data.offset(4),
                        *data.offset(5),
                    ])
                };

                // TODO: There should only be one MAC address associated with
                // a given interface. Consider logging a warning in case this
                // assumption does not hold.
                entry.mac_addr.replace(mac_addr);
            }
            _ => continue,
        }
    }

    // We need to collect the interfaces to free the addresses below. Otherwise,
    // the keys of the hash map will point to dangling references (since the map
    // keys are owned by the address list).
    let ifaces = ifaces.into_values().collect::<Vec<_>>();

    // SAFETY: The `getifaddrs` call at the beginning of this function creates
    // a linked list that we are responsible for freeing using the `freeifaddrs`
    // function [1]. This is safe as we never release the allocated memory.
    //
    // [1]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/freeifaddrs.3.html
    unsafe {
        libc::freeifaddrs(addrs);
    }

    Ok(ifaces.into_iter())
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn loopback_exists() {
        let mut ifaces = interfaces().unwrap();

        // TODO: Check whether we can make more assumptions. For example, on
        // Linux we can assume that the loopback device is named `lo` and that
        // it has a MAC address that consists only of zeros.
        assert! {
            ifaces.any(|iface| {
                iface.ip_addrs().iter().any(|ip_addr| {
                    ip_addr.is_loopback()
                })
            })
        };
    }
}
<commit_msg>Adjust comments about net interfaces on macOS.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use super::*;

/// Collects information about available network interfaces.
///
/// A system agnostic [`interfaces`] function is available in the parent module
/// and should be the preferred choice in general.
///
/// This function is a wrapper around [`getifaddrs`][1] macOS call.
///
/// [1]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/getifaddrs.3.html
///
/// [`interfaces`]: super::interfaces
pub fn interfaces() -> std::io::Result<impl Iterator<Item = Interface>> {
    // Note that the this function is implemented nearly identically to the
    // Linux one. However, despite identical structure names (except for the
    // MAC address structure), their memory layout is completely different and
    // the code cannot (or rather: it should not) be shared.
    let mut addrs = std::mem::MaybeUninit::uninit();

    // SAFETY: `getifaddrs` [1] returns a pointer (through an output parameter)
    // so there is no potential of unsafety here and the function is marked as
    // such because it operates on raw pointers.
    //
    // [1]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/getifaddrs.3.html
    let code = unsafe {
        libc::getifaddrs(addrs.as_mut_ptr())
    };
    if code != 0 {
        return Err(std::io::Error::from_raw_os_error(code));
    }

    // SAFETY: We check return code above. If there was no error, `getifaddrs`
    // should initialized the `addrs` variable to a correct value.
    let addrs = unsafe {
        addrs.assume_init()
    };

    let mut ifaces = std::collections::HashMap::new();

    let mut addr_iter = addrs;
    // SAFETY: We iterate over the linked list of addresses until we hit the
    // last entry. The validity of the `addr_iter` pointer is ensured by:
    //
    //   * Starting at the value reported by the `getifaddrs` call.
    //   * Always moving to the entry pointed by the `ifa_next` field (at the
    //     end of the loop).
    while let Some(addr) = unsafe { addr_iter.as_ref() } {
        use std::os::unix::ffi::OsStrExt as _;

        // We advance the iterator immediately to avoid getting stuck because of
        // the `continue` statements in the code below.
        addr_iter = addr.ifa_next;

        // SAFETY: `ifa_ddr` is not guaranteed to be not null, so we have to
        // verify it. But if it is not null, it is guaranteed to point to valid
        // address instance.
        let family = match unsafe { addr.ifa_addr.as_ref() } {
            Some(addr) => addr.sa_family,
            None => continue,
        };

        // SAFETY: `ifa_name` is a string with interface name. While Apple docs
        // do not mention whether it is null-terminated, it is a safe bet to
        // assume so given the similarity to the Linux version of `getifaddrs`.
        let name = std::ffi::OsStr::from_bytes(unsafe {
            std::ffi::CStr::from_ptr(addr.ifa_name)
        }.to_bytes());

        let entry = ifaces.entry(name).or_insert(Interface {
            name: name.to_os_string(),
            ip_addrs: Vec::new(),
            mac_addr: None,
        });

        match i32::from(family) {
            libc::AF_INET => {
                // SAFETY: For `AF_INET` family the `ifa_addr` field is instance
                // of the IPv4 address [1, 2]. Again, the documentation on this
                // is quite bad.
                //
                // [1]: https://developer.apple.com/documentation/kernel/sockaddr_in
                // [2]: https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/netinet/in.h#L394-L403
                let ipv4_addr_u32 = unsafe {
                    *(addr.ifa_addr as *const libc::sockaddr_in)
                }.sin_addr.s_addr;

                // Unlike on Linux, Apple documentation does not say anything
                // whatsoever about the endianness of the address value [1, 2].
                // We give them the benefit of a doubt and assume that they do
                // a sane thing and follow the Linux convention here.
                //
                // Hence, we have to convert from network endian (big endian)
                // order to what the Rust IPv4 type constructor expects (host
                // endian).
                //
                // [1]: https://developer.apple.com/documentation/kernel/in_addr_t
                // [2]: https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/sys/_types/_in_addr_t.h#L31
                let ipv4_addr_u32 = u32::from_be(ipv4_addr_u32);

                let ipv4_addr = std::net::Ipv4Addr::from(ipv4_addr_u32);
                entry.ip_addrs.push(ipv4_addr.into());
            }
            libc::AF_INET6 => {
                // SAFETY: For `AF_INET6` family the `ifa_addr` field is an
                // instance of the IPv6 address [1, 2]. The comment on the
                // `sin6_family` field confirms it (unlike for `AF_INET`). Thus,
                // the case is safe.
                //
                // [1]: https://developer.apple.com/documentation/kernel/sockaddr_in6
                // [2]: https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/netinet6/in6.h#L181-L188
                let ipv6_addr_octets = unsafe {
                    *(addr.ifa_addr as *const libc::sockaddr_in6)
                }.sin6_addr.s6_addr;

                let ipv6_addr = std::net::Ipv6Addr::from(ipv6_addr_octets);
                entry.ip_addrs.push(ipv6_addr.into());
            }
            libc::AF_LINK => {
                // SAFETY: For `AF_LINK` family the `ifa_addr` field is an
                // instance of a link-level address [1, 2] (whatever that means
                // exactly). Again, the comment on the `sdl_family` field seems
                // to confirm this and the cast is safe.
                //
                // [1]: https://developer.apple.com/documentation/kernel/sockaddr_dl
                // [2]: https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/net/if_dl.h#L95-L110
                let sockaddr = unsafe {
                    *(addr.ifa_addr as *const libc::sockaddr_dl)
                };

                // Unfortunatelly, it is not uncommon to have some other non-MAC
                // addresses with the `AF_LINK` family. We simply ignore such.
                if sockaddr.sdl_alen != 6 {
                    continue;
                }

                // SAFETY: The original `sdl_data` is typed as `i8` (because it
                // contains the name) but the actual address bytes should be in-
                // terpreted as normal bytes (verified empirically). Validity of
                // indexing is ensured by the `sdl_alen` check above.
                let mac_addr = unsafe {
                    let data = sockaddr.sdl_data.as_ptr()
                        .offset(isize::from(sockaddr.sdl_nlen))
                        .cast::<u8>();

                    MacAddr::from([
                        *data.offset(0),
                        *data.offset(1),
                        *data.offset(2),
                        *data.offset(3),
                        *data.offset(4),
                        *data.offset(5),
                    ])
                };

                // TODO: There should only be one MAC address associated with
                // a given interface. Consider logging a warning in case this
                // assumption does not hold.
                entry.mac_addr.replace(mac_addr);
            }
            _ => continue,
        }
    }

    // We need to collect the interfaces to free the addresses below. Otherwise,
    // the keys of the hash map will point to dangling references (since the map
    // keys are owned by the address list).
    let ifaces = ifaces.into_values().collect::<Vec<_>>();

    // SAFETY: The `getifaddrs` call at the beginning of this function creates
    // a linked list that we are responsible for freeing using the `freeifaddrs`
    // function [1]. This is safe as we never release the allocated memory.
    //
    // [1]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/freeifaddrs.3.html
    unsafe {
        libc::freeifaddrs(addrs);
    }

    Ok(ifaces.into_iter())
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn loopback_exists() {
        let mut ifaces = interfaces().unwrap();

        // On macOS the loopback interface seems to be always named `lo0` but it
        // does not appear to be documented anywhere, so to be on the safe side
        // we do not make such specific assertions.
        assert! {
            ifaces.any(|iface| {
                iface.ip_addrs().iter().any(|ip_addr| {
                    ip_addr.is_loopback()
                })
            })
        };
    }
}
<|endoftext|>


<commit_before>use clock::{GameTime, GameClock};
use framerate::counter::FrameCount;

#[derive(Debug)]
pub struct FrameRunner<C: FrameCount> {
    clock: GameClock,
    counter: C,
}

impl<C> FrameRunner<C>
    where C: FrameCount
{
    pub fn new(clock: GameClock, counter: C) -> FrameRunner<C> {
        FrameRunner {
            clock: clock,
            counter: counter,
        }
    }

    pub fn clock(&self) -> &GameClock {
        &self.clock
    }
    pub fn clock_mut(&mut self) -> &mut GameClock {
        &mut self.clock
    }
    pub fn counter(&self) -> &C {
        &self.counter
    }
    pub fn counter_mut(&mut self) -> &mut C {
        &mut self.counter
    }
    pub fn tick(&mut self) -> GameTime {
        let time = self.clock.tick(&mut self.counter);
        time
    }

    pub fn do_frame<F>(&mut self, frame_fn: F)
        where F: FnOnce(GameTime)
    {
        let time = self.tick();
        frame_fn(time);
        self.clock.sleep_remaining(&self.counter);
    }
}
<commit_msg>Document the `runner` module.<commit_after>//! Implements the [`FrameRunner`](./runner/struct.FrameRunner.html) struct for managing frame simulations.
use clock::{GameTime, GameClock};
use framerate::counter::FrameCount;

/// A helper type for running frame simulations with a frame counter.
///
/// `FrameRunner` combines a [`GameClock`](../clock/struct.GameTime.html)
/// and a [`FrameCount`](../framerate/counter/struct.FrameCounter.html) object,
/// tracking each frame as well as a framerate. `FrameRunner` provides
/// a `tick` method like `GameClock`, and updates both the `GameClock` and
/// `FrameCount` objects contained.
#[derive(Debug)]
pub struct FrameRunner<C: FrameCount> {
    clock: GameClock,
    counter: C,
}

impl<C> FrameRunner<C>
    where C: FrameCount
{
    /// Construct a new `FrameRunner` from a `GameClock` and a `FrameCount`.
    pub fn new(clock: GameClock, counter: C) -> FrameRunner<C> {
        FrameRunner {
            clock: clock,
            counter: counter,
        }
    }

    /// Get a reference to the contained `GameClock`.
    pub fn clock(&self) -> &GameClock {
        &self.clock
    }
    /// Get a mutable reference to the contained `GameClock`.
    pub fn clock_mut(&mut self) -> &mut GameClock {
        &mut self.clock
    }
    /// Get a reference to the contained `FrameCount`.
    pub fn counter(&self) -> &C {
        &self.counter
    }
    /// Get a mutable reference to the contained `FrameCount`.
    pub fn counter_mut(&mut self) -> &mut C {
        &mut self.counter
    }
    /// Mark the start of a new frame, updating time and frame rate statistics.
    ///
    /// The `GameTime` for the new frame is returned, with the same properties as that
    /// returned from [`GameClock::tick`](../clock/struct.GameClock.html#method.tick).
    pub fn tick(&mut self) -> GameTime {
        let time = self.clock.tick(&mut self.counter);
        time
    }

    /// Perform one frame of the simulation using `frame_fn`.
    ///
    /// The closure is passed the `GameTime` for the frame by calling `tick`
    /// and will call
    /// [`GameClock::sleep_remaining`](../clock/struct.GameClock.html#method.sleep_remaining)
    /// after the closure has ended.
    pub fn do_frame<F>(&mut self, frame_fn: F)
        where F: FnOnce(GameTime)
    {
        let time = self.tick();
        frame_fn(time);
        self.clock.sleep_remaining(&self.counter);
    }
}
<|endoftext|>


<commit_before>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate collections;
extern crate sync;
extern crate rand;
extern crate serialize;
use std::cmp::min;
use std::io::{IoResult, IoError, InvalidInput, SeekStyle, BufWriter, BufReader};
use std::io::{SeekSet, SeekEnd, SeekCur};
use std::mem::size_of;
use sync::{Arc, RWLock};
use serialize::ebml::{reader,writer};
use serialize::{Encodable, Decodable};
mod buffer;

#[deriving(Encodable, Decodable)]
enum SqlType {
	Char(uint),
	Varchar(uint),
	Integer,
}

#[deriving(Encodable, Decodable)]
enum SqlAttribute {
	Null,
	NotNull,
}

#[deriving(Encodable, Decodable)]
struct Column {
	name: ~str,
	datatype: SqlType,
	attributes: Vec<SqlAttribute>,
}

#[deriving(Encodable, Decodable)]
struct Relation {
	name: ~str,
	columns: Vec<Column>,
}

impl Relation {
	pub fn new(name: ~str) -> Relation {
		Relation {name: name, columns: Vec::new()}
	}

	pub fn add_column(&mut self, column: Column) {
		self.columns.push(column);
	}
}

#[deriving(Encodable, Decodable)]
struct Schema {
	relations: Vec<Relation>,
}

struct SchemaWriter<'a> {
	buffer_manager: &'a mut buffer::BufferManager,
	location: u64,
	maximum: u64,
}

impl<'a> Writer for SchemaWriter<'a> {
	fn write(&mut self, buf: &[u8]) -> IoResult<()> {
		let pageno = self.location / buffer::PAGE_SIZE as u64 + 1;
		let start_from = (self.location % buffer::PAGE_SIZE as u64) as uint;

		let pagelock = self.buffer_manager.fix_page(pageno).unwrap_or_else(|| fail!("Fix page failed"));
		let mut copied = 0;
		{
			let mut page = pagelock.write();
			let content = page.get_mut_data();

			for i in range(0, min(buf.len(), buffer::PAGE_SIZE)) {
				content[start_from+i] = buf[i];
				copied += 1;
				self.location += 1;
			}
		}
		self.buffer_manager.unfix_page(pagelock, true);
		if self.location > self.maximum {
			self.maximum = self.location;
			let pagelock = self.buffer_manager.fix_page(0).unwrap_or_else(
				|| fail!("Fixing zero page failed"));
			{
				let mut page = pagelock.write();
				let content = page.get_mut_data();
				let mut writer = BufWriter::new(content);
				match writer.write_le_u64(self.maximum) {
					Ok(_) => (),
					Err(e) => fail!("Failed writing lenght to page: {}", e)
				};
			}
			self.buffer_manager.unfix_page(pagelock, true);
		}
		//TODO remaining bytes from buf
		println!("copied {}/{}, location: {}", copied, buf.len(), self.location);
		//assert!(copied, buf.len());
		if copied == buf.len() {
			Ok(())
		} else {
			Err(IoError {
				kind: InvalidInput,
				desc: "Did not copy all data",
				detail: None,
			})
		}
	}
}

impl<'a> Seek for SchemaWriter<'a> {
	fn tell(&self) -> IoResult<u64> {
		Ok(self.location)
	}

	fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
		println!("Seeking {}", pos);
		match style {
			SeekSet => {
				self.location = pos as u64;
				Ok(())
			}
			SeekEnd => {
				Err(IoError {
					kind: InvalidInput,
					desc: "seek to end not supported",
					detail: None,
				})
			}
			SeekCur => {
				self.location = (self.location as i64 + pos) as u64;
				Ok(())
			}
		}
	}
}

impl<'a> SchemaWriter<'a> {
	pub fn new<'b>(bufman: &'b mut buffer::BufferManager) -> SchemaWriter<'b> {
		SchemaWriter {buffer_manager: bufman, location: 0,
			maximum: 0}
	}

	pub fn get_data(&mut self) -> Vec<u8> {
		let pagelock = self.buffer_manager.fix_page(0).unwrap_or_else(
			|| fail!("Failed fixing 0 page for schema length"));
		let mut size;
		{
			let page = pagelock.read();
			let mut reader = BufReader::new(page.get_data());
			size = reader.read_le_u64().unwrap();
		}
		self.buffer_manager.unfix_page(pagelock, false);
		println!("Size: {}", size);

		let mut data: Vec<u8> = Vec::with_capacity(size as uint);
		let mut read = 0;

		println!("location: {}", self.location);
		for i in range(1, self.location / buffer::PAGE_SIZE as u64 + 2) {
			println!("Reading page {}", i);
			let pagelock = self.buffer_manager.fix_page(i).unwrap_or_else(
				|| fail!("Failed fixing page {}", i));
			{
				let page = pagelock.read();
				let content = page.get_data();
				let mut j = 0;
				while read < size {
					data.push(content[j]);
					j += 1;
					read += 1;
				}
			}
			self.buffer_manager.unfix_page(pagelock, false);
		}
		data
	}
}

impl Schema {
	pub fn new() -> Schema {
		Schema {relations: Vec::new()}
	}

	pub fn new_from_disk(bufmanager: &mut buffer::BufferManager) -> Schema {
		let mut wr = SchemaWriter::new(bufmanager);
		let data = wr.get_data();
		let ebml_doc = reader::Doc(data.as_slice());
		let mut deser = reader::Decoder(ebml_doc);
		let value: Schema = match Decodable::decode(&mut deser) {
			Ok(v) => v,
			Err(e) => fail!("Error decoding: {}", e),
		};
		value
	}

	pub fn add_relation(&mut self, relation: Relation) {
		self.relations.push(relation);
	}

	pub fn save_to_disk(&self, bufmanager: &mut buffer::BufferManager) {
		let mut wr = SchemaWriter::new(bufmanager);
		{
			let mut ebml_w = writer::Encoder(&mut wr);
			let _ = self.encode(&mut ebml_w);
		}
	}
}

struct Record {
	// TODO: do we even need this?
	len: uint,
	data: Vec<u8>,
}

impl Record {
	/* move semantics, no copy */
	pub fn new(len: uint, data: Vec<u8>) -> Record {
		Record {len: len, data: data}
	}

	pub fn get_data<'a>(&'a self) -> &'a [u8] {
		self.data.as_slice()
	}
}

struct SPSegment<'a> {
	id: u64,
	manager: &'a mut buffer::BufferManager,
}

struct SlottedPageHeader {
	slot_count: uint,
	free_slot: uint,
	data_start: uint,
	free_space: uint,
}

struct Slot((uint, uint));

struct SlottedPage {
	header: SlottedPageHeader,
	frame: Arc<RWLock<buffer::BufferFrame>>,
}

impl SlottedPage {
	pub fn new(frame: Arc<RWLock<buffer::BufferFrame>>) -> SlottedPage {
		let header = {
			let mut frame = frame.write();
			let mut br = BufReader::new(frame.get_data());
			let slot_count = br.read_le_uint().unwrap();
			let free_slot = br.read_le_uint().unwrap();
			let data_start = br.read_le_uint().unwrap();
			let free_space = br.read_le_uint().unwrap();

			if slot_count == 0 && free_space == 0 {
				// blank frame, construct header
				let slot_count = 0;
				let free_slot = 0;
				let data_start = buffer::PAGE_SIZE;
				let free_space = buffer::PAGE_SIZE - size_of::<SlottedPageHeader>();
				SlottedPageHeader {slot_count: slot_count,
					free_slot: free_slot, data_start: data_start,
					free_space: free_space}
			} else {
				SlottedPageHeader {slot_count: slot_count,
					free_slot: free_slot, data_start: data_start,
					free_space: free_space}
			}

		};
		SlottedPage {frame: frame, header: header}
	}

	fn write_header(&mut self) {
		let mut frame = self.frame.write();
		let mut bw = BufWriter::new(frame.get_mut_data());
		bw.write_le_uint(self.header.slot_count);
		bw.write_le_uint(self.header.free_slot);
		bw.write_le_uint(self.header.data_start);
		bw.write_le_uint(self.header.free_space);
	}

	fn try_insert(&mut self, r: &Record) -> (bool, uint) {
		(false, 0)
	}
}

struct TID {
	page_id: u64,
	slot_id: uint,
}

fn join_segment(segment: u64, page: u64) -> u64{
	(segment << 48) & page
}

impl<'a> SPSegment<'a> {
	pub fn insert(&mut self, r: &Record) -> TID {
		let mut tid = TID {page_id: 0, slot_id: 0};
		for i in range(1, 1<<48) {
			let pagelock = match self.manager.fix_page(join_segment(self.id, i as u64)) {
				Some(p) => p,
				None => fail!("Failed aquiring page {}", i),
			};
			let mut sp = SlottedPage::new(pagelock.clone());
			let (inserted, slot) = sp.try_insert(r);
			self.manager.unfix_page(pagelock, inserted);
			if inserted {
				tid = TID {page_id: i as u64, slot_id: slot};
				break;
			}
		}
		tid
	}

	pub fn remove(tid: TID) -> bool {
		false
	}

	pub fn lookup(tid: TID) -> Record {
		// TODO
		Record {len: 1, data: vec!(1)}
	}

	pub fn update(tid: TID, r: Record) -> bool {
		false
	}
}

#[test]
fn main() {
}

#[test]
fn create_schema() {
	let name = Column {name: ~"name", datatype: Varchar(128), attributes: vec!(NotNull)};
	let age = Column {name: ~"age", datatype: Integer, attributes: vec!(NotNull)};
	let mut relation = Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	let mut schema = Schema::new();
	schema.add_relation(relation);

	let mut manager = buffer::BufferManager::new(1024, Path::new("."));
	schema.save_to_disk(&mut manager);
	let new_schema = Schema::new_from_disk(&mut manager);
	println!("new_schema == {:?}", new_schema);
	assert!(false);
}

#[test]
fn slotted_page_create() {
	let mut manager = buffer::BufferManager::new(1024, Path::new("."));
	let mut seg = SPSegment {id: 1, manager: &mut manager};
	let rec = Record {len: 1, data: vec!(42)};
	let tid = seg.insert(&rec);
}
<commit_msg>Implemented insertion<commit_after>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate collections;
extern crate sync;
extern crate rand;
extern crate serialize;
use std::cmp::min;
use std::io::{IoResult, IoError, InvalidInput, SeekStyle, BufWriter, BufReader};
use std::io::{SeekSet, SeekEnd, SeekCur};
use std::mem::size_of;
use sync::{Arc, RWLock};
use serialize::ebml::{reader,writer};
use serialize::{Encodable, Decodable};
mod buffer;

#[deriving(Encodable, Decodable)]
enum SqlType {
	Char(uint),
	Varchar(uint),
	Integer,
}

#[deriving(Encodable, Decodable)]
enum SqlAttribute {
	Null,
	NotNull,
}

#[deriving(Encodable, Decodable)]
struct Column {
	name: ~str,
	datatype: SqlType,
	attributes: Vec<SqlAttribute>,
}

#[deriving(Encodable, Decodable)]
struct Relation {
	name: ~str,
	columns: Vec<Column>,
}

impl Relation {
	pub fn new(name: ~str) -> Relation {
		Relation {name: name, columns: Vec::new()}
	}

	pub fn add_column(&mut self, column: Column) {
		self.columns.push(column);
	}
}

#[deriving(Encodable, Decodable)]
struct Schema {
	relations: Vec<Relation>,
}

struct SchemaWriter<'a> {
	buffer_manager: &'a mut buffer::BufferManager,
	location: u64,
	maximum: u64,
}

impl<'a> Writer for SchemaWriter<'a> {
	fn write(&mut self, buf: &[u8]) -> IoResult<()> {
		let pageno = self.location / buffer::PAGE_SIZE as u64 + 1;
		let start_from = (self.location % buffer::PAGE_SIZE as u64) as uint;

		let pagelock = self.buffer_manager.fix_page(pageno).unwrap_or_else(|| fail!("Fix page failed"));
		let mut copied = 0;
		{
			let mut page = pagelock.write();
			let content = page.get_mut_data();

			for i in range(0, min(buf.len(), buffer::PAGE_SIZE)) {
				content[start_from+i] = buf[i];
				copied += 1;
				self.location += 1;
			}
		}
		self.buffer_manager.unfix_page(pagelock, true);
		if self.location > self.maximum {
			self.maximum = self.location;
			let pagelock = self.buffer_manager.fix_page(0).unwrap_or_else(
				|| fail!("Fixing zero page failed"));
			{
				let mut page = pagelock.write();
				let content = page.get_mut_data();
				let mut writer = BufWriter::new(content);
				match writer.write_le_u64(self.maximum) {
					Ok(_) => (),
					Err(e) => fail!("Failed writing lenght to page: {}", e)
				};
			}
			self.buffer_manager.unfix_page(pagelock, true);
		}
		//TODO remaining bytes from buf
		println!("copied {}/{}, location: {}", copied, buf.len(), self.location);
		//assert!(copied, buf.len());
		if copied == buf.len() {
			Ok(())
		} else {
			Err(IoError {
				kind: InvalidInput,
				desc: "Did not copy all data",
				detail: None,
			})
		}
	}
}

impl<'a> Seek for SchemaWriter<'a> {
	fn tell(&self) -> IoResult<u64> {
		Ok(self.location)
	}

	fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
		println!("Seeking {}", pos);
		match style {
			SeekSet => {
				self.location = pos as u64;
				Ok(())
			}
			SeekEnd => {
				Err(IoError {
					kind: InvalidInput,
					desc: "seek to end not supported",
					detail: None,
				})
			}
			SeekCur => {
				self.location = (self.location as i64 + pos) as u64;
				Ok(())
			}
		}
	}
}

impl<'a> SchemaWriter<'a> {
	pub fn new<'b>(bufman: &'b mut buffer::BufferManager) -> SchemaWriter<'b> {
		SchemaWriter {buffer_manager: bufman, location: 0,
			maximum: 0}
	}

	pub fn get_data(&mut self) -> Vec<u8> {
		let pagelock = self.buffer_manager.fix_page(0).unwrap_or_else(
			|| fail!("Failed fixing 0 page for schema length"));
		let mut size;
		{
			let page = pagelock.read();
			let mut reader = BufReader::new(page.get_data());
			size = reader.read_le_u64().unwrap();
		}
		self.buffer_manager.unfix_page(pagelock, false);
		println!("Size: {}", size);

		let mut data: Vec<u8> = Vec::with_capacity(size as uint);
		let mut read = 0;

		println!("location: {}", self.location);
		for i in range(1, self.location / buffer::PAGE_SIZE as u64 + 2) {
			println!("Reading page {}", i);
			let pagelock = self.buffer_manager.fix_page(i).unwrap_or_else(
				|| fail!("Failed fixing page {}", i));
			{
				let page = pagelock.read();
				let content = page.get_data();
				let mut j = 0;
				while read < size {
					data.push(content[j]);
					j += 1;
					read += 1;
				}
			}
			self.buffer_manager.unfix_page(pagelock, false);
		}
		data
	}
}

impl Schema {
	pub fn new() -> Schema {
		Schema {relations: Vec::new()}
	}

	pub fn new_from_disk(bufmanager: &mut buffer::BufferManager) -> Schema {
		let mut wr = SchemaWriter::new(bufmanager);
		let data = wr.get_data();
		let ebml_doc = reader::Doc(data.as_slice());
		let mut deser = reader::Decoder(ebml_doc);
		let value: Schema = match Decodable::decode(&mut deser) {
			Ok(v) => v,
			Err(e) => fail!("Error decoding: {}", e),
		};
		value
	}

	pub fn add_relation(&mut self, relation: Relation) {
		self.relations.push(relation);
	}

	pub fn save_to_disk(&self, bufmanager: &mut buffer::BufferManager) {
		let mut wr = SchemaWriter::new(bufmanager);
		{
			let mut ebml_w = writer::Encoder(&mut wr);
			let _ = self.encode(&mut ebml_w);
		}
	}
}

struct Record {
	// TODO: do we even need this?
	len: uint,
	data: Vec<u8>,
}

impl Record {
	/* move semantics, no copy */
	pub fn new(len: uint, data: Vec<u8>) -> Record {
		Record {len: len, data: data}
	}

	pub fn get_data<'a>(&'a self) -> &'a [u8] {
		self.data.as_slice()
	}
}

struct SPSegment<'a> {
	id: u64,
	manager: &'a mut buffer::BufferManager,
}

struct SlottedPageHeader {
	slot_count: uint,
	free_slot: uint,
	data_start: uint,
	free_space: uint,
}

struct Slot(uint, uint);

struct SlottedPage {
	header: SlottedPageHeader,
	frame: Arc<RWLock<buffer::BufferFrame>>,
}

impl SlottedPage {
	pub fn new(frame: Arc<RWLock<buffer::BufferFrame>>) -> SlottedPage {
		let header = {
			let mut frame = frame.write();
			let mut br = BufReader::new(frame.get_data());
			let slot_count = br.read_le_uint().unwrap();
			let free_slot = br.read_le_uint().unwrap();
			let data_start = br.read_le_uint().unwrap();
			let free_space = br.read_le_uint().unwrap();

			if slot_count == 0 && free_space == 0 {
				// blank frame, construct header
				let slot_count = 0;
				let free_slot = 0;
				let data_start = buffer::PAGE_SIZE;
				let free_space = buffer::PAGE_SIZE - size_of::<SlottedPageHeader>();
				SlottedPageHeader {slot_count: slot_count,
					free_slot: free_slot, data_start: data_start,
					free_space: free_space}
			} else {
				SlottedPageHeader {slot_count: slot_count,
					free_slot: free_slot, data_start: data_start,
					free_space: free_space}
			}

		};
		println!("SlottedPageHeader: {:?}", header);
		SlottedPage {frame: frame, header: header}
	}

	fn write_header(&mut self) {
		let mut frame = self.frame.write();
		let mut bw = BufWriter::new(frame.get_mut_data());
		bw.write_le_uint(self.header.slot_count);
		bw.write_le_uint(self.header.free_slot);
		bw.write_le_uint(self.header.data_start);
		bw.write_le_uint(self.header.free_space);
	}

	fn try_insert(&mut self, r: &Record) -> (bool, uint) {
		println!("s.h.free_space {}", self.header.free_space);
		if self.header.free_space < r.len {
			return (false, 0)
		}
		// copy data from record to page
		self.header.data_start -= r.len;
		self.header.free_space -= r.len;
		let slot = Slot(self.header.data_start, r.len);
		{
			let mut frame = self.frame.write();
			let mut bw = BufWriter::new(frame.get_mut_data());
			// seek to place where we can store data
			bw.seek(self.header.data_start as i64, SeekSet);
			// copy it over from record
			bw.write(r.get_data());
			// seek to beginning of slot storage
			bw.seek((size_of::<SlottedPageHeader>() +
				self.header.slot_count * size_of::<Slot>()) as i64,
				SeekSet);
			// write out slot
			let Slot(offset, len) = slot;
			bw.write_le_uint(offset);
			bw.write_le_uint(len);
		}
		let res = (true, self.header.slot_count);
		self.header.free_slot += 1;
		self.header.slot_count += 1;

		self.write_header();
		res
	}
}

struct TID {
	page_id: u64,
	slot_id: uint,
}

fn join_segment(segment: u64, page: u64) -> u64{
	(segment << 48) & page
}

impl<'a> SPSegment<'a> {
	pub fn insert(&mut self, r: &Record) -> TID {
		let mut tid = TID {page_id: 0, slot_id: 0};
		println!("inserting")
		for i in range(1, 1<<48) {
			println!("Testing {}", i);
			let pagelock = match self.manager.fix_page(join_segment(self.id, i as u64)) {
				Some(p) => p,
				None => fail!("Failed aquiring page {}", i),
			};
			let mut sp = SlottedPage::new(pagelock.clone());
			let (inserted, slot) = sp.try_insert(r);
			println!("try_insert: {}", inserted);
			self.manager.unfix_page(pagelock, inserted);
			if inserted {
				tid = TID {page_id: i as u64, slot_id: slot};
				break;
			}
			break;
		}
		tid
	}

	pub fn remove(tid: TID) -> bool {
		false
	}

	pub fn lookup(tid: TID) -> Record {
		// TODO
		Record {len: 1, data: vec!(1)}
	}

	pub fn update(tid: TID, r: Record) -> bool {
		false
	}
}

#[test]
fn main() {
}

#[test]
fn create_schema() {
	let name = Column {name: ~"name", datatype: Varchar(128), attributes: vec!(NotNull)};
	let age = Column {name: ~"age", datatype: Integer, attributes: vec!(NotNull)};
	let mut relation = Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	let mut schema = Schema::new();
	schema.add_relation(relation);

	let mut manager = buffer::BufferManager::new(1024, Path::new("."));
	schema.save_to_disk(&mut manager);
	let new_schema = Schema::new_from_disk(&mut manager);
	println!("new_schema == {:?}", new_schema);
	assert!(false);
}

#[test]
fn slotted_page_create() {
	let mut manager = buffer::BufferManager::new(1024, Path::new("."));
	let mut seg = SPSegment {id: 1, manager: &mut manager};
	let rec = Record {len: 1, data: vec!(42)};
	let tid = seg.insert(&rec);
	println!("TID: {:?}", tid);
	assert!(false);
}
<|endoftext|>


<commit_before>use configuration::Configuration;
use std::slice::SliceExt;
use std::cmp::Ordering;
use score::Score;

pub struct Search {
    pub config: Configuration,
    current: usize,
    pub query: String,
    pub selection: Option<String>,
    pub result: Vec<String>,
}

impl Search {
    pub fn blank(config: Configuration) -> Search {
        let query = config.initial_search.clone();
        let previous_result = config.choices.clone();
        Search::new(config, query, previous_result, 0)
    }

    fn new(config: Configuration, query: String, result: Vec<String>, index: usize) -> Search {

        let selection = Search::select(&result, index);

        Search { config: config,
                 current: index,
                 query: query,
                 selection: selection,
                 result: result }
    }

    fn new_for_index(self, index: usize) -> Search {
        Search::new(self.config, self.query, self.result, index)
    }

    fn new_for_query(self, new_query: String) -> Search {
        let new_result = Search::filter(new_query.as_slice(), &self.config.choices);

        Search::new(self.config, new_query, new_result, self.current)
    }

    fn filter(query: &str, choices: &Vec<String>) -> Vec<String> {
        let mut filtered = choices.iter().filter_map( |choice| {
            let quality = Score::score(choice.as_slice(), query);
            if quality > 0.0 {
                Some((quality, choice.to_string()))
            } else {
                None
            }
        }).collect::<Vec<(f32, String)>>();

        filtered.sort_by( |&(quality_a, _), &(quality_b, _)| {
            quality_a.partial_cmp(&quality_b).unwrap_or(Ordering::Equal).reverse()
        });

        filtered.iter().map( |&(_, ref choice)| choice.to_string() ).collect::<Vec<String>>()
    }

    fn select(result: &Vec<String>, index: usize) -> Option<String> {
        if result.len() > 0 {
            Some(result[index].to_string())
        } else {
            None
        }
    }

    pub fn down(self) -> Search {
        let next_index = self.next_index();
        self.new_for_index(next_index)
    }

    fn up(self) -> Search {
        let next_index = self.prev_index();
        self.new_for_index(next_index)
    }

    pub fn append_to_search(self, input: &str) -> Search {
        let mut new_query = self.query.clone();
        new_query.push_str(input.as_slice());

        self.new_for_query(new_query)
    }

    fn backspace(self) -> Search {
        let mut new_query = self.query.clone();
        new_query.pop();

        self.new_for_query(new_query).new_for_index(0)
    }

    fn next_index(&self) -> usize {
        let next_index = self.current + 1;

        if next_index >= self.config.visible_limit { 0 } else { next_index }
    }

    fn prev_index(&self) -> usize {
        if self.current == 0 { self.config.visible_limit - 1 } else  { self.current - 1 }
    }
}

#[cfg(test)]
fn one_two_three() -> Vec<String> {
    vec!["one".to_string(),
         "two".to_string(),
         "three".to_string()]
}

#[test]
fn it_selects_the_first_choice_by_default() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.selection, Some("one".to_string()));
}

#[test]
fn it_selets_the_second_when_down_is_called() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.down().selection, Some("two".to_string()));
}

#[test]
fn it_loop_around_when_reaching_end_of_list() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.down().down().down().down().selection, Some("two".to_string()));
}

#[test]
fn it_loop_around_when_reaching_top_of_list() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.up().up().selection, Some("two".to_string()));
}

#[test]
fn it_loop_around_when_reaching_visible_limit() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, Some(2));
    let search = Search::blank(config);
    assert_eq!(search.down().down().down().selection, Some("two".to_string()));
}

#[test]
fn it_moves_down_the_filtered_search_results() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.append_to_search("t").down().selection, Some("three".to_string()));
}

#[test]
fn it_moves_down_the_filtered_search_results_twice() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.append_to_search("t").append_to_search("w").selection, Some("two".to_string()));
}

#[test]
fn it_handles_not_matching_anything() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.append_to_search("x").selection, None);
}

#[test]
fn up_match_nothing_after_filtering_all_out() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config).append_to_search("x");

    assert_eq!(search.up().selection, None);
}

#[test]
fn down_match_nothing_after_filtering_all_out() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config).append_to_search("x");

    assert_eq!(search.down().selection, None);
}

#[test]
fn backspaces_over_characters() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config).append_to_search("e");

    assert_eq!(search.query, "e");
    assert_eq!(search.backspace().query, "");
}

#[test]
fn resets_the_index() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config).append_to_search("e");

    assert_eq!(search.down().backspace().current, 0);
}

#[test]
fn previous_results_appear_after_backspace() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config).append_to_search("t");

    assert_eq!(search.backspace().result.len(), 3);
}
<commit_msg>A search can now be finished<commit_after>use configuration::Configuration;
use std::slice::SliceExt;
use std::cmp::Ordering;
use score::Score;

#[derive(Show)]
pub struct Search {
    pub config: Configuration,
    current: usize,
    pub query: String,
    pub selection: Option<String>,
    pub result: Vec<String>,
    done: bool,
}

impl Search {
    pub fn blank(config: Configuration) -> Search {
        let query = config.initial_search.clone();
        let previous_result = config.choices.clone();
        Search::new(config, query, previous_result, 0, false)
    }

    pub fn is_done(&self) -> bool {
        self.done
    }

    pub fn abort(self) -> Search {
        let mut search = Search::new(self.config, self.query, self.result, self.current, true);
        search.selection = None;
        search
    }

    pub fn done(self) -> Search {
        self.abort()
    }

    fn new(config: Configuration, query: String, result: Vec<String>, index: usize, done: bool) -> Search {

        let selection = Search::select(&result, index);

        Search { config: config,
                 current: index,
                 query: query,
                 selection: selection,
                 result: result,
                 done: done}
    }

    fn new_for_index(self, index: usize) -> Search {
        Search::new(self.config, self.query, self.result, index, self.done)
    }

    fn new_for_query(self, new_query: String) -> Search {
        let new_result = Search::filter(new_query.as_slice(), &self.config.choices);

        Search::new(self.config, new_query, new_result, self.current, self.done)
    }

    fn filter(query: &str, choices: &Vec<String>) -> Vec<String> {
        let mut filtered = choices.iter().filter_map( |choice| {
            let quality = Score::score(choice.as_slice(), query);
            if quality > 0.0 {
                Some((quality, choice.to_string()))
            } else {
                None
            }
        }).collect::<Vec<(f32, String)>>();

        filtered.sort_by( |&(quality_a, _), &(quality_b, _)| {
            quality_a.partial_cmp(&quality_b).unwrap_or(Ordering::Equal).reverse()
        });

        filtered.iter().map( |&(_, ref choice)| choice.to_string() ).collect::<Vec<String>>()
    }

    fn select(result: &Vec<String>, index: usize) -> Option<String> {
        if result.len() > 0 {
            Some(result[index].to_string())
        } else {
            None
        }
    }

    pub fn down(self) -> Search {
        let next_index = self.next_index();
        self.new_for_index(next_index)
    }

    fn up(self) -> Search {
        let next_index = self.prev_index();
        self.new_for_index(next_index)
    }

    pub fn append_to_search(self, input: &str) -> Search {
        let mut new_query = self.query.clone();
        new_query.push_str(input.as_slice());

        self.new_for_query(new_query)
    }

    fn backspace(self) -> Search {
        let mut new_query = self.query.clone();
        new_query.pop();

        self.new_for_query(new_query).new_for_index(0)
    }

    fn next_index(&self) -> usize {
        let next_index = self.current + 1;

        if next_index >= self.config.visible_limit { 0 } else { next_index }
    }

    fn prev_index(&self) -> usize {
        if self.current == 0 { self.config.visible_limit - 1 } else  { self.current - 1 }
    }
}

#[cfg(test)]
fn one_two_three() -> Vec<String> {
    vec!["one".to_string(),
         "two".to_string(),
         "three".to_string()]
}

#[test]
fn it_selects_the_first_choice_by_default() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.selection, Some("one".to_string()));
}

#[test]
fn it_selets_the_second_when_down_is_called() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.down().selection, Some("two".to_string()));
}

#[test]
fn it_loop_around_when_reaching_end_of_list() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.down().down().down().down().selection, Some("two".to_string()));
}

#[test]
fn it_loop_around_when_reaching_top_of_list() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.up().up().selection, Some("two".to_string()));
}

#[test]
fn it_loop_around_when_reaching_visible_limit() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, Some(2));
    let search = Search::blank(config);
    assert_eq!(search.down().down().down().selection, Some("two".to_string()));
}

#[test]
fn it_moves_down_the_filtered_search_results() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.append_to_search("t").down().selection, Some("three".to_string()));
}

#[test]
fn it_moves_down_the_filtered_search_results_twice() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.append_to_search("t").append_to_search("w").selection, Some("two".to_string()));
}

#[test]
fn it_handles_not_matching_anything() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.append_to_search("x").selection, None);
}

#[test]
fn up_match_nothing_after_filtering_all_out() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config).append_to_search("x");

    assert_eq!(search.up().selection, None);
}

#[test]
fn down_match_nothing_after_filtering_all_out() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config).append_to_search("x");

    assert_eq!(search.down().selection, None);
}

#[test]
fn backspaces_over_characters() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config).append_to_search("e");

    assert_eq!(search.query, "e");
    assert_eq!(search.backspace().query, "");
}

#[test]
fn resets_the_index() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config).append_to_search("e");

    assert_eq!(search.down().backspace().current, 0);
}

#[test]
fn previous_results_appear_after_backspace() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config).append_to_search("t");

    assert_eq!(search.backspace().result.len(), 3);
}

#[test]
fn initial_search_is_not_done() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);

    assert!(!search.is_done());
}

#[test]
fn aborted_search_is_done() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config).abort();

    assert!(search.is_done());
}

#[test]
fn done_search_is_done() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config).done();

    assert!(search.is_done());
}

#[test]
fn aborted_search_has_no_selection() {
    let input = one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config).abort();

    assert_eq!(search.selection, None);
}
<|endoftext|>