<commit_before>use std::collections::{VecDeque};
use std::char::{from_u32};

use from_ascii::{FromAsciiRadix, ParseIntError};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        InvalidValue {
            from(ParseIntError)
        }
        UnexpectedEnd
    }
}

pub fn unescape(s: &[u8], unicode: bool) -> Result<Vec<u8>, Error> {
    let mut buf = Vec::with_capacity(s.len());
    let mut oct_buf = VecDeque::with_capacity(3);

    let mut i = 0;

    macro_rules! read {
        () => ({
            match s.get(i) {
                None => return Err(Error::UnexpectedEnd),
                Some(c) => {
                    i += 1;
                    *c
                }
            }
        })
    }

    macro_rules! peek {
        () => ({
            s.get(i).map(|c| *c)
        })
    }

    loop {
        if i >= s.len() {
            return Ok(buf)
        }

        let c = read!();

        if c != b'\\' {
            buf.push(c);
            continue
        }

        let marker = read!();

        match marker {
            b'\n' => (),
            b'\\' => buf.push(b'\\'),
            b'\'' => buf.push(b'\''),
            b'"' => buf.push(b'"'),
            b'a' => buf.push(b'\x07'),
            b'b' => buf.push(b'\x08'),
            b'f' => buf.push(b'\x0c'),
            b'n' => buf.push(b'\n'),
            b'r' => buf.push(b'\r'),
            b't' => buf.push(b'\t'),
            b'v' => buf.push(b'\x0b'),
            b'x' => {
                let hex_buf = [read!(), read!()];
                buf.push(try!(u8::from_ascii_radix(&hex_buf, 16)))
            }
            b'0' ... b'7' => {
                oct_buf.push_back(marker);
                peek!().map(|c| {
                    if c >= b'0' && c <= b'7' {
                        oct_buf.push_back(c);
                        i += 1;

                        peek!().map(|c| {
                            if c >= b'0' && c <= b'7' {
                                oct_buf.push_back(c);
                                i += 1;
                            }
                        });
                    }
                });

                let value = try!(u16::from_ascii_radix(oct_buf.as_slices().0, 8));
                oct_buf.clear();
                buf.push(if value > 255 {
                    255
                } else {
                    value as u8
                });
                continue
            },
            b'u' if unicode => unimplemented!(),
            b'U' if unicode => {
                let mut s = String::new();
                let hex_buf = [read!(), read!(), read!(), read!(), read!(), read!(), read!(), read!()];
                let value = try!(u32::from_ascii_radix(&hex_buf, 16));
                s.push(match from_u32(value) {
                    Some(v) => v,
                    None => return Err(Error::InvalidValue),
                });
                buf.extend_from_slice(s.as_bytes());
            },
            _ => {
                buf.push(b'\\');
                buf.push(marker);
            }
        }
    }
}

#[cfg(test)]
mod tests {

    use super::{unescape};

    #[test]
    fn test_unescape() {
        assert_eq!(unescape(b"foo", false).unwrap(), b"foo");
        assert_eq!(unescape(b"f\\noo", false).unwrap(), b"f\noo");
        assert_eq!(unescape(b"f\\x01oo", false).unwrap(), b"f\x01oo");
        assert_eq!(unescape(b"f\\375oo", false).unwrap(), b"f\xfdoo");
        assert_eq!(unescape(b"f\\75oo", false).unwrap(), b"f\x3doo");
        assert_eq!(unescape(b"f\\5oo", false).unwrap(), b"f\x05oo");
        assert_eq!(unescape(b"f\\oo", false).unwrap(), b"f\\oo");
        assert_eq!(unescape(b"f\\coo", false).unwrap(), b"f\\coo");
    }
}<commit_msg>Add utf-16 unicode unescaping<commit_after>use std::collections::{VecDeque};
use std::char::{from_u32};

use from_ascii::{FromAsciiRadix, ParseIntError};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        InvalidValue {
            from(ParseIntError)
        }
        UnexpectedEnd
    }
}

pub fn unescape(s: &[u8], unicode: bool) -> Result<Vec<u8>, Error> {
    let mut buf = Vec::with_capacity(s.len());
    let mut oct_buf = VecDeque::with_capacity(3);

    let mut i = 0;

    macro_rules! read {
        () => ({
            match s.get(i) {
                None => return Err(Error::UnexpectedEnd),
                Some(c) => {
                    i += 1;
                    *c
                }
            }
        })
    }

    macro_rules! peek {
        () => ({
            s.get(i).map(|c| *c)
        })
    }

    loop {
        if i >= s.len() {
            return Ok(buf)
        }

        let c = read!();

        if c != b'\\' {
            buf.push(c);
            continue
        }

        let marker = read!();

        match marker {
            b'\n' => (),
            b'\\' => buf.push(b'\\'),
            b'\'' => buf.push(b'\''),
            b'"' => buf.push(b'"'),
            b'a' => buf.push(b'\x07'),
            b'b' => buf.push(b'\x08'),
            b'f' => buf.push(b'\x0c'),
            b'n' => buf.push(b'\n'),
            b'r' => buf.push(b'\r'),
            b't' => buf.push(b'\t'),
            b'v' => buf.push(b'\x0b'),
            b'x' => {
                let hex_buf = [read!(), read!()];
                buf.push(try!(u8::from_ascii_radix(&hex_buf, 16)))
            }
            b'0' ... b'7' => {
                oct_buf.push_back(marker);
                peek!().map(|c| {
                    if c >= b'0' && c <= b'7' {
                        oct_buf.push_back(c);
                        i += 1;

                        peek!().map(|c| {
                            if c >= b'0' && c <= b'7' {
                                oct_buf.push_back(c);
                                i += 1;
                            }
                        });
                    }
                });

                let value = try!(u16::from_ascii_radix(oct_buf.as_slices().0, 8));
                oct_buf.clear();
                buf.push(if value > 255 {
                    255
                } else {
                    value as u8
                });
                continue
            },
            b'u' if unicode => {
                let hex_buf = [read!(), read!(), read!(), read!()];
                let value = try!(u16::from_ascii_radix(&hex_buf, 16));
                let s = match String::from_utf16(&[value]) {
                    Ok(s) => s,
                    Err(_) => return Err(Error::InvalidValue),
                };
                buf.extend_from_slice(s.as_bytes());
            },
            b'U' if unicode => {
                let mut s = String::new();
                let hex_buf = [read!(), read!(), read!(), read!(), read!(), read!(), read!(), read!()];
                let value = try!(u32::from_ascii_radix(&hex_buf, 16));
                s.push(match from_u32(value) {
                    Some(v) => v,
                    None => return Err(Error::InvalidValue),
                });
                buf.extend_from_slice(s.as_bytes());
            },
            _ => {
                buf.push(b'\\');
                buf.push(marker);
            }
        }
    }
}

#[cfg(test)]
mod tests {

    use super::{unescape};

    #[test]
    fn test_unescape() {
        assert_eq!(unescape(b"foo", false).unwrap(), b"foo");
        assert_eq!(unescape(b"f\\noo", false).unwrap(), b"f\noo");
        assert_eq!(unescape(b"f\\x01oo", false).unwrap(), b"f\x01oo");
        assert_eq!(unescape(b"f\\375oo", false).unwrap(), b"f\xfdoo");
        assert_eq!(unescape(b"f\\75oo", false).unwrap(), b"f\x3doo");
        assert_eq!(unescape(b"f\\5oo", false).unwrap(), b"f\x05oo");
        assert_eq!(unescape(b"f\\oo", false).unwrap(), b"f\\oo");
        assert_eq!(unescape(b"f\\coo", false).unwrap(), b"f\\coo");
        assert_eq!(unescape(b"f\\U00002663oo", true).unwrap(), b"f\xe2\x99\xa3oo");
    }
}<|endoftext|>


<commit_before>use core::panic;
//
use std::sync::mpsc::channel;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::Sender;
use std::thread;

use parking_lot::RwLock;
use std::rc::Rc;
use std::sync::Arc;

#[macro_use]
pub(crate) mod macros;

pub mod codec;
pub mod codepointinfo;
pub mod config;
pub mod document;
pub mod editor;
pub mod event;
pub mod mapped_file;
pub mod modes;
pub mod screen;
pub mod view;

use crate::core::config::Config;
use crate::core::document::Document;
use crate::core::editor::Editor;
use crate::core::editor::EditorEnv;
use crate::core::event::Event;
use crate::core::event::EventMessage;
use crate::core::view::View;

pub const VERSION: &str = env!("CARGO_PKG_VERSION");

use std::sync::atomic::{AtomicUsize, Ordering};

//
pub static DBG_PRINTLN_FLAG: AtomicUsize = AtomicUsize::new(0);

pub fn enable_dbg_println() {
    DBG_PRINTLN_FLAG.store(1, Ordering::Relaxed);
}
pub fn disable_dbg_println() {
    DBG_PRINTLN_FLAG.store(0, Ordering::Relaxed);
}
pub fn toggle_dbg_println() {
    let v = DBG_PRINTLN_FLAG.load(Ordering::Relaxed);
    if v != 0 {
        disable_dbg_println();
    } else {
        enable_dbg_println();
    }
}

//
pub static USE_READ_CACHE: AtomicUsize = AtomicUsize::new(1);
pub fn disable_read_cache() {
    USE_READ_CACHE.store(0, Ordering::Relaxed);
}

pub fn use_read_cache() -> bool {
    USE_READ_CACHE.load(Ordering::Relaxed) != 0
}

//
pub static USE_BYTE_INDEX: AtomicUsize = AtomicUsize::new(1);
pub fn disable_byte_index() {
    USE_BYTE_INDEX.store(0, Ordering::Relaxed);
}

pub fn use_byte_index() -> bool {
    USE_BYTE_INDEX.load(Ordering::Relaxed) != 0
}

//
pub static BENCH_TO_EOF: AtomicUsize = AtomicUsize::new(0);
pub fn enable_bench_to_eof() {
    BENCH_TO_EOF.store(1, Ordering::Relaxed);
}
pub fn bench_to_eof() -> bool {
    BENCH_TO_EOF.load(Ordering::Relaxed) != 0
}

//
pub static RAW_FILTER_TO_SCREEN: AtomicUsize = AtomicUsize::new(0);
pub fn enable_raw_data_filter_to_screen() {
    RAW_FILTER_TO_SCREEN.store(1, Ordering::Relaxed);
}
pub fn raw_data_filter_to_screen() -> bool {
    RAW_FILTER_TO_SCREEN.load(Ordering::Relaxed) != 0
}

//
pub static NO_UI_RENDER: AtomicUsize = AtomicUsize::new(0);
pub fn set_no_ui_render(b: bool) {
    if b {
        NO_UI_RENDER.store(1, Ordering::Relaxed);
    } else {
        NO_UI_RENDER.store(0, Ordering::Relaxed);
    }
}
pub fn no_ui_render() -> bool {
    NO_UI_RENDER.load(Ordering::Relaxed) != 0
}

/*
 TODO(ceg):

    "core-mode" {
        scrollbar-mode
        v-split-mode
        h-split-mode
    }

text-mode =
    "raw-data"
    "utf8-codec"
    "mark-mode"
    "undo-mode"
    ----------
    "wrap-line"
    "wrap-word"

    --------------
    "replay-mode"

    "tab-mode"
    "selection/high-light"
    "fold-mode"
    "search-mode"
    "regex-mode"

    "exec-bin-mode"

    "dir-mode"

    "shell-mode"

    "ffi-mode"

    "hex-mode"

    "follow-mode"

    split layout.rs -> modes

  document.predefined_modes() Option<vec["internal:welcome-mode"]>
  document.predefined_modes() Option<vec["internal:debug-message"]>

  based on extension we will load predefine modes / keywords list etc ..

    replay-mode
      ctrl+x ctrl+x r :  {left,right} alt+{left,right}
*/

pub static WELCOME_MESSAGE: &str = r#"-*- Welcome to unlimitED! -*-

unlimitED! is an experimental text editor (running in the terminal).

SYNOPSIS
unlimited [options] [file ..]

It comes with:

  - basic UTF-8 support
  - very large file support
  - "infinite" undo/redo
  - multi-cursors
  - mouse selection (X11 terminal)

[Quit]
    Quit:           => ctrl+x ctrl+c

    Quit (no save)  => ctrl+x ctrl+q

    NB: quit will wait for large file(s) sync to storage.

[Moves]
    Left            =>
    Right           =>
    Up              =>
    Down            =>

[Edit]
    ctrl+o          => Open file

    ctrl+u          => Undo
    ctrl+r          => Redo

[Selection/Copy/Paste]
    with the keyboard:

    with the mouse (X11 terminal):

[Save]
    ctrl+x ctrl+s   => Save
                    synchronization of large file(s) does not block the ui.
                    the the is in "synchronization"

[Document Selection]

NB: unlimitED! comes with ABSOLUTELY NO WARRANTY
"#;

/// This function is the core of the editor.
/// It should be ran in an other thread than the main one (which is kept for ui)
pub fn run<'a>(
    config: Config,
    core_rx: &Receiver<EventMessage<'static>>,
    core_tx: &Sender<EventMessage<'static>>,
    ui_tx: &Sender<EventMessage<'static>>,
) {
    let (worker_tx, worker_rx) = channel();
    let (indexer_tx, indexer_rx) = channel();

    let mut editor = Editor::new(
        config,
        core_tx.clone(),
        ui_tx.clone(),
        worker_tx.clone(),
        indexer_tx.clone(),
    );
    let mut env = EditorEnv::new();

    // create worker thread
    let worker_th = {
        let core_tx = core_tx.clone();
        Some(thread::spawn(move || worker(&worker_rx, &core_tx)))
    };
    let indexer_th = {
        let core_tx = core_tx.clone();
        Some(thread::spawn(move || indexer(&indexer_rx, &core_tx)))
    };

    editor.worker_tx = worker_tx.clone();

    load_modes(&mut editor, &mut env);

    load_files(&mut editor, &mut env);

    create_views(&mut editor, &mut env);

    editor::main_loop(&mut editor, &mut env, &core_rx, &ui_tx);

    // wait for worker thread
    if let Some(worker_handle) = worker_th {
        worker_handle.join().unwrap()
    }
    if let Some(indexer_handle) = indexer_th {
        indexer_handle.join().unwrap()
    }
}

/////////////////////// worker.rs

pub fn worker(
    worker_rx: &Receiver<EventMessage<'static>>,
    _core_tx: &Sender<EventMessage<'static>>,
) {
    dbg_println!("[starting worker thread]");
    loop {
        if let Ok(evt) = worker_rx.recv() {
            match evt.event {
                Event::ApplicationQuitEvent => {
                    dbg_println!("[stopping worker thread]");
                    break;
                }

                Event::SyncTask { doc } => {
                    document::sync_to_storage(&doc);
                }

                //                Event::OutsourcedTask { task_uid,  editor, editor_env, doc_id, vid, action, params ? } => {
                //                    action();
                //                }
                _ => {
                    panic!("worker thread received an unexpected message");
                }
            }
        }
    }
}

pub fn indexer(
    worker_rx: &Receiver<EventMessage<'static>>,
    core_tx: &Sender<EventMessage<'static>>,
) {
    if !use_byte_index() {
        return;
    }

    dbg_println!("[starting worker thread (indexer)]");
    loop {
        if let Ok(evt) = worker_rx.recv() {
            match evt.event {
                Event::ApplicationQuitEvent => {
                    dbg_println!("[stopping worker thread]");
                    break;
                }

                // TODO(ceg): split in sub-threads/async task
                Event::IndexTask { document_map } => {
                    dbg_println!("[receive index task ]");

                    let mut refresh_ui = false;
                    let map = document_map.read();
                    let mut t0 = std::time::Instant::now();
                    for (_id, doc) in map.iter() {
                        document::build_index(doc);
                        refresh_ui = true;
                        let t1 = std::time::Instant::now();
                        if (t1 - t0).as_millis() > 1000 {
                            // send ui refresh event
                            let msg = EventMessage::new(0, Event::RefreshViewEvent);
                            core_tx.send(msg).unwrap_or(());

                            refresh_ui = false;
                            t0 = t1;
                        }
                    }

                    // last ui refresh
                    if refresh_ui {
                        let msg = EventMessage::new(0, Event::RefreshViewEvent);
                        core_tx.send(msg).unwrap_or(());
                    }
                }

                _ => {
                    panic!("worker thread received an unexpected message");
                }
            }
        }
    }
}

use crate::core::document::DocumentBuilder;

/// TODO(ceg): replace this by load/unload doc functions
/// the ui will open the documents on demand
pub fn load_files(editor: &mut Editor<'static>, env: &mut EditorEnv<'static>) {
    let mut id = editor.document_map.read().len();

    for f in &editor.config.files_list {
        let b = DocumentBuilder::new()
            .document_name(f)
            .file_name(f)
            .internal(false)
            .finalize();

        if let Some(b) = b {
            let doc_id = document::Id(id);
            b.as_ref().write().id = doc_id; // TODO(ceg): improve doc id generation
            editor.document_map.write().insert(doc_id, b);
            id += 1;
        }
    }

    // default buffer ?
    let map_is_empty = editor.document_map.read().is_empty();
    if map_is_empty {
        // edit.get_untitled_count() -> 1

        let b = DocumentBuilder::new()
            .document_name("untitled-1")
            .internal(false)
            .finalize();
        if let Some(b) = b {
            {
                let mut d = b.write();
                let s = WELCOME_MESSAGE.as_bytes();

                // move 1st tag to ctor/doc::new() ?
                d.tag(env.current_time, 0, vec![0]); // TODO(ceg): rm this only if the buffer log is cleared
                                                     //    create_views(&mut editor, &mut env);

                d.insert(0, s.len(), s);

                // do not allow to go back to empty buffer
                d.buffer_log_reset();
                d.changed = false;
            }
            let doc_id = document::Id(id);
            editor.document_map.write().insert(doc_id, b);
            id += 1;
        }
    }

    // configure document
    let modes = editor.modes.clone();
    for (mode_name, mode) in modes.borrow().iter() {
        // per mode document metadata
        dbg_println!("setup mode[{}] document metadata", mode_name);
        let mut mode = mode.borrow_mut();
        let map = editor.document_map.clone();
        let mut map = map.as_ref().write();
        for (_, doc) in map.iter_mut() {
            let mut doc = doc.write();
            mode.configure_document(editor, env, &mut doc);
        }
    }

    dbg_println!("id {}", id);
}

pub fn create_views(mut editor: &mut Editor<'static>, mut env: &mut EditorEnv<'static>) {
    let document_map = editor.document_map.clone();
    let document_map = document_map.read();

    // create default views
    // sort by arg pos first
    let mut docs_id: Vec<document::Id> = document_map.iter().map(|(k, _v)| *k).collect();
    docs_id.sort();
    let mut docs: Vec<Arc<RwLock<Document>>> = vec![];
    for id in docs_id.iter() {
        if let Some(doc) = document_map.get(id) {
            docs.push(Arc::clone(doc));
        }
    }

    let modes = match std::env::var("SINGLE_VIEW") {
        Ok(_) => vec!["simple-view".to_owned()],
        _ => vec!["basic-editor".to_owned()],
    };

    // create views
    for doc in docs {
        let view = View::new(
            &mut editor,
            &mut env,
            None,
            0,
            0,
            1,
            1,
            Some(doc),
            &modes,
            0,
        );
        dbg_println!("create {:?}", view.id);

        // top level views
        editor.root_views.push(view.id);
        editor.view_map.insert(view.id, Rc::new(RwLock::new(view)));
    }

    // index documents
    // TODO(ceg): send one event per doc
    if true {
        let msg = EventMessage {
            seq: 0,
            event: Event::IndexTask {
                document_map: Arc::clone(&editor.document_map),
            },
        };
        editor.indexer_tx.send(msg).unwrap_or(());
    }
}

use crate::core::modes::BasicEditorMode;
use crate::core::modes::SimpleViewMode;

use crate::core::modes::CoreMode;
use crate::core::modes::FindMode;
use crate::core::modes::TextMode;

use crate::core::modes::StatusMode;

use crate::core::modes::HsplitMode;
use crate::core::modes::VsplitMode;

use crate::core::modes::VscrollbarMode;

use crate::core::modes::LineNumberMode;

pub fn load_modes(editor: &mut Editor, _env: &mut EditorEnv) {
    // set default mode(s)
    editor.register_mode(Box::new(CoreMode::new()));
    editor.register_mode(Box::new(BasicEditorMode::new()));
    editor.register_mode(Box::new(SimpleViewMode::new()));

    editor.register_mode(Box::new(VsplitMode::new()));
    editor.register_mode(Box::new(HsplitMode::new()));

    editor.register_mode(Box::new(VscrollbarMode::new()));

    editor.register_mode(Box::new(TextMode::new()));
    editor.register_mode(Box::new(StatusMode::new()));

    editor.register_mode(Box::new(FindMode::new()));

    editor.register_mode(Box::new(LineNumberMode::new()));
}
<commit_msg>ignore directories (temporary)<commit_after>use core::panic;
//
use std::fs;
use std::sync::mpsc::channel;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::Sender;
use std::thread;

use parking_lot::RwLock;
use std::rc::Rc;
use std::sync::Arc;

#[macro_use]
pub(crate) mod macros;

pub mod codec;
pub mod codepointinfo;
pub mod config;
pub mod document;
pub mod editor;
pub mod event;
pub mod mapped_file;
pub mod modes;
pub mod screen;
pub mod view;

use crate::core::config::Config;
use crate::core::document::Document;
use crate::core::editor::Editor;
use crate::core::editor::EditorEnv;
use crate::core::event::Event;
use crate::core::event::EventMessage;
use crate::core::view::View;

pub const VERSION: &str = env!("CARGO_PKG_VERSION");

use std::sync::atomic::{AtomicUsize, Ordering};

//
pub static DBG_PRINTLN_FLAG: AtomicUsize = AtomicUsize::new(0);

pub fn enable_dbg_println() {
    DBG_PRINTLN_FLAG.store(1, Ordering::Relaxed);
}
pub fn disable_dbg_println() {
    DBG_PRINTLN_FLAG.store(0, Ordering::Relaxed);
}
pub fn toggle_dbg_println() {
    let v = DBG_PRINTLN_FLAG.load(Ordering::Relaxed);
    if v != 0 {
        disable_dbg_println();
    } else {
        enable_dbg_println();
    }
}

//
pub static USE_READ_CACHE: AtomicUsize = AtomicUsize::new(1);
pub fn disable_read_cache() {
    USE_READ_CACHE.store(0, Ordering::Relaxed);
}

pub fn use_read_cache() -> bool {
    USE_READ_CACHE.load(Ordering::Relaxed) != 0
}

//
pub static USE_BYTE_INDEX: AtomicUsize = AtomicUsize::new(1);
pub fn disable_byte_index() {
    USE_BYTE_INDEX.store(0, Ordering::Relaxed);
}

pub fn use_byte_index() -> bool {
    USE_BYTE_INDEX.load(Ordering::Relaxed) != 0
}

//
pub static BENCH_TO_EOF: AtomicUsize = AtomicUsize::new(0);
pub fn enable_bench_to_eof() {
    BENCH_TO_EOF.store(1, Ordering::Relaxed);
}
pub fn bench_to_eof() -> bool {
    BENCH_TO_EOF.load(Ordering::Relaxed) != 0
}

//
pub static RAW_FILTER_TO_SCREEN: AtomicUsize = AtomicUsize::new(0);
pub fn enable_raw_data_filter_to_screen() {
    RAW_FILTER_TO_SCREEN.store(1, Ordering::Relaxed);
}
pub fn raw_data_filter_to_screen() -> bool {
    RAW_FILTER_TO_SCREEN.load(Ordering::Relaxed) != 0
}

//
pub static NO_UI_RENDER: AtomicUsize = AtomicUsize::new(0);
pub fn set_no_ui_render(b: bool) {
    if b {
        NO_UI_RENDER.store(1, Ordering::Relaxed);
    } else {
        NO_UI_RENDER.store(0, Ordering::Relaxed);
    }
}
pub fn no_ui_render() -> bool {
    NO_UI_RENDER.load(Ordering::Relaxed) != 0
}

/*
 TODO(ceg):

    "core-mode" {
        scrollbar-mode
        v-split-mode
        h-split-mode
    }

text-mode =
    "raw-data"
    "utf8-codec"
    "mark-mode"
    "undo-mode"
    ----------
    "wrap-line"
    "wrap-word"

    --------------
    "replay-mode"

    "tab-mode"
    "selection/high-light"
    "fold-mode"
    "search-mode"
    "regex-mode"

    "exec-bin-mode"

    "dir-mode"

    "shell-mode"

    "ffi-mode"

    "hex-mode"

    "follow-mode"

    split layout.rs -> modes

  document.predefined_modes() Option<vec["internal:welcome-mode"]>
  document.predefined_modes() Option<vec["internal:debug-message"]>

  based on extension we will load predefine modes / keywords list etc ..

    replay-mode
      ctrl+x ctrl+x r :  {left,right} alt+{left,right}
*/

pub static WELCOME_MESSAGE: &str = r#"-*- Welcome to unlimitED! -*-

unlimitED! is an experimental text editor (running in the terminal).

SYNOPSIS
unlimited [options] [file ..]

It comes with:

  - basic UTF-8 support
  - very large file support
  - "infinite" undo/redo
  - multi-cursors
  - mouse selection (X11 terminal)

[Quit]
    Quit:           => ctrl+x ctrl+c

    Quit (no save)  => ctrl+x ctrl+q

    NB: quit will wait for large file(s) sync to storage.

[Moves]
    Left            =>
    Right           =>
    Up              =>
    Down            =>

[Edit]
    ctrl+o          => Open file

    ctrl+u          => Undo
    ctrl+r          => Redo

[Selection/Copy/Paste]
    with the keyboard:

    with the mouse (X11 terminal):

[Save]
    ctrl+x ctrl+s   => Save
                    synchronization of large file(s) does not block the ui.
                    the the is in "synchronization"

[Document Selection]

NB: unlimitED! comes with ABSOLUTELY NO WARRANTY
"#;

/// This function is the core of the editor.
/// It should be ran in an other thread than the main one (which is kept for ui)
pub fn run<'a>(
    config: Config,
    core_rx: &Receiver<EventMessage<'static>>,
    core_tx: &Sender<EventMessage<'static>>,
    ui_tx: &Sender<EventMessage<'static>>,
) {
    let (worker_tx, worker_rx) = channel();
    let (indexer_tx, indexer_rx) = channel();

    let mut editor = Editor::new(
        config,
        core_tx.clone(),
        ui_tx.clone(),
        worker_tx.clone(),
        indexer_tx.clone(),
    );
    let mut env = EditorEnv::new();

    // create worker thread
    let worker_th = {
        let core_tx = core_tx.clone();
        Some(thread::spawn(move || worker(&worker_rx, &core_tx)))
    };
    let indexer_th = {
        let core_tx = core_tx.clone();
        Some(thread::spawn(move || indexer(&indexer_rx, &core_tx)))
    };

    editor.worker_tx = worker_tx.clone();

    load_modes(&mut editor, &mut env);

    load_files(&mut editor, &mut env);

    create_views(&mut editor, &mut env);

    editor::main_loop(&mut editor, &mut env, &core_rx, &ui_tx);

    // wait for worker thread
    if let Some(worker_handle) = worker_th {
        worker_handle.join().unwrap()
    }
    if let Some(indexer_handle) = indexer_th {
        indexer_handle.join().unwrap()
    }
}

/////////////////////// worker.rs

pub fn worker(
    worker_rx: &Receiver<EventMessage<'static>>,
    _core_tx: &Sender<EventMessage<'static>>,
) {
    dbg_println!("[starting worker thread]");
    loop {
        if let Ok(evt) = worker_rx.recv() {
            match evt.event {
                Event::ApplicationQuitEvent => {
                    dbg_println!("[stopping worker thread]");
                    break;
                }

                Event::SyncTask { doc } => {
                    document::sync_to_storage(&doc);
                }

                //                Event::OutsourcedTask { task_uid,  editor, editor_env, doc_id, vid, action, params ? } => {
                //                    action();
                //                }
                _ => {
                    panic!("worker thread received an unexpected message");
                }
            }
        }
    }
}

pub fn indexer(
    worker_rx: &Receiver<EventMessage<'static>>,
    core_tx: &Sender<EventMessage<'static>>,
) {
    if !use_byte_index() {
        return;
    }

    dbg_println!("[starting worker thread (indexer)]");
    loop {
        if let Ok(evt) = worker_rx.recv() {
            match evt.event {
                Event::ApplicationQuitEvent => {
                    dbg_println!("[stopping worker thread]");
                    break;
                }

                // TODO(ceg): split in sub-threads/async task
                Event::IndexTask { document_map } => {
                    dbg_println!("[receive index task ]");

                    let mut refresh_ui = false;
                    let map = document_map.read();
                    let mut t0 = std::time::Instant::now();
                    for (_id, doc) in map.iter() {
                        document::build_index(doc);
                        refresh_ui = true;
                        let t1 = std::time::Instant::now();
                        if (t1 - t0).as_millis() > 1000 {
                            // send ui refresh event
                            let msg = EventMessage::new(0, Event::RefreshViewEvent);
                            core_tx.send(msg).unwrap_or(());

                            refresh_ui = false;
                            t0 = t1;
                        }
                    }

                    // last ui refresh
                    if refresh_ui {
                        let msg = EventMessage::new(0, Event::RefreshViewEvent);
                        core_tx.send(msg).unwrap_or(());
                    }
                }

                _ => {
                    panic!("worker thread received an unexpected message");
                }
            }
        }
    }
}

use crate::core::document::DocumentBuilder;

/// TODO(ceg): replace this by load/unload doc functions
/// the ui will open the documents on demand
pub fn load_files(editor: &mut Editor<'static>, env: &mut EditorEnv<'static>) {
    let mut id = editor.document_map.read().len();

    for f in &editor.config.files_list {
        // check file type
        if let Ok(metadata) = fs::metadata(f) {
            let file_type = metadata.file_type();

            // ignore directories for now
            if file_type.is_dir() {
                continue;
            }
        } else {
            // log error
            eprintln!("cannot check {} file type", f);
            continue;
        }

        let b = DocumentBuilder::new()
            .document_name(f)
            .file_name(f)
            .internal(false)
            .finalize();

        if let Some(b) = b {
            let doc_id = document::Id(id);
            b.as_ref().write().id = doc_id; // TODO(ceg): improve doc id generation
            editor.document_map.write().insert(doc_id, b);
            id += 1;
        }
    }

    // default buffer ?
    let map_is_empty = editor.document_map.read().is_empty();
    if map_is_empty {
        // edit.get_untitled_count() -> 1

        let b = DocumentBuilder::new()
            .document_name("untitled-1")
            .internal(false)
            .finalize();
        if let Some(b) = b {
            {
                let mut d = b.write();
                let s = WELCOME_MESSAGE.as_bytes();

                // move 1st tag to ctor/doc::new() ?
                d.tag(env.current_time, 0, vec![0]); // TODO(ceg): rm this only if the buffer log is cleared
                                                     //    create_views(&mut editor, &mut env);

                d.insert(0, s.len(), s);

                // do not allow to go back to empty buffer
                d.buffer_log_reset();
                d.changed = false;
            }
            let doc_id = document::Id(id);
            editor.document_map.write().insert(doc_id, b);
            id += 1;
        }
    }

    // configure document
    let modes = editor.modes.clone();
    for (mode_name, mode) in modes.borrow().iter() {
        // per mode document metadata
        dbg_println!("setup mode[{}] document metadata", mode_name);
        let mut mode = mode.borrow_mut();
        let map = editor.document_map.clone();
        let mut map = map.as_ref().write();
        for (_, doc) in map.iter_mut() {
            let mut doc = doc.write();
            mode.configure_document(editor, env, &mut doc);
        }
    }

    dbg_println!("id {}", id);
}

pub fn create_views(mut editor: &mut Editor<'static>, mut env: &mut EditorEnv<'static>) {
    let document_map = editor.document_map.clone();
    let document_map = document_map.read();

    // create default views
    // sort by arg pos first
    let mut docs_id: Vec<document::Id> = document_map.iter().map(|(k, _v)| *k).collect();
    docs_id.sort();
    let mut docs: Vec<Arc<RwLock<Document>>> = vec![];
    for id in docs_id.iter() {
        if let Some(doc) = document_map.get(id) {
            docs.push(Arc::clone(doc));
        }
    }

    let modes = match std::env::var("SINGLE_VIEW") {
        Ok(_) => vec!["simple-view".to_owned()],
        _ => vec!["basic-editor".to_owned()],
    };

    // create views
    for doc in docs {
        let view = View::new(
            &mut editor,
            &mut env,
            None,
            0,
            0,
            1,
            1,
            Some(doc),
            &modes,
            0,
        );
        dbg_println!("create {:?}", view.id);

        // top level views
        editor.root_views.push(view.id);
        editor.view_map.insert(view.id, Rc::new(RwLock::new(view)));
    }

    // index documents
    // TODO(ceg): send one event per doc
    if true {
        let msg = EventMessage {
            seq: 0,
            event: Event::IndexTask {
                document_map: Arc::clone(&editor.document_map),
            },
        };
        editor.indexer_tx.send(msg).unwrap_or(());
    }
}

use crate::core::modes::BasicEditorMode;
use crate::core::modes::SimpleViewMode;

use crate::core::modes::CoreMode;
use crate::core::modes::FindMode;
use crate::core::modes::TextMode;

use crate::core::modes::StatusMode;

use crate::core::modes::HsplitMode;
use crate::core::modes::VsplitMode;

use crate::core::modes::VscrollbarMode;

use crate::core::modes::LineNumberMode;

pub fn load_modes(editor: &mut Editor, _env: &mut EditorEnv) {
    // set default mode(s)
    editor.register_mode(Box::new(CoreMode::new()));
    editor.register_mode(Box::new(BasicEditorMode::new()));
    editor.register_mode(Box::new(SimpleViewMode::new()));

    editor.register_mode(Box::new(VsplitMode::new()));
    editor.register_mode(Box::new(HsplitMode::new()));

    editor.register_mode(Box::new(VscrollbarMode::new()));

    editor.register_mode(Box::new(TextMode::new()));
    editor.register_mode(Box::new(StatusMode::new()));

    editor.register_mode(Box::new(FindMode::new()));

    editor.register_mode(Box::new(LineNumberMode::new()));
}
<|endoftext|>


<commit_before>use Printer;
use direction::Direction;
use event::{Event, EventResult};
use std::any::Any;
use vec::Vec2;
use view::{Selector, View};

/// Generic wrapper around a view.
///
/// This trait is a shortcut to implement `View` on a type by forwarding
/// calls to a wrapped view.
///
/// You only need to define `with_view` and `with_view_mut`
/// (the [`wrap_impl!`] macro can help you with that), and you will get
/// the `View` implementation for free.
///
/// You can also override any of the `wrap_*` methods for more specific
/// behaviors (the default implementations simply forwards the calls to the
/// child view).
///
/// [`wrap_impl!`]: ../macro.wrap_impl.html
pub trait ViewWrapper: 'static {
    /// Type that this view wraps.
    type V: View + ?Sized;

    /// Runs a function on the inner view, returning the result.
    ///
    /// Returns `None` if the inner view is unavailable.  This should only
    /// happen with some views if they are already borrowed by another call.
    fn with_view<F, R>(&self, f: F) -> Option<R>
    where
        F: FnOnce(&Self::V) -> R;

    /// Runs a function on the inner view, returning the result.
    ///
    /// Returns `None` if the inner view is unavailable.  This should only
    /// happen with some views if they are already borrowed by another call.
    fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
    where
        F: FnOnce(&mut Self::V) -> R;

    /// Attempts to retrieve the inner view.
    fn into_inner(self) -> Result<Self::V, Self>
    where
        Self: Sized,
        Self::V: Sized,
    {
        Err(self)
    }

    /// Wraps the `draw` method.
    fn wrap_draw(&self, printer: &Printer) {
        self.with_view(|v| v.draw(printer));
    }

    /// Wraps the `required_size` method.
    fn wrap_required_size(&mut self, req: Vec2) -> Vec2 {
        self.with_view_mut(|v| v.required_size(req))
            .unwrap_or_else(Vec2::zero)
    }

    /// Wraps the `on_event` method.
    fn wrap_on_event(&mut self, ch: Event) -> EventResult {
        self.with_view_mut(|v| v.on_event(ch))
            .unwrap_or(EventResult::Ignored)
    }

    /// Wraps the `layout` method.
    fn wrap_layout(&mut self, size: Vec2) {
        self.with_view_mut(|v| v.layout(size));
    }

    /// Wraps the `take_focus` method.
    fn wrap_take_focus(&mut self, source: Direction) -> bool {
        self.with_view_mut(|v| v.take_focus(source))
            .unwrap_or(false)
    }

    /// Wraps the `find` method.
    fn wrap_call_on_any<'a>(
        &mut self, selector: &Selector, callback: Box<FnMut(&mut Any) + 'a>
    ) {
        self.with_view_mut(|v| v.call_on_any(selector, callback));
    }

    /// Wraps the `focus_view` method.
    fn wrap_focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
        self.with_view_mut(|v| v.focus_view(selector))
            .unwrap_or(Err(()))
    }

    /// Wraps the `needs_relayout` method.
    fn wrap_needs_relayout(&self) -> bool {
        self.with_view(|v| v.needs_relayout()).unwrap_or(true)
    }
}

// Some types easily implement ViewWrapper.
// This includes Box<T: View>
use std::ops::{Deref, DerefMut};

impl<U, T> ViewWrapper for T
where
    U: View + ?Sized,
    T: Deref<Target = U> + DerefMut + 'static,
{
    type V = U;

    fn with_view<F, R>(&self, f: F) -> Option<R>
    where
        F: FnOnce(&Self::V) -> R,
    {
        Some(f(self.deref()))
    }

    fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
    where
        F: FnOnce(&mut Self::V) -> R,
    {
        Some(f(self.deref_mut()))
    }
}

// The main point of implementing ViewWrapper is to have View for free.
impl<T: ViewWrapper> View for T {
    fn draw(&self, printer: &Printer) {
        self.wrap_draw(printer);
    }

    fn required_size(&mut self, req: Vec2) -> Vec2 {
        self.wrap_required_size(req)
    }

    fn on_event(&mut self, ch: Event) -> EventResult {
        self.wrap_on_event(ch)
    }

    fn layout(&mut self, size: Vec2) {
        self.wrap_layout(size);
    }

    fn take_focus(&mut self, source: Direction) -> bool {
        self.wrap_take_focus(source)
    }

    fn call_on_any<'a>(
        &mut self, selector: &Selector, callback: Box<FnMut(&mut Any) + 'a>
    ) {
        self.wrap_call_on_any(selector, callback)
    }

    fn needs_relayout(&self) -> bool {
        self.wrap_needs_relayout()
    }

    fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
        self.wrap_focus_view(selector)
    }
}

/// Convenient macro to implement the [`ViewWrapper`] trait.
///
/// It defines the `with_view` and `with_view_mut` implementations,
/// as well as the `type V` declaration.
///
/// [`ViewWrapper`]: view/trait.ViewWrapper.html
///
/// # Examples
///
/// ```no_run
/// # #[macro_use] extern crate cursive;
/// # use cursive::view::{View,ViewWrapper};
/// struct FooView<T: View> {
///     view: T,
/// }
///
/// impl <T: View> ViewWrapper for FooView<T> {
///     wrap_impl!(self.view: T);
/// }
/// # fn main() { }
/// ```
#[macro_export]
macro_rules! wrap_impl {
    (self.$v:ident: $t:ty) => {
        type V = $t;

        fn with_view<F, R>(&self, f: F) -> Option<R>
            where F: FnOnce(&Self::V) -> R
        {
            Some(f(&self.$v))
        }

        fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
            where F: FnOnce(&mut Self::V) -> R
        {
            Some(f(&mut self.$v))
        }

        fn into_inner(self) -> Result<Self::V, Self> where Self::V: Sized {
            Ok(self.$v)
        }
    };
}

/// Convenient macro to implement the getters for inner [`View`] in [`ViewWrapper`].
///
/// It defines the `get_inner` and `get_inner_mut` implementations.
///
/// [`ViewWrapper`]: view/trait.ViewWrapper.html
/// [`View`]: view/trait.View.html
///
/// # Examples
///
/// ```no_run
/// # #[macro_use] extern crate cursive;
/// # use cursive::view::{View,ViewWrapper};
/// struct FooView<T: View> {
///     view: T,
/// }
///
/// impl<T: View> FooView<T> {
///     inner_getters!(self.view: T);
/// }
///
/// impl <T: View> ViewWrapper for FooView<T> {
///     wrap_impl!(self.view: T);
/// }
/// # fn main() { }
/// ```
#[macro_export]
macro_rules! inner_getters {
    (self.$v:ident: $t:ty) => {
        /// Gets access to the inner view.
        pub fn get_inner(&self) -> &$t {
            &self.view
        }
        /// Gets mutable access to the inner view.
        pub fn get_inner_mut(&mut self) -> &mut $t {
            &mut self.view
        }
    }
}
<commit_msg>Fix getting view in inner_getters<commit_after>use Printer;
use direction::Direction;
use event::{Event, EventResult};
use std::any::Any;
use vec::Vec2;
use view::{Selector, View};

/// Generic wrapper around a view.
///
/// This trait is a shortcut to implement `View` on a type by forwarding
/// calls to a wrapped view.
///
/// You only need to define `with_view` and `with_view_mut`
/// (the [`wrap_impl!`] macro can help you with that), and you will get
/// the `View` implementation for free.
///
/// You can also override any of the `wrap_*` methods for more specific
/// behaviors (the default implementations simply forwards the calls to the
/// child view).
///
/// [`wrap_impl!`]: ../macro.wrap_impl.html
pub trait ViewWrapper: 'static {
    /// Type that this view wraps.
    type V: View + ?Sized;

    /// Runs a function on the inner view, returning the result.
    ///
    /// Returns `None` if the inner view is unavailable.  This should only
    /// happen with some views if they are already borrowed by another call.
    fn with_view<F, R>(&self, f: F) -> Option<R>
    where
        F: FnOnce(&Self::V) -> R;

    /// Runs a function on the inner view, returning the result.
    ///
    /// Returns `None` if the inner view is unavailable.  This should only
    /// happen with some views if they are already borrowed by another call.
    fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
    where
        F: FnOnce(&mut Self::V) -> R;

    /// Attempts to retrieve the inner view.
    fn into_inner(self) -> Result<Self::V, Self>
    where
        Self: Sized,
        Self::V: Sized,
    {
        Err(self)
    }

    /// Wraps the `draw` method.
    fn wrap_draw(&self, printer: &Printer) {
        self.with_view(|v| v.draw(printer));
    }

    /// Wraps the `required_size` method.
    fn wrap_required_size(&mut self, req: Vec2) -> Vec2 {
        self.with_view_mut(|v| v.required_size(req))
            .unwrap_or_else(Vec2::zero)
    }

    /// Wraps the `on_event` method.
    fn wrap_on_event(&mut self, ch: Event) -> EventResult {
        self.with_view_mut(|v| v.on_event(ch))
            .unwrap_or(EventResult::Ignored)
    }

    /// Wraps the `layout` method.
    fn wrap_layout(&mut self, size: Vec2) {
        self.with_view_mut(|v| v.layout(size));
    }

    /// Wraps the `take_focus` method.
    fn wrap_take_focus(&mut self, source: Direction) -> bool {
        self.with_view_mut(|v| v.take_focus(source))
            .unwrap_or(false)
    }

    /// Wraps the `find` method.
    fn wrap_call_on_any<'a>(
        &mut self, selector: &Selector, callback: Box<FnMut(&mut Any) + 'a>
    ) {
        self.with_view_mut(|v| v.call_on_any(selector, callback));
    }

    /// Wraps the `focus_view` method.
    fn wrap_focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
        self.with_view_mut(|v| v.focus_view(selector))
            .unwrap_or(Err(()))
    }

    /// Wraps the `needs_relayout` method.
    fn wrap_needs_relayout(&self) -> bool {
        self.with_view(|v| v.needs_relayout()).unwrap_or(true)
    }
}

// Some types easily implement ViewWrapper.
// This includes Box<T: View>
use std::ops::{Deref, DerefMut};

impl<U, T> ViewWrapper for T
where
    U: View + ?Sized,
    T: Deref<Target = U> + DerefMut + 'static,
{
    type V = U;

    fn with_view<F, R>(&self, f: F) -> Option<R>
    where
        F: FnOnce(&Self::V) -> R,
    {
        Some(f(self.deref()))
    }

    fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
    where
        F: FnOnce(&mut Self::V) -> R,
    {
        Some(f(self.deref_mut()))
    }
}

// The main point of implementing ViewWrapper is to have View for free.
impl<T: ViewWrapper> View for T {
    fn draw(&self, printer: &Printer) {
        self.wrap_draw(printer);
    }

    fn required_size(&mut self, req: Vec2) -> Vec2 {
        self.wrap_required_size(req)
    }

    fn on_event(&mut self, ch: Event) -> EventResult {
        self.wrap_on_event(ch)
    }

    fn layout(&mut self, size: Vec2) {
        self.wrap_layout(size);
    }

    fn take_focus(&mut self, source: Direction) -> bool {
        self.wrap_take_focus(source)
    }

    fn call_on_any<'a>(
        &mut self, selector: &Selector, callback: Box<FnMut(&mut Any) + 'a>
    ) {
        self.wrap_call_on_any(selector, callback)
    }

    fn needs_relayout(&self) -> bool {
        self.wrap_needs_relayout()
    }

    fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
        self.wrap_focus_view(selector)
    }
}

/// Convenient macro to implement the [`ViewWrapper`] trait.
///
/// It defines the `with_view` and `with_view_mut` implementations,
/// as well as the `type V` declaration.
///
/// [`ViewWrapper`]: view/trait.ViewWrapper.html
///
/// # Examples
///
/// ```no_run
/// # #[macro_use] extern crate cursive;
/// # use cursive::view::{View,ViewWrapper};
/// struct FooView<T: View> {
///     view: T,
/// }
///
/// impl <T: View> ViewWrapper for FooView<T> {
///     wrap_impl!(self.view: T);
/// }
/// # fn main() { }
/// ```
#[macro_export]
macro_rules! wrap_impl {
    (self.$v:ident: $t:ty) => {
        type V = $t;

        fn with_view<F, R>(&self, f: F) -> Option<R>
            where F: FnOnce(&Self::V) -> R
        {
            Some(f(&self.$v))
        }

        fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
            where F: FnOnce(&mut Self::V) -> R
        {
            Some(f(&mut self.$v))
        }

        fn into_inner(self) -> Result<Self::V, Self> where Self::V: Sized {
            Ok(self.$v)
        }
    };
}

/// Convenient macro to implement the getters for inner [`View`] in [`ViewWrapper`].
///
/// It defines the `get_inner` and `get_inner_mut` implementations.
///
/// [`ViewWrapper`]: view/trait.ViewWrapper.html
/// [`View`]: view/trait.View.html
///
/// # Examples
///
/// ```no_run
/// # #[macro_use] extern crate cursive;
/// # use cursive::view::{View,ViewWrapper};
/// struct FooView<T: View> {
///     view: T,
/// }
///
/// impl<T: View> FooView<T> {
///     inner_getters!(self.view: T);
/// }
///
/// impl <T: View> ViewWrapper for FooView<T> {
///     wrap_impl!(self.view: T);
/// }
/// # fn main() { }
/// ```
#[macro_export]
macro_rules! inner_getters {
    (self.$v:ident: $t:ty) => {
        /// Gets access to the inner view.
        pub fn get_inner(&self) -> &$t {
            &self.$v
        }
        /// Gets mutable access to the inner view.
        pub fn get_inner_mut(&mut self) -> &mut $t {
            &mut self.$v
        }
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;

use env::Env;
use library::*;
use super::type_kind::TypeKind;

pub type Info = Vec<Parameter>;

pub fn analyze(env: &Env, type_: &Function) -> (Info, bool) {
    let mut outs = Info::new();
    let mut unsupported_outs = false;
    //Only process out parameters if function returns None
    if type_.ret.typ != Default::default() { return (outs, false); }

    for par in &type_.parameters {
        if par.direction != ParameterDirection::Out { continue; }
        if can_as_return(env, par) {
            outs.push(par.clone());
        } else {
            unsupported_outs = true;
        }
    }

    (outs, unsupported_outs)
}

fn can_as_return(env: &Env, par: &Parameter) -> bool {
    use super::type_kind::TypeKind::*;
    match TypeKind::of(&env.library, par.typ) {
        Enumeration |
            Converted |
            Direct => true,
        _ => false
    }
}
<commit_msg>Changed analysis::out_parameters::Info into struct<commit_after>use std::slice::Iter;
use std::vec::Vec;

use env::Env;
use library::*;
use super::type_kind::TypeKind;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Mode {
    None,
    Normal,
}

pub struct Info {
    pub mode: Mode,
    pub params: Vec<Parameter>,
}

impl Info {
    pub fn is_empty(&self) -> bool {
        self.mode == Mode::None
    }

    pub fn iter(&self) -> Iter<Parameter> {
        self.params.iter()
    }

    pub fn len(&self) -> usize {
        self.params.len()
    }
}

pub fn analyze(env: &Env, type_: &Function) -> (Info, bool) {
    let mut info = Info { mode: Mode::None, params: Vec::new() };
    let mut unsupported_outs = false;

    //Only process out parameters if function returns None
    if type_.ret.typ == Default::default() {
        info.mode = Mode::Normal;
    } else {
        return (info, false);
    }

    for par in &type_.parameters {
        if par.direction != ParameterDirection::Out { continue; }
        if can_as_return(env, par) {
            info.params.push(par.clone());
        } else {
            unsupported_outs = true;
        }
    }

    if info.params.is_empty() { info.mode = Mode::None }

    (info, unsupported_outs)
}

fn can_as_return(env: &Env, par: &Parameter) -> bool {
    use super::type_kind::TypeKind::*;
    match TypeKind::of(&env.library, par.typ) {
        Enumeration |
            Converted |
            Direct => true,
        _ => false
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program 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
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate docopt;
#[macro_use]
extern crate log;
extern crate mimir;
extern crate mimirsbrunn;
extern crate rustc_serialize;

use mimir::rubber::Rubber;
use mimirsbrunn::osm_reader::admin::{administrative_regions, compute_admin_weight};
use mimirsbrunn::osm_reader::poi::{pois, compute_poi_weight, PoiConfig};
use mimirsbrunn::osm_reader::street::{streets, compute_street_weight};
use mimirsbrunn::osm_reader::parse_osm_pbf;
use mimirsbrunn::admin_geofinder::AdminGeoFinder;

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_level: Vec<u32>,
    flag_city_level: u32,
    flag_connection_string: String,
    flag_import_way: bool,
    flag_import_admin: bool,
    flag_import_poi: bool,
    flag_dataset: String,
    flag_poi_config: Option<String>,
}

static USAGE: &'static str = r#"Usage:
    osm2mimir --help
    osm2mimir [options] --input=<file> --level=<level> ...

Options:
    -h, --help                Show this message.
    -i, --input=<file>        OSM PBF file.
    -l, --level=<level>       Admin levels to keep.
    -C, --city-level=<level>  City level to  calculate weight, [default: 8]
    -w, --import-way          Import ways
    -a, --import-admin        Import admins
    -p, --import-poi          Import POIs
    -c, --connection-string=<connection-string>
                              Elasticsearch parameters, [default: http://localhost:9200/munin]
    -d, --dataset=<dataset>   Name of the dataset, [default: fr]
    -j, --poi-config=<json>   POI configuration
"#;

fn main() {
    mimir::logger_init().unwrap();
    let args: Args =
        docopt::Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());

    let levels = args.flag_level
        .iter()
        .cloned()
        .collect();
    let city_level = args.flag_city_level;
    let mut parsed_pbf = parse_osm_pbf(&args.flag_input);
    debug!("creation of indexes");
    let mut rubber = Rubber::new(&args.flag_connection_string);

    info!("creating adminstrative regions");
    let admins_geofinder =
        administrative_regions(&mut parsed_pbf, levels).iter().cloned().collect::<AdminGeoFinder>();
    {
        info!("Extracting streets from osm");
        let mut streets = streets(&mut parsed_pbf, &admins_geofinder, city_level);

        info!("computing city weight");
        compute_admin_weight(&mut streets, &admins_geofinder);

        info!("computing street weight");
        compute_street_weight(&mut streets, city_level);

        if args.flag_import_way {
            info!("importing streets into Mimir");
            let nb_streets = rubber.index(&args.flag_dataset, streets.into_iter()).unwrap();
            info!("Nb of indexed street: {}", nb_streets);
        }
    }
    let nb_admins = rubber.index(&args.flag_dataset, admins_geofinder.admins()).unwrap();
    info!("Nb of indexed admin: {}", nb_admins);

    if args.flag_import_poi {
        let matcher = match args.flag_poi_config {
            None => PoiConfig::default(),
            Some(filename) => {
                let path = std::path::Path::new(&filename);
                let r = std::fs::File::open(&path).unwrap();
                PoiConfig::from_reader(r).unwrap()
            }
        };
        info!("Extracting pois from osm");
        let mut pois = pois(&mut parsed_pbf, &matcher, &admins_geofinder, city_level);

        info!("computing poi weight");
        compute_poi_weight(&mut pois, city_level);

        info!("Importing pois into Mimir");
        let nb_pois = rubber.index(&args.flag_dataset, pois.iter()).unwrap();

        info!("Nb of indexed pois: {}", nb_pois);
    }
}
<commit_msg>cosmetic change<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program 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
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate docopt;
#[macro_use]
extern crate log;
extern crate mimir;
extern crate mimirsbrunn;
extern crate rustc_serialize;

use mimir::rubber::Rubber;
use mimirsbrunn::osm_reader::admin::{administrative_regions, compute_admin_weight};
use mimirsbrunn::osm_reader::poi::{pois, compute_poi_weight, PoiConfig};
use mimirsbrunn::osm_reader::street::{streets, compute_street_weight};
use mimirsbrunn::osm_reader::parse_osm_pbf;
use mimirsbrunn::admin_geofinder::AdminGeoFinder;

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_level: Vec<u32>,
    flag_city_level: u32,
    flag_connection_string: String,
    flag_import_way: bool,
    flag_import_admin: bool,
    flag_import_poi: bool,
    flag_dataset: String,
    flag_poi_config: Option<String>,
}

static USAGE: &'static str = r#"Usage:
    osm2mimir --help
    osm2mimir [options] --input=<file> --level=<level> ...

Options:
    -h, --help                Show this message.
    -i, --input=<file>        OSM PBF file.
    -l, --level=<level>       Admin levels to keep.
    -C, --city-level=<level>  City level to  calculate weight, [default: 8]
    -w, --import-way          Import ways
    -a, --import-admin        Import admins
    -p, --import-poi          Import POIs
    -c, --connection-string=<connection-string>
                              Elasticsearch parameters, [default: http://localhost:9200/munin]
    -d, --dataset=<dataset>   Name of the dataset, [default: fr]
    -j, --poi-config=<json>   POI configuration
"#;

fn main() {
    mimir::logger_init().unwrap();
    let args: Args =
        docopt::Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());

    let levels = args.flag_level
        .iter()
        .cloned()
        .collect();
    let city_level = args.flag_city_level;
    let mut parsed_pbf = parse_osm_pbf(&args.flag_input);
    debug!("creation of indexes");
    let mut rubber = Rubber::new(&args.flag_connection_string);

    info!("creating adminstrative regions");
    let admins_geofinder =
        administrative_regions(&mut parsed_pbf, levels).into_iter().collect::<AdminGeoFinder>();
    {
        info!("Extracting streets from osm");
        let mut streets = streets(&mut parsed_pbf, &admins_geofinder, city_level);

        info!("computing city weight");
        compute_admin_weight(&mut streets, &admins_geofinder);

        info!("computing street weight");
        compute_street_weight(&mut streets, city_level);

        if args.flag_import_way {
            info!("importing streets into Mimir");
            let nb_streets = rubber.index(&args.flag_dataset, streets.into_iter()).unwrap();
            info!("Nb of indexed street: {}", nb_streets);
        }
    }
    let nb_admins = rubber.index(&args.flag_dataset, admins_geofinder.admins()).unwrap();
    info!("Nb of indexed admin: {}", nb_admins);

    if args.flag_import_poi {
        let matcher = match args.flag_poi_config {
            None => PoiConfig::default(),
            Some(filename) => {
                let path = std::path::Path::new(&filename);
                let r = std::fs::File::open(&path).unwrap();
                PoiConfig::from_reader(r).unwrap()
            }
        };
        info!("Extracting pois from osm");
        let mut pois = pois(&mut parsed_pbf, &matcher, &admins_geofinder, city_level);

        info!("computing poi weight");
        compute_poi_weight(&mut pois, city_level);

        info!("Importing pois into Mimir");
        let nb_pois = rubber.index(&args.flag_dataset, pois.iter()).unwrap();

        info!("Nb of indexed pois: {}", nb_pois);
    }
}
<|endoftext|>


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


<commit_before>use std::ops::Deref;
use std::mem;

/*
* storing in & out edges seperately should cut down on the number of "things" i have to traverse
* if a vertex has 10k edges (5k in and out 5k out) then doing something like*   g(v).outV()
* should be ok
*/
#[derive(Debug)]
pub struct Vertex {
    pub id: i64,
    // pointers on both sides, yay
    pub out_edges: Vec<*mut Edge>,
    pub in_edges:  Vec<*mut Edge>,
}

impl Vertex {
    pub fn new(id: i64) -> Box<Vertex> {
        Box::new(Vertex{id:id,
                        out_edges: Vec::new(),
                        in_edges: Vec::new()})
    }
}

pub struct VertexProxy {
    pub id: i64,
    pub v: *mut Vertex,
}

impl VertexProxy {
    pub fn add_edge(&mut self, to_vertex: &mut VertexProxy) -> EdgeProxy {
        let in_vertex: &mut Vertex;
        let out_vertex: &mut Vertex;

        unsafe {
            in_vertex =  &mut *(self.v);
            out_vertex = &mut *(to_vertex.v);
        }

        // create the edge
        let e = Box::new(Edge{from_vertex: self.v, to_vertex: to_vertex.v});

        let edge: *mut Edge = unsafe { mem::transmute(e) };

        in_vertex.out_edges.push(edge);
        out_vertex.in_edges.push(edge);
        EdgeProxy{edge:edge}
    }

    pub fn query(self) {
        unimplemented!()
    }

}

impl Deref for VertexProxy {
    type Target = Vertex;

    fn deref<'a>(&'a self) -> &'a Vertex {
        unsafe {
            &*(self.v)
        }
    }
}

#[derive(Debug)]
pub struct Edge {
    pub from_vertex: *mut Vertex,
    pub to_vertex: *mut Vertex
}

pub struct EdgeProxy {
    edge: *mut Edge
}

impl Deref for EdgeProxy {
    type Target = Edge;
    fn deref<'a>(&'a self) -> &'a Edge {
        unsafe { &*(self.edge) }
    }
}
<commit_msg>converted EdgeProxy to be a tuple struct<commit_after>use std::ops::Deref;
use std::mem;

/*
* storing in & out edges seperately should cut down on the number of "things" i have to traverse
* if a vertex has 10k edges (5k in and out 5k out) then doing something like*   g(v).outV()
* should be ok
*/
#[derive(Debug)]
pub struct Vertex {
    pub id: i64,
    // pointers on both sides, yay
    pub out_edges: Vec<*mut Edge>,
    pub in_edges:  Vec<*mut Edge>,
}

impl Vertex {
    pub fn new(id: i64) -> Box<Vertex> {
        Box::new(Vertex{id:id,
                        out_edges: Vec::new(),
                        in_edges: Vec::new()})
    }
}

pub struct VertexProxy {
    pub id: i64,
    pub v: *mut Vertex,
}

impl VertexProxy {
    pub fn add_edge(&mut self, to_vertex: &mut VertexProxy) -> EdgeProxy {
        let in_vertex: &mut Vertex;
        let out_vertex: &mut Vertex;

        unsafe {
            in_vertex =  &mut *(self.v);
            out_vertex = &mut *(to_vertex.v);
        }

        // create the edge
        let e = Box::new(Edge{from_vertex: self.v, to_vertex: to_vertex.v});

        let edge: *mut Edge = unsafe { mem::transmute(e) };

        in_vertex.out_edges.push(edge);
        out_vertex.in_edges.push(edge);
        EdgeProxy(edge)
    }

    pub fn query(self) {
        unimplemented!()
    }
}

impl Deref for VertexProxy {
    type Target = Vertex;

    fn deref<'a>(&'a self) -> &'a Vertex {
        unsafe {
            &*(self.v)
        }
    }
}

#[derive(Debug)]
pub struct Edge {
    pub from_vertex: *mut Vertex,
    pub to_vertex: *mut Vertex
}

pub struct EdgeProxy(*mut Edge);
<|endoftext|>