<commit_before>use redox::*;

// TODO: Structure using loops
// TODO: Make capital commands doing the reverse of the command
//       Y: Yank before the cursor
//       D: Delete before the cursor.

use super::Mode;
use super::Mode::*;
use super::Editor;

// TODO: Move vars to `Editor`
pub fn exec(editor: &mut Editor, mode: &mut Mode, multiplier: &mut Option<u32>, last_change: &mut String, key_event: KeyEvent, window: &mut Window, swap: &mut usize, period: &mut String, is_recording: &mut bool, clipboard: &mut String) {
    match (*mode, key_event.scancode) {
        (Insert, K_ESC) => {
            *mode = Normal;
        },
        (Insert, K_BKSP) => editor.backspace(window),
        (Insert, K_DEL) => editor.delete(window),
        (_, K_F5) => editor.reload(window),
        (_, K_F6) => editor.save(window),
        (_, K_HOME) => editor.offset = 0,
        (_, K_UP) => editor.up(),
        (_, K_LEFT) => editor.left(),
        (_, K_RIGHT) => editor.right(),
        (_, K_END) => editor.offset = editor.string.len(),
        (_, K_DOWN) => editor.down(),
        (m, _) => {
            let (no_mult, mut times) = match *multiplier {
                Some(n) => (false, n),
                None => (true, 1),
            };
            let mut is_none = false;

            match (*mode, key_event.character) {
                (Normal, '0') if !no_mult => times *= 10,

                (Normal, '1') if no_mult => times = 1,
                (Normal, '1') => times = times * 10 + 1,

                (Normal, '2') if no_mult => times = 2,
                (Normal, '2') => times = times * 10 + 2,

                (Normal, '3') if no_mult => times = 3,
                (Normal, '3') => times = times * 10 + 3,

                (Normal, '4') if no_mult => times = 4,
                (Normal, '4') => times = times * 10 + 4,

                (Normal, '5') if no_mult => times = 5,
                (Normal, '5') => times = times * 10 + 5,

                (Normal, '6') if no_mult => times = 6,
                (Normal, '6') => times = times * 10 + 6,

                (Normal, '7') if no_mult => times = 7,
                (Normal, '7') => times = times * 10 + 7,

                (Normal, '8') if no_mult => times = 8,
                (Normal, '8') => times = times * 10 + 8,

                (Normal, '9') if no_mult => times = 9,
                (Normal, '9') => times = times * 10 + 9,
                (_, _) => {
                    if *is_recording {
                        if key_event.character == ',' {
                            *is_recording = false;
                        } else {
                            period.push(key_event.character);
                        }
                    } else {
                        for _ in 0 .. times {
                            match (m, key_event.character) {
                                (Normal, 'i') => {
                                    *mode = Insert;
                                    *last_change = editor.string.clone();
                                },
                                (Normal, 'h') => editor.left(),
                                (Normal, 'l') => editor.right(),
                                (Normal, 'k') | (Normal, ' ') => editor.up(),
                                (Normal, 'j') | (Normal, '\n') => editor.down(),
                                (Normal, 'K') => {
                                    for _ in 1..15 {
                                        editor.up();
                                    }
                                },
                                (Normal, 'J') => {
                                    for _ in 1..15 {
                                        editor.down();
                                    }
                                },
                                (Normal, 'g') => editor.offset = 0,
                                (Normal, 'G') => editor.offset = editor.string.len(),
                                (Normal, 'a') => {
                                    editor.right();
                                    *mode = Insert;
                                    *last_change = editor.string.clone();
                                },
                                (Normal, 'x') => editor.delete(window),
                                (Normal, 'X') => editor.backspace(window),
                                (Normal, 'u') => {
                                    editor.offset = 0;
                                    ::core::mem::swap(last_change, &mut editor.string);
                                },
                                (Normal, 'c') => {
                                    ::core::mem::swap(&mut editor.offset, swap);
                                },
                                (Normal, 'z') => {
                                    *clipboard = String::new();
                                    while editor.cur() != '\n' &&
                                          editor.offset < editor.string.len() {
                                        *clipboard = clipboard.clone().to_string() + &editor.cur().to_string();
                                        editor.delete(window);
                                    }
                                },
                                (Normal, 'Z') => {
                                    *clipboard = String::new();
                                    while editor.cur() != '\n' &&
                                          editor.offset >= 0 {
                                        clipboard.push(editor.cur());
                                        editor.backspace(window);
                                        editor.left();
                                    }
                                    editor.right();
                                },
                                (Normal, 's') => {
                                    editor.delete(window);
                                    *mode = Insert;
                                },
                                (Normal, 'o') => {
                                    while editor.cur() != '\n' &&
                                          editor.cur() != '\0' &&
                                          editor.offset < editor.string.len() {
                                        editor.right();
                                    }
                                    editor.insert('\n', window);
                                    *mode = Insert;
                                },
                                (Normal, 'O') => {
                                    while editor.cur() != '\n' &&
                                          editor.cur() != '\0' &&
                                          editor.offset >= 1 {
                                        editor.left();
                                    }
                                    editor.insert('\n', window);
                                    editor.left();
                                    *mode = Insert;
                                },
                                (Normal, '^') => {
                                    while editor.cur() != '\n' &&
                                          editor.cur() != '\0' &&
                                          editor.offset <= 0 {
                                        editor.left();
                                    }
                                    editor.right();
                                    while (editor.cur() == ' ' ||
                                          editor.cur() == '\t') &&
                                          editor.offset < editor.string.len() {
                                        editor.right();
                                    }
                                },
                                (Normal, 'y') => {
                                    *clipboard = String::new();
                                    let mut mov = 1;
                                    while editor.cur() != '\n' &&
                                          editor.offset < editor.string.len() {
                                        clipboard.push(editor.cur());
                                        editor.right();
                                        mov += 1;
                                    }

                                    for _ in 1..mov {
                                        editor.left();
                                    }
                                },
                                (Normal, 'Y') => {
                                    *clipboard = String::new();
                                    let mut mov = 1;
                                    while editor.cur() != '\n' &&
                                          editor.offset < editor.string.len() {
                                        *clipboard = editor.cur().to_string() + clipboard;
                                        editor.left();
                                        mov += 1;
                                    }

                                    for _ in 1..mov {
                                        editor.right();
                                    }
                                },
                                (Normal, 'p') => {
                                    for c in clipboard.chars() {
                                        editor.insert(c, window);
                                    }
                                },
                                (Normal, '$') => {
                                    while editor.cur() != '\n' &&
                                          editor.cur() != '\0' &&
                                          editor.offset < editor.string.len() {
                                        editor.right();
                                    }
                                },
                                (Normal,  '0') => {
                                    editor.left();
                                    while editor.cur() != '\n' &&
                                          editor.cur() != '\0' &&
                                          editor.offset >= 1 {
                                        editor.left();
                                    }
                                    editor.right();
                                },
                                (Normal, 'd') => {
                                    while editor.cur() != '\n' &&
                                          editor.cur() != '\0' &&
                                          editor.offset < editor.string.len() {
                                        editor.delete(window);
                                    }
                                },
                                (Normal, 'D') => {
                                    while editor.cur() != '\n' &&
                                          editor.cur() != '\0' &&
                                          editor.offset >= 1 {
                                        editor.backspace(window);
                                        editor.left();
                                    }
                                    editor.right();
                                },
                                (Normal, 'w') => {
                                    editor.save(window);
                                },
                                (Normal, 'e') => {
                                    editor.right();
                                    while editor.cur() != '.' &&
                                          editor.cur() != '{' &&
                                          editor.cur() != ',' &&
                                          editor.cur() != ' ' &&
                                          editor.cur() != '}' &&
                                          editor.cur() != '(' &&
                                          editor.cur() != ')' &&
                                          editor.cur() != '[' &&
                                          editor.cur() != ']' &&
                                          editor.cur() != ';' &&
                                          editor.cur() != '"' &&
                                          editor.cur() != '\'' &&
                                          editor.cur() != '\n' &&
                                          editor.offset < editor.string.len() {
                                        editor.right();
                                    }
                                },
                                (Normal, 'b') => {
                                    editor.left();
                                    while editor.cur() != '.' &&
                                          editor.cur() != '{' &&
                                          editor.cur() != ',' &&
                                          editor.cur() != ' ' &&
                                          editor.cur() != '}' &&
                                          editor.cur() != '(' &&
                                          editor.cur() != ')' &&
                                          editor.cur() != '[' &&
                                          editor.cur() != ']' &&
                                          editor.cur() != ';' &&
                                          editor.cur() != '"' &&
                                          editor.cur() != '\'' &&
                                          editor.cur() != '\n' &&
                                          editor.offset >= 1 {
                                        editor.left();
                                    }
                                },
                                (Normal, 'E') => {
                                    editor.right();
                                    while editor.cur() != ' ' && editor.offset < editor.string.len() {
                                        editor.right();
                                    }
                                },
                                (Normal, 'B') => {
                                    editor.left();
                                    while editor.cur() != ' ' && editor.offset >= 1 {
                                        editor.left();
                                    }
                                },
                                (Normal, ',') => {
                                    *is_recording = true;
                                    *period = String::new();
                                },
                                (Normal, '%') => {
                                    match editor.cur() {
                                        '(' | '[' | '{' => {
                                            let mut i = 1;
                                            while i != 0 {
                                                editor.right();
                                                i += match editor.cur() {
                                                    '(' | '[' | '{' => 1,
                                                    ')' | ']' | '}' => -1,
                                                    _ => 0,
                                                };
                                                if editor.offset < editor.string.len() {
                                                    break;
                                                }
                                            }
                                        },
                                        ')' | ']' | '}' => {
                                            let mut i = 1;
                                            while i != 0 {
                                                editor.left();
                                                i += match editor.cur() {
                                                    '(' | '[' | '{' => -1,
                                                    ')' | ']' | '}' => 1,
                                                    _ => 0,
                                                };
                                                if editor.offset >= 1 {
                                                    break;
                                                }
                                            }
                                        },
                                        _ => {},

                                    }
                                },
                                (Normal, '!') => {
                                    for c in period.clone().chars() {
                                        exec(editor, mode, multiplier, last_change, KeyEvent {
                                            character: c,
                                            scancode: 0,
                                            pressed: true,
                                        }, window, swap, period, is_recording, clipboard);
                                    }
                                },
                                (Insert, '\0') => (),
                                (Insert, c) => {
                                    editor.insert(c, window);
                                },
                                _ => {},
                            }
                        }
                    }
                    is_none = true;
                }
            }

            if !is_none {
                *multiplier = Some(times);
            } else {
                *multiplier = None;
            }
        }
    }
}
<commit_msg>Make ^ command better<commit_after>use redox::*;

// TODO: Structure using loops
// TODO: Make capital commands doing the reverse of the command
//       Y: Yank before the cursor
//       D: Delete before the cursor.

use super::Mode;
use super::Mode::*;
use super::Editor;

// TODO: Move vars to `Editor`
pub fn exec(editor: &mut Editor, mode: &mut Mode, multiplier: &mut Option<u32>, last_change: &mut String, key_event: KeyEvent, window: &mut Window, swap: &mut usize, period: &mut String, is_recording: &mut bool, clipboard: &mut String) {
    match (*mode, key_event.scancode) {
        (Insert, K_ESC) => {
            *mode = Normal;
        },
        (Insert, K_BKSP) => editor.backspace(window),
        (Insert, K_DEL) => editor.delete(window),
        (_, K_F5) => editor.reload(window),
        (_, K_F6) => editor.save(window),
        (_, K_HOME) => editor.offset = 0,
        (_, K_UP) => editor.up(),
        (_, K_LEFT) => editor.left(),
        (_, K_RIGHT) => editor.right(),
        (_, K_END) => editor.offset = editor.string.len(),
        (_, K_DOWN) => editor.down(),
        (m, _) => {
            let (no_mult, mut times) = match *multiplier {
                Some(n) => (false, n),
                None => (true, 1),
            };
            let mut is_none = false;

            match (*mode, key_event.character) {
                (Normal, '0') if !no_mult => times *= 10,

                (Normal, '1') if no_mult => times = 1,
                (Normal, '1') => times = times * 10 + 1,

                (Normal, '2') if no_mult => times = 2,
                (Normal, '2') => times = times * 10 + 2,

                (Normal, '3') if no_mult => times = 3,
                (Normal, '3') => times = times * 10 + 3,

                (Normal, '4') if no_mult => times = 4,
                (Normal, '4') => times = times * 10 + 4,

                (Normal, '5') if no_mult => times = 5,
                (Normal, '5') => times = times * 10 + 5,

                (Normal, '6') if no_mult => times = 6,
                (Normal, '6') => times = times * 10 + 6,

                (Normal, '7') if no_mult => times = 7,
                (Normal, '7') => times = times * 10 + 7,

                (Normal, '8') if no_mult => times = 8,
                (Normal, '8') => times = times * 10 + 8,

                (Normal, '9') if no_mult => times = 9,
                (Normal, '9') => times = times * 10 + 9,
                (_, _) => {
                    if *is_recording {
                        if key_event.character == ',' {
                            *is_recording = false;
                        } else {
                            period.push(key_event.character);
                        }
                    } else {
                        for _ in 0 .. times {
                            match (m, key_event.character) {
                                (Normal, 'i') => {
                                    *mode = Insert;
                                    *last_change = editor.string.clone();
                                },
                                (Normal, 'h') => editor.left(),
                                (Normal, 'l') => editor.right(),
                                (Normal, 'k') | (Normal, ' ') => editor.up(),
                                (Normal, 'j') | (Normal, '\n') => editor.down(),
                                (Normal, 'K') => {
                                    for _ in 1..15 {
                                        editor.up();
                                    }
                                },
                                (Normal, 'J') => {
                                    for _ in 1..15 {
                                        editor.down();
                                    }
                                },
                                (Normal, 'g') => editor.offset = 0,
                                (Normal, 'G') => editor.offset = editor.string.len(),
                                (Normal, 'a') => {
                                    editor.right();
                                    *mode = Insert;
                                    *last_change = editor.string.clone();
                                },
                                (Normal, 'x') => editor.delete(window),
                                (Normal, 'X') => editor.backspace(window),
                                (Normal, 'u') => {
                                    editor.offset = 0;
                                    ::core::mem::swap(last_change, &mut editor.string);
                                },
                                (Normal, 'c') => {
                                    ::core::mem::swap(&mut editor.offset, swap);
                                },
                                (Normal, 'z') => {
                                    *clipboard = String::new();
                                    while editor.cur() != '\n' &&
                                          editor.offset < editor.string.len() {
                                        *clipboard = clipboard.clone().to_string() + &editor.cur().to_string();
                                        editor.delete(window);
                                    }
                                },
                                (Normal, 'Z') => {
                                    *clipboard = String::new();
                                    while editor.cur() != '\n' &&
                                          editor.offset >= 0 {
                                        clipboard.push(editor.cur());
                                        editor.backspace(window);
                                        editor.left();
                                    }
                                    editor.right();
                                },
                                (Normal, 's') => {
                                    editor.delete(window);
                                    *mode = Insert;
                                },
                                (Normal, 'o') => {
                                    while editor.cur() != '\n' &&
                                          editor.cur() != '\0' &&
                                          editor.offset < editor.string.len() {
                                        editor.right();
                                    }
                                    editor.insert('\n', window);
                                    *mode = Insert;
                                },
                                (Normal, 'O') => {
                                    while editor.cur() != '\n' &&
                                          editor.cur() != '\0' &&
                                          editor.offset >= 1 {
                                        editor.left();
                                    }
                                    editor.insert('\n', window);
                                    editor.left();
                                    *mode = Insert;
                                },
                                (Normal, '^') => {
                                    editor.left();
                                    while editor.cur() != '\n' &&
                                          editor.cur() != '\0' &&
                                          editor.offset >= 0 {
                                        editor.left();
                                    }
                                    editor.right();
                                    while (editor.cur() == ' ' ||
                                          editor.cur() == '\t') &&
                                          editor.offset < editor.string.len() {
                                        editor.right();
                                    }
                                },
                                (Normal, 'y') => {
                                    *clipboard = String::new();
                                    let mut mov = 1;
                                    while editor.cur() != '\n' &&
                                          editor.offset < editor.string.len() {
                                        clipboard.push(editor.cur());
                                        editor.right();
                                        mov += 1;
                                    }

                                    for _ in 1..mov {
                                        editor.left();
                                    }
                                },
                                (Normal, 'Y') => {
                                    *clipboard = String::new();
                                    let mut mov = 1;
                                    while editor.cur() != '\n' &&
                                          editor.offset < editor.string.len() {
                                        *clipboard = editor.cur().to_string() + clipboard;
                                        editor.left();
                                        mov += 1;
                                    }

                                    for _ in 1..mov {
                                        editor.right();
                                    }
                                },
                                (Normal, 'p') => {
                                    for c in clipboard.chars() {
                                        editor.insert(c, window);
                                    }
                                },
                                (Normal, '$') => {
                                    while editor.cur() != '\n' &&
                                          editor.cur() != '\0' &&
                                          editor.offset < editor.string.len() {
                                        editor.right();
                                    }
                                },
                                (Normal,  '0') => {
                                    editor.left();
                                    while editor.cur() != '\n' &&
                                          editor.cur() != '\0' &&
                                          editor.offset >= 1 {
                                        editor.left();
                                    }
                                    editor.right();
                                },
                                (Normal, 'd') => {
                                    while editor.cur() != '\n' &&
                                          editor.cur() != '\0' &&
                                          editor.offset < editor.string.len() {
                                        editor.delete(window);
                                    }
                                },
                                (Normal, 'D') => {
                                    while editor.cur() != '\n' &&
                                          editor.cur() != '\0' &&
                                          editor.offset >= 1 {
                                        editor.backspace(window);
                                        editor.left();
                                    }
                                    editor.right();
                                },
                                (Normal, 'w') => {
                                    editor.save(window);
                                },
                                (Normal, 'e') => {
                                    editor.right();
                                    while editor.cur() != '.' &&
                                          editor.cur() != '{' &&
                                          editor.cur() != ',' &&
                                          editor.cur() != ' ' &&
                                          editor.cur() != '}' &&
                                          editor.cur() != '(' &&
                                          editor.cur() != ')' &&
                                          editor.cur() != '[' &&
                                          editor.cur() != ']' &&
                                          editor.cur() != ';' &&
                                          editor.cur() != '"' &&
                                          editor.cur() != '\'' &&
                                          editor.cur() != '\n' &&
                                          editor.offset < editor.string.len() {
                                        editor.right();
                                    }
                                },
                                (Normal, 'b') => {
                                    editor.left();
                                    while editor.cur() != '.' &&
                                          editor.cur() != '{' &&
                                          editor.cur() != ',' &&
                                          editor.cur() != ' ' &&
                                          editor.cur() != '}' &&
                                          editor.cur() != '(' &&
                                          editor.cur() != ')' &&
                                          editor.cur() != '[' &&
                                          editor.cur() != ']' &&
                                          editor.cur() != ';' &&
                                          editor.cur() != '"' &&
                                          editor.cur() != '\'' &&
                                          editor.cur() != '\n' &&
                                          editor.offset >= 1 {
                                        editor.left();
                                    }
                                },
                                (Normal, 'E') => {
                                    editor.right();
                                    while editor.cur() != ' ' && editor.offset < editor.string.len() {
                                        editor.right();
                                    }
                                },
                                (Normal, 'B') => {
                                    editor.left();
                                    while editor.cur() != ' ' && editor.offset >= 1 {
                                        editor.left();
                                    }
                                },
                                (Normal, ',') => {
                                    *is_recording = true;
                                    *period = String::new();
                                },
                                (Normal, '%') => {
                                    match editor.cur() {
                                        '(' | '[' | '{' => {
                                            let mut i = 1;
                                            while i != 0 {
                                                editor.right();
                                                i += match editor.cur() {
                                                    '(' | '[' | '{' => 1,
                                                    ')' | ']' | '}' => -1,
                                                    _ => 0,
                                                };
                                                if editor.offset < editor.string.len() {
                                                    break;
                                                }
                                            }
                                        },
                                        ')' | ']' | '}' => {
                                            let mut i = 1;
                                            while i != 0 {
                                                editor.left();
                                                i += match editor.cur() {
                                                    '(' | '[' | '{' => -1,
                                                    ')' | ']' | '}' => 1,
                                                    _ => 0,
                                                };
                                                if editor.offset >= 1 {
                                                    break;
                                                }
                                            }
                                        },
                                        _ => {},

                                    }
                                },
                                (Normal, '!') => {
                                    for c in period.clone().chars() {
                                        exec(editor, mode, multiplier, last_change, KeyEvent {
                                            character: c,
                                            scancode: 0,
                                            pressed: true,
                                        }, window, swap, period, is_recording, clipboard);
                                    }
                                },
                                (Insert, '\0') => (),
                                (Insert, c) => {
                                    editor.insert(c, window);
                                },
                                _ => {},
                            }
                        }
                    }
                    is_none = true;
                }
            }

            if !is_none {
                *multiplier = Some(times);
            } else {
                *multiplier = None;
            }
        }
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::fs::{File, OpenOptions, create_dir_all, remove_file, copy, rename};
use std::io::{Seek, SeekFrom, Read};
use std::path::{Path, PathBuf};

use error::{MapErrInto, StoreError as SE, StoreErrorKind as SEK};

use super::FileAbstraction;
use super::FileAbstractionInstance;
use super::Drain;
use store::Entry;
use storeid::StoreId;

#[derive(Debug)]
pub enum FSFileAbstractionInstance {
    Absent(PathBuf),
    File(File, PathBuf)
}

impl FileAbstractionInstance for FSFileAbstractionInstance {

    /**
     * Get the content behind this file
     */
    fn get_file_content(&mut self, id: StoreId) -> Result<Entry, SE> {
        debug!("Getting lazy file: {:?}", self);
        let (file, path) = match *self {
            FSFileAbstractionInstance::File(ref mut f, _) => return {
                // We seek to the beginning of the file since we expect each
                // access to the file to be in a different context
                try!(f.seek(SeekFrom::Start(0))
                    .map_err_into(SEK::FileNotSeeked));

                let mut s = String::new();
                f.read_to_string(&mut s)
                    .map_err_into(SEK::IoError)
                    .map(|_| s)
                    .and_then(|s| Entry::from_str(id, &s))
            },
            FSFileAbstractionInstance::Absent(ref p) =>
                (try!(open_file(p).map_err_into(SEK::FileNotFound)), p.clone()),
        };
        *self = FSFileAbstractionInstance::File(file, path);
        if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
            let mut s = String::new();
            f.read_to_string(&mut s)
                .map_err_into(SEK::IoError)
                .map(|_| s)
                .and_then(|s| Entry::from_str(id, &s))
        } else {
            unreachable!()
        }
    }

    /**
     * Write the content of this file
     */
    fn write_file_content(&mut self, buf: &Entry) -> Result<(), SE> {
        use std::io::Write;

        let buf = buf.to_str().into_bytes();

        let (file, path) = match *self {
            FSFileAbstractionInstance::File(ref mut f, _) => return {
                // We seek to the beginning of the file since we expect each
                // access to the file to be in a different context
                try!(f.seek(SeekFrom::Start(0))
                    .map_err_into(SEK::FileNotCreated));
                f.write_all(&buf).map_err_into(SEK::FileNotWritten)
            },
            FSFileAbstractionInstance::Absent(ref p) =>
                (try!(create_file(p).map_err_into(SEK::FileNotCreated)), p.clone()),
        };
        *self = FSFileAbstractionInstance::File(file, path);
        if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
            return f.write_all(&buf).map_err_into(SEK::FileNotWritten);
        }
        unreachable!();
    }

}

/// `FSFileAbstraction` state type
///
/// A lazy file is either absent, but a path to it is available, or it is present.
#[derive(Debug)]
pub struct FSFileAbstraction {
}

impl FSFileAbstraction {
    pub fn new() -> FSFileAbstraction {
        FSFileAbstraction { }
    }
}

impl FileAbstraction for FSFileAbstraction {

    fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
        remove_file(path).map_err_into(SEK::FileNotRemoved)
    }

    fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
        copy(from, to).map_err_into(SEK::FileNotCopied).map(|_| ())
    }

    fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
        rename(from, to).map_err_into(SEK::FileNotRenamed)
    }

    fn create_dir_all(&self, path: &PathBuf) -> Result<(), SE> {
        create_dir_all(path).map_err_into(SEK::DirNotCreated)
    }

    fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
        Box::new(FSFileAbstractionInstance::Absent(p))
    }

    /// We return nothing from the FS here.
    fn drain(&self) -> Result<Drain, SE> {
        Ok(Drain::empty())
    }

    /// FileAbstraction::fill implementation that consumes the Drain and writes everything to the
    /// filesystem
    fn fill(&mut self, mut d: Drain) -> Result<(), SE> {
        d.iter()
            .fold(Ok(()), |acc, (path, element)| {
                acc.and_then(|_| self.new_instance(path).write_file_content(&element))
            })
    }
}

fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    OpenOptions::new().write(true).read(true).open(p)
}

fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    if let Some(parent) = p.as_ref().parent() {
        debug!("Implicitely creating directory: {:?}", parent);
        if let Err(e) = create_dir_all(parent) {
            return Err(e);
        }
    }
    OpenOptions::new().write(true).read(true).create(true).open(p)
}

<commit_msg>Fix: Re-set file length before writing to it<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::fs::{File, OpenOptions, create_dir_all, remove_file, copy, rename};
use std::io::{Seek, SeekFrom, Read};
use std::path::{Path, PathBuf};

use error::{MapErrInto, StoreError as SE, StoreErrorKind as SEK};

use super::FileAbstraction;
use super::FileAbstractionInstance;
use super::Drain;
use store::Entry;
use storeid::StoreId;

#[derive(Debug)]
pub enum FSFileAbstractionInstance {
    Absent(PathBuf),
    File(File, PathBuf)
}

impl FileAbstractionInstance for FSFileAbstractionInstance {

    /**
     * Get the content behind this file
     */
    fn get_file_content(&mut self, id: StoreId) -> Result<Entry, SE> {
        debug!("Getting lazy file: {:?}", self);
        let (file, path) = match *self {
            FSFileAbstractionInstance::File(ref mut f, _) => return {
                // We seek to the beginning of the file since we expect each
                // access to the file to be in a different context
                try!(f.seek(SeekFrom::Start(0))
                    .map_err_into(SEK::FileNotSeeked));

                let mut s = String::new();
                f.read_to_string(&mut s)
                    .map_err_into(SEK::IoError)
                    .map(|_| s)
                    .and_then(|s| Entry::from_str(id, &s))
            },
            FSFileAbstractionInstance::Absent(ref p) =>
                (try!(open_file(p).map_err_into(SEK::FileNotFound)), p.clone()),
        };
        *self = FSFileAbstractionInstance::File(file, path);
        if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
            let mut s = String::new();
            f.read_to_string(&mut s)
                .map_err_into(SEK::IoError)
                .map(|_| s)
                .and_then(|s| Entry::from_str(id, &s))
        } else {
            unreachable!()
        }
    }

    /**
     * Write the content of this file
     */
    fn write_file_content(&mut self, buf: &Entry) -> Result<(), SE> {
        use std::io::Write;

        let buf = buf.to_str().into_bytes();

        let (file, path) = match *self {
            FSFileAbstractionInstance::File(ref mut f, _) => return {
                // We seek to the beginning of the file since we expect each
                // access to the file to be in a different context
                try!(f.seek(SeekFrom::Start(0))
                    .map_err_into(SEK::FileNotCreated));

                try!(f.set_len(buf.len() as u64).map_err_into(SEK::FileNotWritten));

                f.write_all(&buf).map_err_into(SEK::FileNotWritten)
            },
            FSFileAbstractionInstance::Absent(ref p) =>
                (try!(create_file(p).map_err_into(SEK::FileNotCreated)), p.clone()),
        };
        *self = FSFileAbstractionInstance::File(file, path);
        if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
            return f.write_all(&buf).map_err_into(SEK::FileNotWritten);
        }
        unreachable!();
    }

}

/// `FSFileAbstraction` state type
///
/// A lazy file is either absent, but a path to it is available, or it is present.
#[derive(Debug)]
pub struct FSFileAbstraction {
}

impl FSFileAbstraction {
    pub fn new() -> FSFileAbstraction {
        FSFileAbstraction { }
    }
}

impl FileAbstraction for FSFileAbstraction {

    fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
        remove_file(path).map_err_into(SEK::FileNotRemoved)
    }

    fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
        copy(from, to).map_err_into(SEK::FileNotCopied).map(|_| ())
    }

    fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
        rename(from, to).map_err_into(SEK::FileNotRenamed)
    }

    fn create_dir_all(&self, path: &PathBuf) -> Result<(), SE> {
        create_dir_all(path).map_err_into(SEK::DirNotCreated)
    }

    fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
        Box::new(FSFileAbstractionInstance::Absent(p))
    }

    /// We return nothing from the FS here.
    fn drain(&self) -> Result<Drain, SE> {
        Ok(Drain::empty())
    }

    /// FileAbstraction::fill implementation that consumes the Drain and writes everything to the
    /// filesystem
    fn fill(&mut self, mut d: Drain) -> Result<(), SE> {
        d.iter()
            .fold(Ok(()), |acc, (path, element)| {
                acc.and_then(|_| self.new_instance(path).write_file_content(&element))
            })
    }
}

fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    OpenOptions::new().write(true).read(true).open(p)
}

fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    if let Some(parent) = p.as_ref().parent() {
        debug!("Implicitely creating directory: {:?}", parent);
        if let Err(e) = create_dir_all(parent) {
            return Err(e);
        }
    }
    OpenOptions::new().write(true).read(true).create(true).open(p)
}

<|endoftext|>


<commit_before><commit_msg>Make code more idomatic<commit_after><|endoftext|>


<commit_before><commit_msg>add refactored testimage generator<commit_after>use std::ops::Range;
use std::iter::{Map, Rev, once, Once, Chain, Zip};

extern crate nalgebra;
use self::nalgebra::{DMat};

extern crate num;
use self::num::traits::{Zero, One};

pub type HorizontalReturnT<T> = Map<Range<usize>, fn(usize) -> T>;
pub type VerticalReturnT<T> = Map<Rev<Range<usize>>, fn(usize) -> T>;
pub type StaticReturnT<T> = Chain<Chain<Chain<Once<T>, VerticalReturnT<T>>, Once<T>>, HorizontalReturnT<T>>;
pub type TestReturnT<T> = Map<Zip<HorizontalReturnT<T>, VerticalReturnT<T>>, fn((T, T)) -> T>;

/// returns a matrix that has `1` in `row` for all `cols` and `0` everywhere else
///
/// ```
/// horizontal_line(9, 0..5);
/// ```
fn horizontal_line<T, I>(row: usize, cols: I) -> DMat<T>
    where T: Clone + Copy + Zero + One,
          I: Iterator<Item = usize>
{
    let mut factor: DMat<T> = DMat::new_zeros(10, 10);
    for col in cols {
        factor[(row, col)] = T::one();
    }
    factor
}

fn horizontal_evolving_factors<T>() -> HorizontalReturnT<DMat<T>>
    where T: Clone + Copy + Zero + One
{
    fn helper<U: Clone + Copy + Zero + One>(start_col: usize) -> DMat<U> {
        horizontal_line(9, start_col..(start_col + 5))
    }
    (0..6).map(helper)
}

/// returns a matrix that has `1` in `col` for all `rows` and `0` everywhere else
///
/// ```
/// vertical_line(5..10, 0);
/// ```
fn vertical_line<T, I>(rows: I, col: usize) -> DMat<T>
    where T: Clone + Copy + Zero + One,
          I: Iterator<Item = usize>
{
    let mut factor: DMat<T> = DMat::new_zeros(10, 10);
    for row in rows {
        factor[(row, col)] = T::one();
    }
    factor
}

fn vertical_evolving_factors<T>() -> VerticalReturnT<DMat<T>>
    where T: Clone + Copy + Zero + One
{
    fn helper<U: Clone + Copy + Zero + One>(start_row: usize) -> DMat<U> {
        vertical_line(start_row..(start_row + 5), 0)
    }
    (0..6).rev().map(helper)
}

fn static_factors<T>() -> StaticReturnT<DMat<T>>
    where T: Clone + Copy + Zero + One
{
    fn helper_horizontal<U: Clone + Copy + Zero + One>(row: usize) -> DMat<U> {
        horizontal_line(row, 0..10)
    }
    fn helper_vertical<U: Clone + Copy + Zero + One>(col: usize) -> DMat<U> {
        vertical_line(0..10, col)
    }
    once(horizontal_line(9, 0..5))
        .chain((0..9).rev().map(helper_horizontal as fn(usize) -> DMat<T>))
        .chain(once(vertical_line(5..10, 0)))
        .chain((1..10).map(helper_vertical as fn(usize) -> DMat<T>))
}
<|endoftext|>


<commit_before><commit_msg>Index message stats by key.<commit_after><|endoftext|>


<commit_before>use collections::VecDeque;
// Temporary hack until libredox get hashmaps
use redox::*;

#[derive(Clone, PartialEq, Copy, Hash)]
pub enum InsertMode {
    Append,
    Insert,
    Replace,
}

#[derive(Clone, PartialEq, Copy, Hash)]
pub struct InsertOptions {
    mode: InsertMode,
}

/// A mode
#[derive(Clone, PartialEq, Copy, Hash)]
pub enum Mode {
    /// A primitive mode (no repeat, no delimiters, no preprocessing)
    Primitive(PrimitiveMode),
    /// Command mode
    Command(CommandMode),
}

#[derive(Clone, PartialEq, Copy, Hash)]
/// A command mode
pub enum CommandMode {
//    Visual(VisualOptions),
    /// Normal mode
    Normal,
}

#[derive(Clone, PartialEq, Copy, Hash)]
/// A primitive mode
pub enum PrimitiveMode {
    /// Insert mode
    Insert(InsertOptions),
}

#[derive(Clone, PartialEq, Hash)]
pub enum Unit {
    /// Single [repeated] instruction
    Inst(u16, char),
    /// Multiple instructions
    Block(u16, Vec<Unit>),
}

#[derive(Clone, PartialEq, Hash)]
/// The state of the editor
pub struct State {
    /// The current cursor
    pub current_cursor: u8,
    /// The cursors
    pub cursors: Vec<Cursor>,
    /// The text (document)
    pub text: VecDeque<VecDeque<char>>,
    /// The x coordinate of the scroll
    pub scroll_x: u32,
    /// The y coordinate of the scroll
    pub scroll_y: u32,
}

impl State {
    fn insert(&mut self, c: char) {

    }
    fn new() -> State {
        State {
            current_cursor: 0,
            cursors: Vec::new(),
            text: VecDeque::new(),
            scroll_x: 0,
            scroll_y: 0,
        }
    }
}

/// A command char
#[derive(Clone, Copy, Hash, PartialEq)]
pub enum CommandChar {
    /// A char
    Char(char),
    /// A wildcard
    Wildcard,
}

/// The editor
pub struct Editor {
    /// The state of the editor
    pub state: State,
}

impl Editor {
    pub fn new() -> Self {
        Editor {
            state: State::new(),
        }
    }

    pub fn exec(&mut self, cmd: &Unit) {

        match *cmd {
            Unit::Inst(n, ref c) => {
                // Execute commands
            },
            Unit::Block(n, ref units) => {
                for _ in 1..n {
                    for i in units {
                        self.exec(&i);
                    }
                }
            },
        }
    }
}

#[derive(Clone, PartialEq, Hash)]
/// A cursor
pub struct Cursor {
    /// The x coordinate of the cursor
    pub x: u32,
    /// The y coordinate of the cursor
    pub y: u32,
    /// The mode of the cursor
    pub mode: Mode,
    /// The history of the cursor
    pub history: Vec<Unit>,
}

/// An iterator over units
pub struct UnitIterator<'a, I: Iterator<Item = char> + 'a> {
    /// The iterator over the chars
    char_iter: &'a mut I,
    /// The state
    state: &'a mut State,
}

impl<'a, I: Iterator<Item = char> + 'a> Iterator for UnitIterator<'a, I> {
    type Item = Unit;

    fn next(&mut self) -> Option<Unit> {
        match self.state.cursors[self.state.current_cursor as usize].mode {
            Mode::Primitive(_) => Some(Unit::Inst(1, match self.char_iter.next() {
                Some(c) => c,
                None => return None,
            })),
            Mode::Command(_) => {
                let mut ch = self.char_iter.next().unwrap_or('\0');
                let mut n = 1;

                let mut unset = true;
                for c in self.char_iter {
                    n = match c {
                        '0' if n != 0 => n * 10,
                        '1'           => n * 10 + 1,
                        '2'           => n * 10 + 2,
                        '3'           => n * 10 + 3,
                        '4'           => n * 10 + 4,
                        '5'           => n * 10 + 5,
                        '6'           => n * 10 + 6,
                        '7'           => n * 10 + 7,
                        '8'           => n * 10 + 8,
                        '9'           => n * 10 + 9,
                        r             => {
                            ch = r;
                            break;
                        },
                    };

                    if unset {
                        unset = false;
                        n     = 0;
                    }
                }

                if ch == '(' {
                    let mut level = 0;
                    let mut vec = self.char_iter.take_while(|c| {
                        level = match *c {
                            '(' => level + 1,
                            ')' => level - 1,
                            ';' => 0,
                            _ => level,
                        };
                        level != 0
                    }).skip(1).collect::<Vec<_>>();
                    vec.pop();
                    Some(Unit::Block(n, vec.into_iter().unit_iter(&mut self.state).collect()))
                } else if let Some(ch) = self.char_iter.next() {
                    Some(Unit::Inst(n, ch))
                } else {
                    None
                }
            }
        }
    }
}

pub trait ToUnitIterator<'a>: Iterator<Item = char> + 'a {
    /// Create a iterator of the unit given by the chars
    fn unit_iter(&'a mut self, state: &'a mut State) -> UnitIterator<'a, Self>;
}

impl<'a, I: Iterator<Item = char> + 'a> ToUnitIterator<'a> for I {
    fn unit_iter(&'a mut self, state: &'a mut State) -> UnitIterator<'a, I> {
        UnitIterator {
            char_iter: self,
            state: state,
        }
    }
}
<commit_msg>Simplify structure<commit_after>use collections::VecDeque;
// Temporary hack until libredox get hashmaps
use redox::*;

#[derive(Clone, PartialEq, Copy, Hash)]
pub enum InsertMode {
    Append,
    Insert,
    Replace,
}

#[derive(Clone, PartialEq, Copy, Hash)]
pub struct InsertOptions {
    mode: InsertMode,
}

/// A mode
#[derive(Clone, PartialEq, Copy, Hash)]
pub enum Mode {
    /// A primitive mode (no repeat, no delimiters, no preprocessing)
    Primitive(PrimitiveMode),
    /// Command mode
    Command(CommandMode),
}

#[derive(Clone, PartialEq, Copy, Hash)]
/// A command mode
pub enum CommandMode {
//    Visual(VisualOptions),
    /// Normal mode
    Normal,
}

#[derive(Clone, PartialEq, Copy, Hash)]
/// A primitive mode
pub enum PrimitiveMode {
    /// Insert mode
    Insert(InsertOptions),
}

#[derive(Clone, PartialEq, Hash)]
/// The state of the editor
pub struct State {
    /// The current cursor
    pub current_cursor: u8,
    /// The cursors
    pub cursors: Vec<Cursor>,
    /// The text (document)
    pub text: VecDeque<VecDeque<char>>,
    /// The x coordinate of the scroll
    pub scroll_x: u32,
    /// The y coordinate of the scroll
    pub scroll_y: u32,
    /// Number of repeation entered
    pub n: u16,
}

impl State {
    fn insert(&mut self, c: char) {

    }
    fn new() -> State {
        State {
            current_cursor: 0,
            cursors: Vec::new(),
            text: VecDeque::new(),
            scroll_x: 0,
            scroll_y: 0,
        }
    }
}

/// A command char
#[derive(Clone, Copy, Hash, PartialEq)]
pub enum CommandChar {
    /// A char
    Char(char),
    /// A wildcard
    Wildcard,
}

/// The editor
pub struct Editor {
    /// The state of the editor
    pub state: State,
}

impl Editor {
    pub fn new() -> Self {
        Editor {
            state: State::new(),
        }
    }

    /// Execute a instruction n times
    pub fn exec(&mut self, n: u16, cmd: char) {

        match cmd {

        }
    }

    /// Feed a char to the editor (as input)
    fn feed(&mut self, c: char) {
        match self.state.cursors[self.state.current_cursor as usize].mode {
            Mode::Primitive(_) => {
                self.exec(0, c);
            },
            Mode::Command(_) => {
                self.n = match c {
                    '0' if self.n != 0 => self.n * 10,
                    '1'           => self.n * 10 + 1,
                    '2'           => self.n * 10 + 2,
                    '3'           => self.n * 10 + 3,
                    '4'           => self.n * 10 + 4,
                    '5'           => self.n * 10 + 5,
                    '6'           => self.n * 10 + 6,
                    '7'           => self.n * 10 + 7,
                    '8'           => self.n * 10 + 8,
                    '9'           => self.n * 10 + 9,
                    _             => {
                        self.exec(if self.n == 0 { 1 } else { self.n }, c);
                        self.n
                    }
                }

            }
        }
    }
}

#[derive(Clone, PartialEq, Hash)]
/// A cursor
pub struct Cursor {
    /// The x coordinate of the cursor
    pub x: u32,
    /// The y coordinate of the cursor
    pub y: u32,
    /// The mode of the cursor
    pub mode: Mode,
    /// The history of the cursor
    pub history: Vec<Unit>,

<|endoftext|>


<commit_before><commit_msg>Remove borrow<commit_after><|endoftext|>


<commit_before>// Translates individual functions in the completed AST to the LLVM IR, using
// destination-passing style.

import syntax::ast;
import middle::trans;
import middle::ty;
import trans::block_ctxt;
import trans::crate_ctxt;
import trans::fn_ctxt;
import trans::local_ctxt;
import lib::llvm::llvm::TypeRef;
import lib::llvm::llvm::ValueRef;
import std::option::none;
import std::option::some;

import type_of_node = trans::node_id_type;

// LLVM utilities

fn llelement_type(TypeRef llty) -> TypeRef {
    lib::llvm::llvm::LLVMGetElementType(llty)
}

// Destination utilities

tag dest_slot {
    dst_nil;
    dst_val(ValueRef);
}

type dest = rec(dest_slot slot, bool move);

fn dest_slot_for_ptr(&ty::ctxt tcx, ValueRef llptr, ty::t t) -> dest_slot {
    if ty::type_is_nil(tcx, t) { dst_nil } else { dst_val(llptr) }
}

fn dest_copy(&ty::ctxt tcx, ValueRef llptr, ty::t t) -> dest {
    ret rec(slot=dest_slot_for_ptr(tcx, llptr, t), move=false);
}

fn dest_move(&ty::ctxt tcx, ValueRef llptr, ty::t t) -> dest {
    ret rec(slot=dest_slot_for_ptr(tcx, llptr, t), move=true);
}

fn dest_tmp(&@block_ctxt bcx, ty::t t) -> tup(@block_ctxt, dest) {
    if ty::type_is_nil(bcx_tcx(bcx), t) {
        ret tup(bcx, rec(slot=dst_nil, move=true));
    }
    auto r = trans::alloc_ty(bcx, t);
    ret tup(r.bcx, dest_move(bcx_tcx(bcx), r.val, t));
}

// Accessors
// TODO: When we have overloading, simplify these names!

fn bcx_tcx(&@block_ctxt bcx) -> ty::ctxt { ret bcx.fcx.lcx.ccx.tcx; }
fn bcx_ccx(&@block_ctxt bcx) -> @crate_ctxt { ret bcx.fcx.lcx.ccx; }
fn bcx_lcx(&@block_ctxt bcx) -> @local_ctxt { ret bcx.fcx.lcx; }
fn bcx_fcx(&@block_ctxt bcx) -> @fn_ctxt { ret bcx.fcx; }

// Common operations

fn store(&@block_ctxt bcx, &dest dest, ValueRef llsrc) -> @block_ctxt {
    alt (dest.slot) {
      dst_nil { /* no-op */ }
      dst_val(?lldest) { bcx.build.Store(llsrc, lldest); }
    }
    ret bcx;
}

// AST substructure translation, with destinations

fn trans_expr(&@block_ctxt bcx, &dest dest, &@ast::expr expr) -> @block_ctxt {
    ret bcx;    // TODO
}

fn trans_recv(&@block_ctxt bcx, &dest dest, &@ast::expr expr) -> @block_ctxt {
    ret bcx;    // TODO
}

fn trans_block(&@block_ctxt cx, &dest dest, &ast::block block)
        -> @block_ctxt {
    auto bcx = cx;
    for each (@ast::local local in trans::block_locals(block)) {
        bcx = trans::alloc_local(bcx, local).bcx;
    }

    for (@ast::stmt stmt in block.node.stmts) {
        bcx = trans_stmt(bcx, stmt);

        // If we hit a terminator, control won't go any further so
        // we're in dead-code land. Stop here.
        if trans::is_terminated(bcx) { ret bcx; }
    }

    alt (block.node.expr) {
      some(?e) { ret trans_expr(bcx, dest, e); }
      none { ret bcx; }
    }
}

// AST substructure translation, without destinations

fn trans_init_local(&@block_ctxt bcx, &@ast::local local) -> @block_ctxt {
    auto llptr = bcx_fcx(bcx).lllocals.get(local.node.id);

    auto t = type_of_node(bcx_ccx(bcx), local.node.id);
    trans::add_clean(bcx, llptr, t);

    alt (local.node.init) {
      some(?init) {
        alt (init.op) {
          ast::init_assign {
            ret trans_expr(bcx, dest_copy(bcx_tcx(bcx), llptr, t), init.expr);
          }
          ast::init_move {
            ret trans_expr(bcx, dest_move(bcx_tcx(bcx), llptr, t), init.expr);
          }
          ast::init_recv {
            ret trans_recv(bcx, dest_copy(bcx_tcx(bcx), llptr, t), init.expr);
          }
        }
      }
      none {
        ret store(bcx, dest_copy(bcx_tcx(bcx), llptr, t),
                  trans_common::C_null(llelement_type(trans::val_ty(llptr))));
      }
    }
}

fn trans_stmt(&@block_ctxt cx, &@ast::stmt stmt) -> @block_ctxt {
    auto bcx = cx;
    alt (stmt.node) {
      ast::stmt_expr(?e, _) {
        auto tmp_r = dest_tmp(bcx, ty::expr_ty(bcx_tcx(bcx), e));
        bcx = tmp_r._0; auto tmp = tmp_r._1;
        ret trans_expr(bcx, tmp, e);
      }
      ast::stmt_decl(?d, _) {
        alt (d.node) {
          ast::decl_local(?local) { ret trans_init_local(bcx, local); }
          ast::decl_item(?item) {
            trans::trans_item(bcx_lcx(bcx), *item);
            ret bcx;
          }
        }
      }
    }
}

<commit_msg>rustc: Translate literals in DPS style; no constification of strings yet.<commit_after>// Translates individual functions in the completed AST to the LLVM IR, using
// destination-passing style.

import back::abi;
import lib::llvm::llvm;
import llvm::TypeRef;
import llvm::ValueRef;
import middle::trans;
import middle::ty;
import syntax::ast;
import trans::block_ctxt;
import trans::crate_ctxt;
import trans::fn_ctxt;
import trans::local_ctxt;

import std::ivec;
import std::option::none;
import std::option::some;
import std::str;

import LLFalse = lib::llvm::False;
import LLTrue = lib::llvm::True;
import lltype_of = trans::val_ty;
import option = std::option::t;
import tc = trans_common;
import type_of_node = trans::node_id_type;

// LLVM utilities

fn llelement_type(TypeRef llty) -> TypeRef {
    lib::llvm::llvm::LLVMGetElementType(llty)
}

// Destination utilities

tag dest_slot {
    dst_nil;
    dst_val(ValueRef);
}

type dest = rec(dest_slot slot, bool move);

fn dest_slot_for_ptr(&ty::ctxt tcx, ValueRef llptr, ty::t t) -> dest_slot {
    if ty::type_is_nil(tcx, t) { dst_nil } else { dst_val(llptr) }
}

fn dest_copy(&ty::ctxt tcx, ValueRef llptr, ty::t t) -> dest {
    ret rec(slot=dest_slot_for_ptr(tcx, llptr, t), move=false);
}

fn dest_move(&ty::ctxt tcx, ValueRef llptr, ty::t t) -> dest {
    ret rec(slot=dest_slot_for_ptr(tcx, llptr, t), move=true);
}

fn dest_tmp(&@block_ctxt bcx, ty::t t) -> tup(@block_ctxt, dest) {
    if ty::type_is_nil(bcx_tcx(bcx), t) {
        ret tup(bcx, rec(slot=dst_nil, move=true));
    }
    auto r = trans::alloc_ty(bcx, t);
    ret tup(r.bcx, dest_move(bcx_tcx(bcx), r.val, t));
}

fn dest_ptr(&dest dest) -> ValueRef {
    alt (dest.slot) {
      dst_nil { tc::C_null(tc::T_ptr(tc::T_i8())) }
      dst_val(?llptr) { llptr }
    }
}

// Accessors
// TODO: When we have overloading, simplify these names!

fn bcx_tcx(&@block_ctxt bcx) -> ty::ctxt { ret bcx.fcx.lcx.ccx.tcx; }
fn bcx_ccx(&@block_ctxt bcx) -> @crate_ctxt { ret bcx.fcx.lcx.ccx; }
fn bcx_lcx(&@block_ctxt bcx) -> @local_ctxt { ret bcx.fcx.lcx; }
fn bcx_fcx(&@block_ctxt bcx) -> @fn_ctxt { ret bcx.fcx; }

// Common operations

// If "cast" is true, casts dest appropriately before the store.
fn store(&@block_ctxt bcx, &dest dest, ValueRef llsrc, bool cast)
        -> @block_ctxt {
    alt (dest.slot) {
      dst_nil { /* no-op */ }
      dst_val(?lldestptr_orig) {
        auto lldestptr = lldestptr_orig;
        if (cast) {
            lldestptr = bcx.build.PointerCast(lldestptr,
                                              tc::T_ptr(lltype_of(llsrc)));
        }

        bcx.build.Store(llsrc, lldestptr);
      }
    }
    ret bcx;
}

tag heap { hp_task; hp_shared; }

// Allocates a value of the given LLVM size on either the task heap or the
// shared heap.
fn malloc(&@block_ctxt bcx, ValueRef lldest, heap heap,
          option[ValueRef] llcustom_size_opt) -> @block_ctxt {
    auto llptrty = llelement_type(lltype_of(lldest));
    auto llty = llelement_type(llptrty);

    auto lltydescptr = tc::C_null(tc::T_ptr(bcx_ccx(bcx).tydesc_type));

    auto llsize;
    alt (llcustom_size_opt) {
      none { llsize = trans::llsize_of(llty); }
      some(?llcustom_size) { llsize = llcustom_size; }
    }

    auto llupcall;
    alt (heap) {
      hp_task { llupcall = bcx_ccx(bcx).upcalls.malloc; }
      hp_shared { llupcall = bcx_ccx(bcx).upcalls.shared_malloc; }
    }

    auto llresult = bcx.build.Call(llupcall, ~[bcx_fcx(bcx).lltaskptr, llsize,
                                               lltydescptr]);
    llresult = bcx.build.PointerCast(llresult, llptrty);
    bcx.build.Store(llresult, lldest);
    ret bcx;
}

// AST substructure translation, with destinations

fn trans_lit(&@block_ctxt cx, &dest dest, &ast::lit lit) -> @block_ctxt {
    auto bcx = cx;
    alt (lit.node) {
      ast::lit_str(?s, ast::sk_unique) {
        auto r = trans_lit_str_common(bcx_ccx(bcx), s);
        auto llstackpart = r._0; auto llheappartopt = r._1;
        bcx = store(bcx, dest, llstackpart, true);
        alt (llheappartopt) {
          none { /* no-op */ }
          some(?llheappart) {
            auto lldestptrptr =
                bcx.build.InBoundsGEP(dest_ptr(dest),
                                      ~[tc::C_int(0),
                                        tc::C_uint(abi::ivec_elt_elems)]);
            auto llheappartty = lltype_of(llheappart);
            lldestptrptr =
                bcx.build.PointerCast(lldestptrptr,
                                      tc::T_ptr(tc::T_ptr(llheappartty)));
            malloc(bcx, lldestptrptr, hp_shared, none);
            auto lldestptr = bcx.build.Load(lldestptrptr);
            bcx.build.Store(llheappart, lldestptr);
          }
        }
      }
      _ {
        bcx = store(bcx, dest, trans_lit_common(bcx_ccx(bcx), lit), false);
      }
    }

    ret bcx;
}

fn trans_expr(&@block_ctxt bcx, &dest dest, &@ast::expr expr) -> @block_ctxt {
    alt (expr.node) {
      ast::expr_lit(?lit) { trans_lit(bcx, dest, *lit); ret bcx; }
      _ { fail "unhandled expr type in trans_expr"; }
    }
}

fn trans_recv(&@block_ctxt bcx, &dest dest, &@ast::expr expr) -> @block_ctxt {
    ret bcx;    // TODO
}

fn trans_block(&@block_ctxt cx, &dest dest, &ast::block block)
        -> @block_ctxt {
    auto bcx = cx;
    for each (@ast::local local in trans::block_locals(block)) {
        bcx = trans::alloc_local(bcx, local).bcx;
    }

    for (@ast::stmt stmt in block.node.stmts) {
        bcx = trans_stmt(bcx, stmt);

        // If we hit a terminator, control won't go any further so
        // we're in dead-code land. Stop here.
        if trans::is_terminated(bcx) { ret bcx; }
    }

    alt (block.node.expr) {
      some(?e) { ret trans_expr(bcx, dest, e); }
      none { ret bcx; }
    }
}

// AST substructure translation, without destinations

// Common setup code shared between the crate-constant literal string case and
// the block-local literal string case. We don't use destination-passing style
// since that doesn't work for crate constants.
fn trans_lit_str_common(&@crate_ctxt ccx, &str s)
        -> tup(ValueRef, option[ValueRef]) {
    auto len = str::byte_len(s);

    auto array = ~[];
    for (u8 ch in s) { array += ~[tc::C_u8(ch as uint)]; }
    array += ~[tc::C_u8(0u)];

    if len < abi::ivec_default_length - 1u {    // minus 1 because of the \0
        while (ivec::len(array) < abi::ivec_default_length) {
            array += ~[tc::C_u8(0u)];
        }

        ret tup(tc::C_struct(~[tc::C_uint(len + 1u),
                               tc::C_uint(abi::ivec_default_length),
                               tc::C_array(tc::T_i8(), array)]),
                none);
    }

    auto llarray = tc::C_array(tc::T_i8(), array);
    ret tup(tc::C_struct(~[tc::C_uint(0u),
                           tc::C_uint(abi::ivec_default_length),
                           tc::C_null(tc::T_ptr(lltype_of(llarray)))]),
            some(llarray));
}

// As above, we don't use destination-passing style here.
fn trans_lit_common(&@crate_ctxt ccx, &ast::lit lit) -> ValueRef {
    alt (lit.node) {
      ast::lit_int(?i) { ret tc::C_int(i); }
      ast::lit_uint(?u) { ret tc::C_int(u as int); }
      ast::lit_mach_int(?tm, ?i) {
        // FIXME: the entire handling of mach types falls apart
        // if target int width is larger than host, at the moment;
        // re-do the mach-int types using 'big' when that works.

        auto t = tc::T_int();
        auto s = LLTrue;
        alt (tm) {
          ast::ty_u8 { t = tc::T_i8(); s = LLFalse; }
          ast::ty_u16 { t = tc::T_i16(); s = LLFalse; }
          ast::ty_u32 { t = tc::T_i32(); s = LLFalse; }
          ast::ty_u64 { t = tc::T_i64(); s = LLFalse; }
          ast::ty_i8 { t = tc::T_i8(); }
          ast::ty_i16 { t = tc::T_i16(); }
          ast::ty_i32 { t = tc::T_i32(); }
          ast::ty_i64 { t = tc::T_i64(); }
        }
        ret tc::C_integral(t, i as uint, s);
      }
      ast::lit_float(?fs) { ret tc::C_float(fs); }
      ast::lit_mach_float(?tm, ?s) {
        auto t = tc::T_float();
        alt (tm) {
          ast::ty_f32 { t = tc::T_f32(); }
          ast::ty_f64 { t = tc::T_f64(); }
        }
        ret tc::C_floating(s, t);
      }
      ast::lit_char(?c) {
        ret tc::C_integral(tc::T_char(), c as uint, LLFalse);
      }
      ast::lit_bool(?b) { ret tc::C_bool(b); }
      ast::lit_nil { ret tc::C_nil(); }
      ast::lit_str(?s, ast::sk_rc) { ret tc::C_str(ccx, s); }
      ast::lit_str(?s, ast::sk_unique) {
        fail "unique str in trans_lit_common";
      }
    }
}

fn trans_init_local(&@block_ctxt bcx, &@ast::local local) -> @block_ctxt {
    auto llptr = bcx_fcx(bcx).lllocals.get(local.node.id);

    auto t = type_of_node(bcx_ccx(bcx), local.node.id);
    trans::add_clean(bcx, llptr, t);

    alt (local.node.init) {
      some(?init) {
        alt (init.op) {
          ast::init_assign {
            ret trans_expr(bcx, dest_copy(bcx_tcx(bcx), llptr, t), init.expr);
          }
          ast::init_move {
            ret trans_expr(bcx, dest_move(bcx_tcx(bcx), llptr, t), init.expr);
          }
          ast::init_recv {
            ret trans_recv(bcx, dest_copy(bcx_tcx(bcx), llptr, t), init.expr);
          }
        }
      }
      none {
        ret store(bcx, dest_copy(bcx_tcx(bcx), llptr, t),
                  tc::C_null(llelement_type(trans::val_ty(llptr))), false);
      }
    }
}

fn trans_stmt(&@block_ctxt cx, &@ast::stmt stmt) -> @block_ctxt {
    auto bcx = cx;
    alt (stmt.node) {
      ast::stmt_expr(?e, _) {
        auto tmp_r = dest_tmp(bcx, ty::expr_ty(bcx_tcx(bcx), e));
        bcx = tmp_r._0; auto tmp = tmp_r._1;
        ret trans_expr(bcx, tmp, e);
      }
      ast::stmt_decl(?d, _) {
        alt (d.node) {
          ast::decl_local(?local) { ret trans_init_local(bcx, local); }
          ast::decl_item(?item) {
            trans::trans_item(bcx_lcx(bcx), *item);
            ret bcx;
          }
        }
      }
    }
}

<|endoftext|>


<commit_before><commit_msg>am e49f75eb: am bbcf2079: Merge "Fix struct initializer for balls." into honeycomb<commit_after><|endoftext|>


<commit_before><commit_msg>Added example of a concurrent server<commit_after>#![feature(macro_rules)]

extern crate hyper;
extern crate debug;

use std::io::util::copy;
use std::io::net::ip::Ipv4Addr;
use std::sync::Arc;

use hyper::{Get, Post};
use hyper::server::{Server, Handler, Incoming, Request, Response};
use hyper::header::common::ContentLength;

trait ConcurrentHandler: Send + Sync {
    fn handle(&self, req: Request, res: Response);
}

struct Concurrent<H: ConcurrentHandler> { handler: Arc<H> }

impl<H: ConcurrentHandler> Handler for Concurrent<H> {
    fn handle(self, mut incoming: Incoming) {
        for (mut req, mut res) in incoming {
            let clone = self.handler.clone();
            spawn(proc() { clone.handle(req, res) })
        }
    }
}

macro_rules! try_abort(
    ($e:expr) => {{
        match $e {
            Ok(v) => v,
            Err(..) => return
        }
    }}
)

struct Echo;

impl ConcurrentHandler for Echo {
    fn handle(&self, mut req: Request, mut res: Response) {
        match req.uri {
            hyper::uri::AbsolutePath(ref path) => match (&req.method, path.as_slice()) {
                (&Get, "/") | (&Get, "/echo") => {
                    let out = b"Try POST /echo";

                    res.headers.set(ContentLength(out.len()));
                    try_abort!(res.write(out));
                    try_abort!(res.end());
                    return;
                },
                (&Post, "/echo") => (), // fall through, fighting mutable borrows
                _ => {
                    res.status = hyper::status::NotFound;
                    try_abort!(res.end());
                    return;
                }
            },
            _ => {
                try_abort!(res.end());
                return;
            }
        }
        try_abort!(copy(&mut req, &mut res));
        try_abort!(res.end());
    }
}

fn main() {
    let server = Server::http(Ipv4Addr(127, 0, 0, 1), 3000);
    server.listen(Concurrent { handler: Arc::new(Echo) }).unwrap();
}
<|endoftext|>


<commit_before>//! Implements traits from Diesel, allowing identifiers to be used as database fields.

use std::{convert::TryFrom, error::Error as StdError, io::Write};

use diesel::{
    backend::Backend,
    deserialize::{FromSql, Result as DeserializeResult},
    serialize::{Output, Result as SerializeResult, ToSql},
    sql_types::Text,
};

macro_rules! diesel_impl {
    ($name:ident) => {
        impl<DB> ToSql<Text, DB> for $crate::$name
        where
            DB: Backend,
        {
            fn to_sql<W: Write>(&self, out: &mut Output<W, DB>) -> SerializeResult {
                ToSql::<Text, DB>::to_sql(&self.to_string(), out)
            }
        }

        impl<DB> FromSql<Text, DB> for $crate::$name
        where
            String: FromSql<Text, DB>,
            DB: Backend,
        {
            fn from_sql(value: Option<&<DB as Backend>::RawValue>) -> DeserializeResult<Self> {
                let string = <String as FromSql<Text, DB>>::from_sql(value)?;
                Self::try_from(string.as_str())
                    .map_err(|error| Box::new(error) as Box<dyn StdError + Send + Sync>)
            }
        }
    };
}

diesel_impl!(EventId);
diesel_impl!(RoomAliasId);
diesel_impl!(RoomId);
diesel_impl!(RoomIdOrAliasId);
diesel_impl!(RoomVersionId);
diesel_impl!(UserId);
<commit_msg>Fix Rust 2018 idiom warning<commit_after>//! Implements traits from Diesel, allowing identifiers to be used as database fields.

use std::{convert::TryFrom, error::Error as StdError, io::Write};

use diesel::{
    backend::Backend,
    deserialize::{FromSql, Result as DeserializeResult},
    serialize::{Output, Result as SerializeResult, ToSql},
    sql_types::Text,
};

macro_rules! diesel_impl {
    ($name:ident) => {
        impl<DB> ToSql<Text, DB> for $crate::$name
        where
            DB: Backend,
        {
            fn to_sql<W: Write>(&self, out: &mut Output<'_, W, DB>) -> SerializeResult {
                ToSql::<Text, DB>::to_sql(&self.to_string(), out)
            }
        }

        impl<DB> FromSql<Text, DB> for $crate::$name
        where
            String: FromSql<Text, DB>,
            DB: Backend,
        {
            fn from_sql(value: Option<&<DB as Backend>::RawValue>) -> DeserializeResult<Self> {
                let string = <String as FromSql<Text, DB>>::from_sql(value)?;
                Self::try_from(string.as_str())
                    .map_err(|error| Box::new(error) as Box<dyn StdError + Send + Sync>)
            }
        }
    };
}

diesel_impl!(EventId);
diesel_impl!(RoomAliasId);
diesel_impl!(RoomId);
diesel_impl!(RoomIdOrAliasId);
diesel_impl!(RoomVersionId);
diesel_impl!(UserId);
<|endoftext|>


<commit_before>// Based on smallpt, http://www.kevinbeason.com/smallpt/ which is also licensed under
// the MIT license.
use std::fs::File;
use std::io::prelude::*;
use std::sync::Arc;
use std::sync::mpsc::channel;

extern crate rand;
use rand::{Rng, XorShiftRng, SeedableRng};

extern crate threadpool;
use threadpool::ThreadPool;

extern crate num_cpus;

mod path_tracer;
use path_tracer::*;

enum Material {
    Diffuse,
    Specular,
    Refractive
}

struct Sphere {
    material: Material,
    radius: f64,
    position: Vec3d,
    emission: Vec3d,
    colour: Vec3d
}

impl Sphere {
    fn new(material: Material, radius: f64, position: Vec3d, emission: Vec3d, colour: Vec3d) -> Sphere {
        Sphere {
          material: material,
          radius: radius,
          position: position,
          emission: emission,
          colour: colour
        }
    }
    fn intersect(&self, ray: &Ray) -> Option<f64> {
        let op = self.position - ray.origin;
        let b = op.dot(ray.direction);
        let determinant = b * b - op.dot(op) + self.radius * self.radius;
        if determinant < 0.0 { return None; }
        let determinant = determinant.sqrt();
        let t1 = b - determinant;
        let t2 = b + determinant;
        const EPSILON : f64 = 0.0001;
        if t1 > EPSILON {
            Some(t1)
        } else if t2 > EPSILON {
            Some(t2)
        } else {
            None
        }
    }
}

#[test]
fn intersection() {
    let sphere = Sphere::new(
        Material::Diffuse,
        100.0,
        Vec3d::new(0.0, 0.0, 200.0),
        Vec3d::zero(),
        Vec3d::zero());
    let ray = Ray::new(Vec3d::zero(), Vec3d::new(0.0, 0.0, 1.0));
    match sphere.intersect(&ray) {
        Some(x) => assert_eq!(x, 100.0),
        None => panic!("unexpected")
    }
    let ray = Ray::new(Vec3d::zero(), Vec3d::new(0.0, 1.0, 0.0));
    match sphere.intersect(&ray) {
        Some(_) => panic!("unexpected"),
        None => {}
    }
}

struct HitRecord<'a> {
    sphere: &'a Sphere,
    dist: f64
}

fn intersect<'a>(scene: &'a Vec<Sphere>, ray: &Ray) -> Option<HitRecord<'a>> {
    let mut result : Option<HitRecord<'a>> = None;
    for sph in scene.iter() {
        if let Some(dist) = sph.intersect(&ray) {
            if match result { None => true, Some(ref x) => dist < x.dist } {
                result = Some(HitRecord { sphere: &sph, dist: dist });
            }
        }
    }
    result
}

fn radiance<R: Rng>(scene: &Vec<Sphere>, ray: &Ray, depth: i32, rng: &mut R) -> Vec3d {
    if let Some(hit) = intersect(&scene, &ray) {
        let hit_pos = ray.origin + ray.direction * hit.dist;
        let hit_normal = (hit_pos - hit.sphere.position).normalized();
        let n1 = if hit_normal.dot(ray.direction) < 0.0 { hit_normal } else { hit_normal.neg() };
        let mut colour = hit.sphere.colour;
        let max_reflectance = colour.max_component();
        let depth = depth + 1;
        if depth > 5 {
            let rand = rng.gen::<f64>();
            if rand < max_reflectance && depth < 100 {
               colour = colour * (1.0 / max_reflectance);
            } else {
                return hit.sphere.emission;
            }
        }
        match hit.sphere.material {
            Material::Diffuse => {
                // Get a random polar coordinate
                let r1 = rng.gen::<f64>() * 2.0 * std::f64::consts::PI;
                let r2 = rng.gen::<f64>();
                let r2s = r2.sqrt();
                // Create a coordinate system u,v,w local to the point, where the w is the normal
                // pointing out of the sphere and the u and v are orthonormal to w.
                let w = n1;
                // Pick an arbitrary non-zero preferred axis for u
                let u = if n1.x.abs() > 0.1 { Vec3d::new(0.0, 1.0, 0.0) } else { Vec3d::new(1.0, 0.0, 0.0) }.cross(w);
                let v = w.cross(u);
                // construct the new direction
                let new_dir = u * r1.cos() * r2s + v * r1.sin() * r2s + w * (1.0 - r2).sqrt();
                colour = colour * radiance(scene, &Ray::new(hit_pos, new_dir.normalized()), depth, rng);
            },
            Material::Specular => {
                let reflection = ray.direction - hit_normal * 2.0 * hit_normal.dot(ray.direction);
                let reflected_ray = Ray::new(hit_pos, reflection);
                colour = colour * radiance(scene, &reflected_ray, depth, rng);
            },
            Material::Refractive => {
                let reflection = ray.direction - hit_normal * 2.0 * hit_normal.dot(ray.direction);
                let reflected_ray = Ray::new(hit_pos, reflection);
                let into = if hit_normal.dot(n1) > 0.0 { true } else { false };
                let nc = 1.0;
                let nt = 1.5;
                let nnt = if into { nc/nt } else { nt/nc };
                let ddn = ray.direction.dot(n1);
                let cos2t = 1.0 - nnt * nnt * (1.0 - ddn * ddn);
                if cos2t < 0.0 {
                    // Total internal reflection
                    colour = colour * radiance(scene, &reflected_ray, depth, rng);
                } else {
                    let tbd = ddn * nnt + cos2t.sqrt();
                    let tbd = if into { tbd } else { -tbd };
                    let tdir = (ray.direction * nnt - hit_normal * tbd).normalized();
                    let transmitted_ray = Ray::new(hit_pos, tdir);
                    let a = nt - nc;
                    let b = nt + nc;
                    let r0 = (a * a) / (b * b);
                    let c = 1.0 - if into { -ddn } else { tdir.dot(hit_normal) };
                    let re = r0 + (1.0 - r0) * c * c * c * c * c;
                    let tr = 1.0 - re;
                    let p = 0.25 + 0.5 * re;
                    let rp = re / p;
                    let tp = tr / (1.0 - p);
                    colour = colour * if depth > 2 {
                        if rng.gen::<f64>() < p {
                            radiance(scene, &reflected_ray, depth, rng) * rp
                        } else {
                            radiance(scene, &transmitted_ray, depth, rng) * tp
                        }
                    } else {
                        radiance(scene, &reflected_ray, depth, rng) * re +
                            radiance(scene, &transmitted_ray, depth, rng) * tr
                    }
                }
            }
        }
        hit.sphere.emission + colour
    } else {
        Vec3d::zero()
    }
}

fn random_samp<T: Rng>(rng: &mut T) -> f64 {
    let r = 2.0 * rng.gen::<f64>();
    if r < 1.0 { r.sqrt() - 1.0 } else { 1.0 - (2.0 - r).sqrt() }
}

fn to_int(v: f64) -> u8 {
    let ch = (v.powf(1.0/2.2) * 255.0 + 0.5) as i64;
    if ch < 0 { 0 } else if ch > 255 { 255 } else { ch as u8 }
}

fn main() {
    const BLACK : Vec3d = Vec3d { x: 0.0, y: 0.0, z: 0.0 };
    const RED : Vec3d = Vec3d { x: 0.75, y: 0.25, z: 0.25 };
    const BLUE : Vec3d = Vec3d { x: 0.25, y: 0.25, z: 0.75 };
    const GREY : Vec3d = Vec3d { x: 0.75, y: 0.75, z: 0.75 };
    const WHITE : Vec3d = Vec3d { x: 0.999, y: 0.999, z: 0.999 };
    let scene = Arc::new(vec!{
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(1e5+1.0, 40.8, 81.6),
            BLACK, RED),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(-1e5+99.0, 40.8, 81.6),
            BLACK, BLUE),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, 40.8, 1e5),
            BLACK, GREY),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, 40.8, -1e5 + 170.0),
            BLACK, BLACK),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, 1e5, 81.6),
            BLACK, GREY),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, -1e5 + 81.6, 81.6),
            BLACK, RED),
        Sphere::new(Material::Specular, 16.5,
            Vec3d::new(27.0, 16.5, 47.0),
            BLACK, WHITE),
        Sphere::new(Material::Refractive, 16.5,
            Vec3d::new(73.0, 16.5, 78.0),
            BLACK, WHITE),
        Sphere::new(Material::Diffuse, 600.0,
            Vec3d::new(50.0, 681.6 - 0.27, 81.6),
            Vec3d::new(12.0, 12.0, 12.0), BLACK),
    });

    const WIDTH: usize = 256;//1024;
    const HEIGHT: usize = 192;//768;
    let samps = 1024;
    let camera_pos = Vec3d::new(50.0, 52.0, 295.6);
    let camera_dir = Vec3d::new(0.0, -0.042612, -1.0);
    let camera_x = Vec3d::new(WIDTH as f64 * 0.5135 / HEIGHT as f64, 0.0, 0.0);
    let camera_y = camera_x.cross(camera_dir).normalized() * 0.5135;

    let num_threads = num_cpus::get();
    println!("Using {} threads", num_threads);
    let pool = ThreadPool::new(num_threads);
    let (tx, rx) = channel();

    for y in 0..HEIGHT {
        let tx = tx.clone();
        let scene = scene.clone();
        pool.execute(move || {
            let mut line = Vec::with_capacity(WIDTH);
            for x in 0..WIDTH {
                let mut rng = XorShiftRng::from_seed([10, 200, 999999, y as u32]);
                let mut sum = Vec3d::zero();
                for sx in 0..2 {
                    for sy in 0..2 {
                        for _samp in 0..samps {
                            let dx = random_samp(&mut rng);
                            let dy = random_samp(&mut rng);
                            let dir = camera_x * (((sx as f64 + 0.5 + dx)/2.0 + x as f64) / WIDTH as f64 - 0.5) +
            camera_y * (((sy as f64 + 0.5 + dy)/2.0 + (HEIGHT - y - 1) as f64) / HEIGHT as f64  - 0.5) + camera_dir;
        let jittered_ray = Ray::new(camera_pos + dir * 140.0, dir.normalized());
        let sample = radiance(&scene, &jittered_ray, 0, &mut rng);
        sum = sum + sample;
                        }
                    }
                }
                line.push(sum / (samps * 4) as f64);
            }
            tx.send((y, line)).unwrap();
        });
    }
    let mut left = HEIGHT;
    let mut screen : Vec<Vec<Vec3d>> = Vec::new();
    for _y in 0..HEIGHT {
        screen.push(Vec::new());
    }
    while left > 0 {
        println!("Rendering ({} spp) {:.4}%...", samps * 4, 100.0 * (HEIGHT - left) as f64 / HEIGHT as f64);
        let (y, line) = rx.recv().unwrap();
        screen[y] = line;
        left -= 1;
    }
    println!("Writing output");
    let mut output_file = File::create("image.ppm").unwrap();
    write!(&mut output_file, "P3\n{} {}\n255\n", WIDTH, HEIGHT).unwrap();
    for y in 0..HEIGHT {
        for x in 0..WIDTH {
            let sum = screen[y][x];
            write!(&mut output_file, "{} {} {} ", to_int(sum.x), to_int(sum.y), to_int(sum.z)).unwrap();
        }
    }
}
<commit_msg>Addressing some things @phildawes brought up (Thanks Phil!)<commit_after>// Based on smallpt, http://www.kevinbeason.com/smallpt/ which is also licensed under
// the MIT license.
use std::fs::File;
use std::io::prelude::*;
use std::sync::Arc;
use std::sync::mpsc::channel;

extern crate rand;
use rand::{Rng, XorShiftRng, SeedableRng};

extern crate threadpool;
use threadpool::ThreadPool;

extern crate num_cpus;

mod path_tracer;
use path_tracer::*;

enum Material {
    Diffuse,
    Specular,
    Refractive
}

struct Sphere {
    material: Material,
    radius: f64,
    position: Vec3d,
    emission: Vec3d,
    colour: Vec3d
}

impl Sphere {
    fn new(material: Material, radius: f64, position: Vec3d, emission: Vec3d, colour: Vec3d) -> Sphere {
        Sphere {
          material: material,
          radius: radius,
          position: position,
          emission: emission,
          colour: colour
        }
    }
    fn intersect(&self, ray: &Ray) -> Option<f64> {
        let op = self.position - ray.origin;
        let b = op.dot(ray.direction);
        let determinant = b * b - op.dot(op) + self.radius * self.radius;
        if determinant < 0.0 { return None; }
        let determinant = determinant.sqrt();
        let t1 = b - determinant;
        let t2 = b + determinant;
        const EPSILON : f64 = 0.0001;
        if t1 > EPSILON {
            Some(t1)
        } else if t2 > EPSILON {
            Some(t2)
        } else {
            None
        }
    }
}

#[test]
fn intersection() {
    let sphere = Sphere::new(
        Material::Diffuse,
        100.0,
        Vec3d::new(0.0, 0.0, 200.0),
        Vec3d::zero(),
        Vec3d::zero());
    let ray = Ray::new(Vec3d::zero(), Vec3d::new(0.0, 0.0, 1.0));
    match sphere.intersect(&ray) {
        Some(x) => assert_eq!(x, 100.0),
        None => panic!("unexpected")
    }
    let ray = Ray::new(Vec3d::zero(), Vec3d::new(0.0, 1.0, 0.0));
    match sphere.intersect(&ray) {
        Some(_) => panic!("unexpected"),
        None => {}
    }
}

struct HitRecord<'a> {
    sphere: &'a Sphere,
    dist: f64
}

fn intersect<'a>(scene: &'a [Sphere], ray: &Ray) -> Option<HitRecord<'a>> {
    let mut result : Option<HitRecord<'a>> = None;
    for sph in scene {
        if let Some(dist) = sph.intersect(&ray) {
            if match result { None => true, Some(ref x) => dist < x.dist } {
                result = Some(HitRecord { sphere: &sph, dist: dist });
            }
        }
    }
    result
}

fn radiance<R: Rng>(scene: &[Sphere], ray: &Ray, depth: i32, rng: &mut R) -> Vec3d {
    if let Some(hit) = intersect(&scene, &ray) {
        let hit_pos = ray.origin + ray.direction * hit.dist;
        let hit_normal = (hit_pos - hit.sphere.position).normalized();
        let n1 = if hit_normal.dot(ray.direction) < 0.0 { hit_normal } else { hit_normal.neg() };
        let mut colour = hit.sphere.colour;
        let max_reflectance = colour.max_component();
        let depth = depth + 1;
        if depth > 5 {
            let rand = rng.gen::<f64>();
            if rand < max_reflectance && depth < 100 {
               colour = colour * (1.0 / max_reflectance);
            } else {
                return hit.sphere.emission;
            }
        }
        match hit.sphere.material {
            Material::Diffuse => {
                // Get a random polar coordinate
                let r1 = rng.gen::<f64>() * 2.0 * std::f64::consts::PI;
                let r2 = rng.gen::<f64>();
                let r2s = r2.sqrt();
                // Create a coordinate system u,v,w local to the point, where the w is the normal
                // pointing out of the sphere and the u and v are orthonormal to w.
                let w = n1;
                // Pick an arbitrary non-zero preferred axis for u
                let u = if n1.x.abs() > 0.1 { Vec3d::new(0.0, 1.0, 0.0) } else { Vec3d::new(1.0, 0.0, 0.0) }.cross(w);
                let v = w.cross(u);
                // construct the new direction
                let new_dir = u * r1.cos() * r2s + v * r1.sin() * r2s + w * (1.0 - r2).sqrt();
                colour = colour * radiance(scene, &Ray::new(hit_pos, new_dir.normalized()), depth, rng);
            },
            Material::Specular => {
                let reflection = ray.direction - hit_normal * 2.0 * hit_normal.dot(ray.direction);
                let reflected_ray = Ray::new(hit_pos, reflection);
                colour = colour * radiance(scene, &reflected_ray, depth, rng);
            },
            Material::Refractive => {
                let reflection = ray.direction - hit_normal * 2.0 * hit_normal.dot(ray.direction);
                let reflected_ray = Ray::new(hit_pos, reflection);
                let into = if hit_normal.dot(n1) > 0.0 { true } else { false };
                let nc = 1.0;
                let nt = 1.5;
                let nnt = if into { nc/nt } else { nt/nc };
                let ddn = ray.direction.dot(n1);
                let cos2t = 1.0 - nnt * nnt * (1.0 - ddn * ddn);
                if cos2t < 0.0 {
                    // Total internal reflection
                    colour = colour * radiance(scene, &reflected_ray, depth, rng);
                } else {
                    let tbd = ddn * nnt + cos2t.sqrt();
                    let tbd = if into { tbd } else { -tbd };
                    let tdir = (ray.direction * nnt - hit_normal * tbd).normalized();
                    let transmitted_ray = Ray::new(hit_pos, tdir);
                    let a = nt - nc;
                    let b = nt + nc;
                    let r0 = (a * a) / (b * b);
                    let c = 1.0 - if into { -ddn } else { tdir.dot(hit_normal) };
                    let re = r0 + (1.0 - r0) * c * c * c * c * c;
                    let tr = 1.0 - re;
                    let p = 0.25 + 0.5 * re;
                    let rp = re / p;
                    let tp = tr / (1.0 - p);
                    colour = colour * if depth > 2 {
                        if rng.gen::<f64>() < p {
                            radiance(scene, &reflected_ray, depth, rng) * rp
                        } else {
                            radiance(scene, &transmitted_ray, depth, rng) * tp
                        }
                    } else {
                        radiance(scene, &reflected_ray, depth, rng) * re +
                            radiance(scene, &transmitted_ray, depth, rng) * tr
                    }
                }
            }
        }
        hit.sphere.emission + colour
    } else {
        Vec3d::zero()
    }
}

fn random_samp<T: Rng>(rng: &mut T) -> f64 {
    let r = 2.0 * rng.gen::<f64>();
    if r < 1.0 { r.sqrt() - 1.0 } else { 1.0 - (2.0 - r).sqrt() }
}

fn to_int(v: f64) -> u8 {
    let ch = (v.powf(1.0/2.2) * 255.0 + 0.5) as i64;
    if ch < 0 { 0 } else if ch > 255 { 255 } else { ch as u8 }
}

fn main() {
    const BLACK : Vec3d = Vec3d { x: 0.0, y: 0.0, z: 0.0 };
    const RED : Vec3d = Vec3d { x: 0.75, y: 0.25, z: 0.25 };
    const BLUE : Vec3d = Vec3d { x: 0.25, y: 0.25, z: 0.75 };
    const GREY : Vec3d = Vec3d { x: 0.75, y: 0.75, z: 0.75 };
    const WHITE : Vec3d = Vec3d { x: 0.999, y: 0.999, z: 0.999 };
    let scene = Arc::new(vec!{
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(1e5+1.0, 40.8, 81.6),
            BLACK, RED),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(-1e5+99.0, 40.8, 81.6),
            BLACK, BLUE),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, 40.8, 1e5),
            BLACK, GREY),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, 40.8, -1e5 + 170.0),
            BLACK, BLACK),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, 1e5, 81.6),
            BLACK, GREY),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, -1e5 + 81.6, 81.6),
            BLACK, RED),
        Sphere::new(Material::Specular, 16.5,
            Vec3d::new(27.0, 16.5, 47.0),
            BLACK, WHITE),
        Sphere::new(Material::Refractive, 16.5,
            Vec3d::new(73.0, 16.5, 78.0),
            BLACK, WHITE),
        Sphere::new(Material::Diffuse, 600.0,
            Vec3d::new(50.0, 681.6 - 0.27, 81.6),
            Vec3d::new(12.0, 12.0, 12.0), BLACK),
    });

    const WIDTH: usize = 256;//1024;
    const HEIGHT: usize = 192;//768;
    let samps = 1024;
    let camera_pos = Vec3d::new(50.0, 52.0, 295.6);
    let camera_dir = Vec3d::new(0.0, -0.042612, -1.0);
    let camera_x = Vec3d::new(WIDTH as f64 * 0.5135 / HEIGHT as f64, 0.0, 0.0);
    let camera_y = camera_x.cross(camera_dir).normalized() * 0.5135;

    let num_threads = num_cpus::get();
    println!("Using {} threads", num_threads);
    let pool = ThreadPool::new(num_threads);
    let (tx, rx) = channel();

    for y in 0..HEIGHT {
        let tx = tx.clone();
        let scene = scene.clone();
        pool.execute(move || {
            let mut line = Vec::with_capacity(WIDTH);
            for x in 0..WIDTH {
                let mut rng = XorShiftRng::from_seed([10, 200, 999999, y as u32]);
                let mut sum = Vec3d::zero();
                for sx in 0..2 {
                    for sy in 0..2 {
                        for _samp in 0..samps {
                            let dx = random_samp(&mut rng);
                            let dy = random_samp(&mut rng);
                            let dir = camera_x * (((sx as f64 + 0.5 + dx)/2.0 + x as f64) / WIDTH as f64 - 0.5) +
            camera_y * (((sy as f64 + 0.5 + dy)/2.0 + (HEIGHT - y - 1) as f64) / HEIGHT as f64  - 0.5) + camera_dir;
                            let jittered_ray = Ray::new(camera_pos + dir * 140.0, dir.normalized());
                            let sample = radiance(&scene, &jittered_ray, 0, &mut rng);
                            sum = sum + sample;
                        }
                    }
                }
                line.push(sum / (samps * 4) as f64);
            }
            tx.send((y, line)).unwrap();
        });
    }
    let mut left = HEIGHT;
    let mut screen : Vec<Vec<Vec3d>> = Vec::new();
    for _y in 0..HEIGHT {
        screen.push(Vec::new());
    }
    while left > 0 {
        println!("Rendering ({} spp) {:.4}%...", samps * 4, 100.0 * (HEIGHT - left) as f64 / HEIGHT as f64);
        let (y, line) = rx.recv().unwrap();
        screen[y] = line;
        left -= 1;
    }
    println!("Writing output");
    let mut output_file = File::create("image.ppm").unwrap();
    write!(&mut output_file, "P3\n{} {}\n255\n", WIDTH, HEIGHT).unwrap();
    for y in 0..HEIGHT {
        for x in 0..WIDTH {
            let sum = screen[y][x];
            write!(&mut output_file, "{} {} {} ", to_int(sum.x), to_int(sum.y), to_int(sum.z)).unwrap();
        }
    }
}
<|endoftext|>