<commit_before>use libc;
use uuid::Uuid;
use std::cmp::PartialEq;
use std::string::String;
use std::any::Any;

macro_rules! gen_primitive_types_io {
    (
        $($t:ty: $tmod:ident);*
    ) => (
            $(
                pub mod $tmod {
                    use std::ptr;
                    use std::mem;
                    pub fn read(mem_ptr: usize) -> $t {
                         unsafe {
                            ptr::read(mem_ptr as *mut $t)
                        }
                    }
                    pub fn write(val: $t, mem_ptr: usize) {
                        unsafe {
                            ptr::write(mem_ptr as *mut $t, val)
                        }
                    }
                    pub fn size(mem_ptr: usize) -> usize {
                        mem::size_of::<$t>()
                    }
                }
            )*
    );
}

macro_rules! gen_compound_types_io {
    (
        $($t:ident, $tmod:ident, $reader:expr, $writer: expr, $size:expr);*
    ) => (
            $(
                pub mod $tmod {
                    use ram::types::*;
                    pub fn read(mem_ptr: usize) -> $t {
                        let read = $reader;
                        read(mem_ptr)
                    }
                    pub fn write(val: &$t, mem_ptr: usize) {
                        let write = $writer;
                        write(val, mem_ptr)
                    }
                    pub fn size(mem_ptr: usize) -> usize {
                        $size
                    }
                }
            )*
    );
}

macro_rules! gen_variable_types_io {
    (
        $($t:ident, $tmod:ident, $reader:expr, $writer: expr, $size:expr);*
    ) => (
            $(
                pub mod $tmod {
                    use ram::types::*;
                    pub fn read(mem_ptr: usize) -> $t {
                        let read = $reader;
                        read(mem_ptr)
                    }
                    pub fn write(val: &$t, mem_ptr: usize) {
                        let write = $writer;
                        write(val, mem_ptr)
                    }
                    pub fn size(mem_ptr: usize) -> usize {
                        let size = $size;
                        size(mem_ptr)
                    }
                }
            )*
    );
}

macro_rules! gen_write_extractor {
    (true, $e:ident, $d:ident) => (
        match $d {
            &Data::$e(ref v) => Some(v),
            _ => None
        }
    );
    (false, $e:ident, $d:ident) => (
        match $d {
            &Data::$e(v) => Some(v),
            _ => None
        }
    )
}

macro_rules! define_types {
    (
        $(
            [ $( $name:expr ),* ], $id:expr, $t:ty, $e:ident, $r:ident, $io:ident
         );*
    ) => (
        pub enum Data {
            $(
                $e($t),
            )*
            NA
        }
        fn get_type_id (name: String) -> i32 {
           match name.as_ref() {
                $(
                    $($name => $id,)*
                )*
                _ => -1,
           }
        }
        fn get_id_type (id: i32) -> &'static str {
           match id {
                $(
                    $id => [$($name),*][0],
                )*
                _ => "N/A",
           }
        }
        fn get_size (id: i32, mem_ptr: usize) -> usize {
           match id {
                $(
                    $id => $io::size(mem_ptr),
                )*
                _ => 0,
           }
        }
        fn get_val (id:i32, mem_ptr: usize) -> Data {
             match id {
                 $(
                     $id => Data::$e($io::read(mem_ptr)),
                 )*
                 _ => Data::NA,
             }
        }
        fn set_val (data: &Data, id:i32, mem_ptr: usize) {
             match id {
                 $(
                     $id => $io::write(gen_write_extractor!($r, $e, data).unwrap() , mem_ptr),
                 )*
                 _ => (),
             }
        }
    );
}

macro_rules! rc {
    (
        $read:ident
    ) => (
        $read
    );
}

macro_rules! wc {
    (
        $rwrite:ident
    ) => (
        $rwrite
    );
}

gen_primitive_types_io!(
    bool:   bool_io       ;
    char:   char_io       ;
    i8:     i8_io         ;
    i16:    i16_io        ;
    i32:    i32_io        ;
    i64:    i64_io        ;
    u8:     u8_io         ;
    u16:    u16_io        ;
    u32:    u32_io        ;
    u64:    u64_io        ;
    isize:  isize_io      ;
    usize:  usize_io      ;
    f32:    f32_io        ;
    f64:    f64_io
);

pub struct pos2d32 {
    pub x: f32,
    pub y: f32,
}

pub struct pos2d64 {
    pub x: f64,
    pub y: f64,
}

pub struct pos3d32 {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

pub struct pos3d64 {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

impl PartialEq for pos2d32 {
    fn eq(&self, other: &pos2d32) -> bool {
        self.x == other.x && self.y == other.y
    }
    fn ne(&self, other: &pos2d32) -> bool {
        self.x != other.x || self.y != other.y
    }
}

impl PartialEq for pos2d64 {
    fn eq(&self, other: &pos2d64) -> bool {
        self.x == other.x && self.y == other.y
    }
    fn ne(&self, other: &pos2d64) -> bool {
        self.x != other.x || self.y != other.y
    }
}

impl PartialEq for pos3d32 {
    fn eq(&self, other: &pos3d32) -> bool {
        self.x == other.x && self.y == other.y && self.z == other.z
    }
    fn ne(&self, other: &pos3d32) -> bool {
        self.x != other.x || self.y != other.y || self.z != other.z
    }
}

impl PartialEq for pos3d64 {
    fn eq(&self, other: &pos3d64) -> bool {
        self.x == other.x && self.y == other.y && self.z == other.z
    }
    fn ne(&self, other: &pos3d64) -> bool {
        self.x != other.x || self.y != other.y || self.z != other.z
    }
}

pub type uuid_ = Uuid;

gen_compound_types_io! (
    pos2d32, pos2d32_io, {
        |mem_ptr| {
            let x = f32_io::read(mem_ptr);
            let y = f32_io::read(mem_ptr + f32_io::size(0));
            pos2d32 {x: x, y: y}
        }
    }, {
        |val: &pos2d32, mem_ptr| {
            f32_io::write(val.x, mem_ptr);
            f32_io::write(val.y, mem_ptr + f32_io::size(0));
        }
    }, {
        f32_io::size(0) * 2
    };

    pos2d64, pos2d64_io, {
        |mem_ptr| {
            let x = f64_io::read(mem_ptr);
            let y = f64_io::read(mem_ptr + f64_io::size(0));
            pos2d64 {x: x, y: y}
        }
    }, {
        |val: &pos2d64, mem_ptr| {
            f64_io::write(val.x, mem_ptr);
            f64_io::write(val.y, mem_ptr + f64_io::size(0));
        }
    }, {
        f64_io::size(0) * 2
    };

    //////////////////////////////////////////////////////////////

    pos3d32, pos3d32_io, {
        |mem_ptr| {
            let x = f32_io::read(mem_ptr);
            let y = f32_io::read(mem_ptr + f32_io::size(0));
            let z = f32_io::read(mem_ptr + f32_io::size(0) * 2);
            pos3d32 {x: x, y: y, z: z}
        }
    }, {
        |val: &pos3d32, mem_ptr| {
            f32_io::write(val.x, mem_ptr);
            f32_io::write(val.y, mem_ptr + f32_io::size(0));
            f32_io::write(val.z, mem_ptr + f32_io::size(0) * 2);
        }
    }, {
        f32_io::size(0) * 3
    };

    pos3d64, pos3d64_io, {
        |mem_ptr| {
            let x = f64_io::read(mem_ptr);
            let y = f64_io::read(mem_ptr + f64_io::size(0));
            let z = f64_io::read(mem_ptr + f64_io::size(0) * 2);
            pos3d64 {x: x, y: y, z: z}
        }
    }, {
        |val: &pos3d64, mem_ptr| {
            f64_io::write(val.x, mem_ptr);
            f64_io::write(val.y, mem_ptr + f64_io::size(0));
            f64_io::write(val.z, mem_ptr + f64_io::size(0) * 2);
        }
    }, {
        f64_io::size(0) * 3
    };

    //////////////////////////////////////////////////////////

    uuid_, uuid_io, {
        |mem_ptr| {
            use uuid::{UuidBytes, Uuid};
            use std::ptr;
            unsafe {
                Uuid::from_bytes(
                    ptr::read(mem_ptr as *mut &UuidBytes) as &[u8]
                ).unwrap()
            }
        }
    }, {
        use uuid::{UuidBytes, Uuid};
        use std::ptr;
        |val: &uuid_, mem_ptr| {
            unsafe {
                ptr::write(mem_ptr as *mut &UuidBytes, val.as_bytes());
            }
        }
    }, {
        16
    }
);

gen_variable_types_io! (
    String, string_io, {
        use std::ptr;
        |mem_ptr| {
            let len = u32_io::read(mem_ptr) as usize;
            let smem_ptr = mem_ptr + u32_io::size(0);
            let mut bytes = Vec::with_capacity(len);
            for i in 0..len {
                let ptr = smem_ptr + i;
                let b = unsafe {ptr::read(ptr as *mut u8)};
                bytes.push(b);
            }
            String::from_utf8(bytes).unwrap()
        }
    }, {
        use std::ptr;
        |val: &String, mem_ptr| {
            let bytes = val.as_bytes();
            let len = bytes.len();
            u32_io::write(len as u32, mem_ptr);
            let mut smem_ptr = mem_ptr + u32_io::size(0);
            unsafe {
                for b in bytes {
                    ptr::write(smem_ptr as *mut u8, *b);
                    smem_ptr += 1;
                }
            }
        }
    }, {
        |mem_ptr| {
            let str_len = u32_io::read(mem_ptr) as usize;
            str_len + u32_io::size(0)

        }
    }
);

define_types!(
    ["bool", "bit"], 0, bool                           ,bool     ,false ,  bool_io       ;
    ["char"], 1, char                                  ,char     ,false ,  char_io       ;
    ["i8"], 2, i8                                      ,i8       ,false ,  i8_io         ;
    ["i16", "int"], 3, i16                             ,i16      ,false ,  i16_io        ;
    ["i32", "long"], 4, i32                            ,i32      ,false ,  i32_io        ;
    ["i64", "longlong"], 5, i64                        ,i64      ,false ,  i64_io        ;
    ["u8", "byte"], 6, u8                              ,u8       ,false ,  u8_io         ;
    ["u16"], 7, u16                                    ,u16      ,false ,  u16_io        ;
    ["u32"], 8, u32                                    ,u32      ,false ,  u32_io        ;
    ["u64"], 9, u64                                    ,u64      ,false ,  u64_io        ;
    ["isize"], 10, isize                               ,isize    ,false ,  isize_io      ;
    ["usize"], 11, usize                               ,usize    ,false ,  usize_io      ;
    ["f32", "float"], 12, f32                          ,f32      ,false ,  f32_io        ;
    ["f64", "double"], 13, f64                         ,f64      ,false ,  f64_io        ;
    ["pos2d32", "pos2d", "pos", "pos32"], 14, pos2d32  ,pos2d32  ,true  ,  pos2d32_io    ;
    ["pos2d64", "pos64"], 15, pos2d64                  ,pos2d64  ,true  ,  pos2d64_io    ;
    ["pos3d32", "pos3d"], 16, pos3d32                  ,pos3d32  ,true  ,  pos3d32_io    ;
    ["pos3d64"], 17, pos3d64                           ,pos3d64  ,true  ,  pos3d64_io    ;
    ["uuid"], 18, uuid_                                ,uuid     ,true  ,  uuid_io       ;
    ["string", "str"], 19, String                      ,string   ,true  ,  string_io
);<commit_msg>kill warning for primitive type size function<commit_after>use libc;
use uuid::Uuid;
use std::cmp::PartialEq;
use std::string::String;
use std::any::Any;

macro_rules! gen_primitive_types_io {
    (
        $($t:ty: $tmod:ident);*
    ) => (
            $(
                pub mod $tmod {
                    use std::ptr;
                    use std::mem;
                    pub fn read(mem_ptr: usize) -> $t {
                         unsafe {
                            ptr::read(mem_ptr as *mut $t)
                        }
                    }
                    pub fn write(val: $t, mem_ptr: usize) {
                        unsafe {
                            ptr::write(mem_ptr as *mut $t, val)
                        }
                    }
                    pub fn size(_: usize) -> usize {
                        mem::size_of::<$t>()
                    }
                }
            )*
    );
}

macro_rules! gen_compound_types_io {
    (
        $($t:ident, $tmod:ident, $reader:expr, $writer: expr, $size:expr);*
    ) => (
            $(
                pub mod $tmod {
                    use ram::types::*;
                    pub fn read(mem_ptr: usize) -> $t {
                        let read = $reader;
                        read(mem_ptr)
                    }
                    pub fn write(val: &$t, mem_ptr: usize) {
                        let write = $writer;
                        write(val, mem_ptr)
                    }
                    pub fn size(mem_ptr: usize) -> usize {
                        $size
                    }
                }
            )*
    );
}

macro_rules! gen_variable_types_io {
    (
        $($t:ident, $tmod:ident, $reader:expr, $writer: expr, $size:expr);*
    ) => (
            $(
                pub mod $tmod {
                    use ram::types::*;
                    pub fn read(mem_ptr: usize) -> $t {
                        let read = $reader;
                        read(mem_ptr)
                    }
                    pub fn write(val: &$t, mem_ptr: usize) {
                        let write = $writer;
                        write(val, mem_ptr)
                    }
                    pub fn size(mem_ptr: usize) -> usize {
                        let size = $size;
                        size(mem_ptr)
                    }
                }
            )*
    );
}

macro_rules! gen_write_extractor {
    (true, $e:ident, $d:ident) => (
        match $d {
            &Data::$e(ref v) => Some(v),
            _ => None
        }
    );
    (false, $e:ident, $d:ident) => (
        match $d {
            &Data::$e(v) => Some(v),
            _ => None
        }
    )
}

macro_rules! define_types {
    (
        $(
            [ $( $name:expr ),* ], $id:expr, $t:ty, $e:ident, $r:ident, $io:ident
         );*
    ) => (
        pub enum Data {
            $(
                $e($t),
            )*
            NA
        }
        fn get_type_id (name: String) -> i32 {
           match name.as_ref() {
                $(
                    $($name => $id,)*
                )*
                _ => -1,
           }
        }
        fn get_id_type (id: i32) -> &'static str {
           match id {
                $(
                    $id => [$($name),*][0],
                )*
                _ => "N/A",
           }
        }
        fn get_size (id: i32, mem_ptr: usize) -> usize {
           match id {
                $(
                    $id => $io::size(mem_ptr),
                )*
                _ => 0,
           }
        }
        fn get_val (id:i32, mem_ptr: usize) -> Data {
             match id {
                 $(
                     $id => Data::$e($io::read(mem_ptr)),
                 )*
                 _ => Data::NA,
             }
        }
        fn set_val (data: &Data, id:i32, mem_ptr: usize) {
             match id {
                 $(
                     $id => $io::write(gen_write_extractor!($r, $e, data).unwrap() , mem_ptr),
                 )*
                 _ => (),
             }
        }
    );
}

macro_rules! rc {
    (
        $read:ident
    ) => (
        $read
    );
}

macro_rules! wc {
    (
        $rwrite:ident
    ) => (
        $rwrite
    );
}

gen_primitive_types_io!(
    bool:   bool_io       ;
    char:   char_io       ;
    i8:     i8_io         ;
    i16:    i16_io        ;
    i32:    i32_io        ;
    i64:    i64_io        ;
    u8:     u8_io         ;
    u16:    u16_io        ;
    u32:    u32_io        ;
    u64:    u64_io        ;
    isize:  isize_io      ;
    usize:  usize_io      ;
    f32:    f32_io        ;
    f64:    f64_io
);

pub struct pos2d32 {
    pub x: f32,
    pub y: f32,
}

pub struct pos2d64 {
    pub x: f64,
    pub y: f64,
}

pub struct pos3d32 {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

pub struct pos3d64 {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

impl PartialEq for pos2d32 {
    fn eq(&self, other: &pos2d32) -> bool {
        self.x == other.x && self.y == other.y
    }
    fn ne(&self, other: &pos2d32) -> bool {
        self.x != other.x || self.y != other.y
    }
}

impl PartialEq for pos2d64 {
    fn eq(&self, other: &pos2d64) -> bool {
        self.x == other.x && self.y == other.y
    }
    fn ne(&self, other: &pos2d64) -> bool {
        self.x != other.x || self.y != other.y
    }
}

impl PartialEq for pos3d32 {
    fn eq(&self, other: &pos3d32) -> bool {
        self.x == other.x && self.y == other.y && self.z == other.z
    }
    fn ne(&self, other: &pos3d32) -> bool {
        self.x != other.x || self.y != other.y || self.z != other.z
    }
}

impl PartialEq for pos3d64 {
    fn eq(&self, other: &pos3d64) -> bool {
        self.x == other.x && self.y == other.y && self.z == other.z
    }
    fn ne(&self, other: &pos3d64) -> bool {
        self.x != other.x || self.y != other.y || self.z != other.z
    }
}

pub type uuid_ = Uuid;

gen_compound_types_io! (
    pos2d32, pos2d32_io, {
        |mem_ptr| {
            let x = f32_io::read(mem_ptr);
            let y = f32_io::read(mem_ptr + f32_io::size(0));
            pos2d32 {x: x, y: y}
        }
    }, {
        |val: &pos2d32, mem_ptr| {
            f32_io::write(val.x, mem_ptr);
            f32_io::write(val.y, mem_ptr + f32_io::size(0));
        }
    }, {
        f32_io::size(0) * 2
    };

    pos2d64, pos2d64_io, {
        |mem_ptr| {
            let x = f64_io::read(mem_ptr);
            let y = f64_io::read(mem_ptr + f64_io::size(0));
            pos2d64 {x: x, y: y}
        }
    }, {
        |val: &pos2d64, mem_ptr| {
            f64_io::write(val.x, mem_ptr);
            f64_io::write(val.y, mem_ptr + f64_io::size(0));
        }
    }, {
        f64_io::size(0) * 2
    };

    //////////////////////////////////////////////////////////////

    pos3d32, pos3d32_io, {
        |mem_ptr| {
            let x = f32_io::read(mem_ptr);
            let y = f32_io::read(mem_ptr + f32_io::size(0));
            let z = f32_io::read(mem_ptr + f32_io::size(0) * 2);
            pos3d32 {x: x, y: y, z: z}
        }
    }, {
        |val: &pos3d32, mem_ptr| {
            f32_io::write(val.x, mem_ptr);
            f32_io::write(val.y, mem_ptr + f32_io::size(0));
            f32_io::write(val.z, mem_ptr + f32_io::size(0) * 2);
        }
    }, {
        f32_io::size(0) * 3
    };

    pos3d64, pos3d64_io, {
        |mem_ptr| {
            let x = f64_io::read(mem_ptr);
            let y = f64_io::read(mem_ptr + f64_io::size(0));
            let z = f64_io::read(mem_ptr + f64_io::size(0) * 2);
            pos3d64 {x: x, y: y, z: z}
        }
    }, {
        |val: &pos3d64, mem_ptr| {
            f64_io::write(val.x, mem_ptr);
            f64_io::write(val.y, mem_ptr + f64_io::size(0));
            f64_io::write(val.z, mem_ptr + f64_io::size(0) * 2);
        }
    }, {
        f64_io::size(0) * 3
    };

    //////////////////////////////////////////////////////////

    uuid_, uuid_io, {
        |mem_ptr| {
            use uuid::{UuidBytes, Uuid};
            use std::ptr;
            unsafe {
                Uuid::from_bytes(
                    ptr::read(mem_ptr as *mut &UuidBytes) as &[u8]
                ).unwrap()
            }
        }
    }, {
        use uuid::{UuidBytes, Uuid};
        use std::ptr;
        |val: &uuid_, mem_ptr| {
            unsafe {
                ptr::write(mem_ptr as *mut &UuidBytes, val.as_bytes());
            }
        }
    }, {
        16
    }
);

gen_variable_types_io! (
    String, string_io, {
        use std::ptr;
        |mem_ptr| {
            let len = u32_io::read(mem_ptr) as usize;
            let smem_ptr = mem_ptr + u32_io::size(0);
            let mut bytes = Vec::with_capacity(len);
            for i in 0..len {
                let ptr = smem_ptr + i;
                let b = unsafe {ptr::read(ptr as *mut u8)};
                bytes.push(b);
            }
            String::from_utf8(bytes).unwrap()
        }
    }, {
        use std::ptr;
        |val: &String, mem_ptr| {
            let bytes = val.as_bytes();
            let len = bytes.len();
            u32_io::write(len as u32, mem_ptr);
            let mut smem_ptr = mem_ptr + u32_io::size(0);
            unsafe {
                for b in bytes {
                    ptr::write(smem_ptr as *mut u8, *b);
                    smem_ptr += 1;
                }
            }
        }
    }, {
        |mem_ptr| {
            let str_len = u32_io::read(mem_ptr) as usize;
            str_len + u32_io::size(0)

        }
    }
);

define_types!(
    ["bool", "bit"], 0, bool                           ,bool     ,false ,  bool_io       ;
    ["char"], 1, char                                  ,char     ,false ,  char_io       ;
    ["i8"], 2, i8                                      ,i8       ,false ,  i8_io         ;
    ["i16", "int"], 3, i16                             ,i16      ,false ,  i16_io        ;
    ["i32", "long"], 4, i32                            ,i32      ,false ,  i32_io        ;
    ["i64", "longlong"], 5, i64                        ,i64      ,false ,  i64_io        ;
    ["u8", "byte"], 6, u8                              ,u8       ,false ,  u8_io         ;
    ["u16"], 7, u16                                    ,u16      ,false ,  u16_io        ;
    ["u32"], 8, u32                                    ,u32      ,false ,  u32_io        ;
    ["u64"], 9, u64                                    ,u64      ,false ,  u64_io        ;
    ["isize"], 10, isize                               ,isize    ,false ,  isize_io      ;
    ["usize"], 11, usize                               ,usize    ,false ,  usize_io      ;
    ["f32", "float"], 12, f32                          ,f32      ,false ,  f32_io        ;
    ["f64", "double"], 13, f64                         ,f64      ,false ,  f64_io        ;
    ["pos2d32", "pos2d", "pos", "pos32"], 14, pos2d32  ,pos2d32  ,true  ,  pos2d32_io    ;
    ["pos2d64", "pos64"], 15, pos2d64                  ,pos2d64  ,true  ,  pos2d64_io    ;
    ["pos3d32", "pos3d"], 16, pos3d32                  ,pos3d32  ,true  ,  pos3d32_io    ;
    ["pos3d64"], 17, pos3d64                           ,pos3d64  ,true  ,  pos3d64_io    ;
    ["uuid"], 18, uuid_                                ,uuid     ,true  ,  uuid_io       ;
    ["string", "str"], 19, String                      ,string   ,true  ,  string_io
);<|endoftext|>


<commit_before>use std::{
    fmt::{self, Display, Formatter},
    ops::Add,
};

use im::HashMap;
use itertools::Itertools;
use linked_hash_map::LinkedHashMap;

use crate::input::Input;

use super::ast_to_hir::AstToHir;

#[salsa::query_group(HirDbStorage)]
pub trait HirDb: AstToHir {
    fn find_expression(&self, input: Input, id: Id) -> Option<Expression>;
    fn all_hir_ids(&self, input: Input) -> Option<Vec<Id>>;
}

fn find_expression(db: &dyn HirDb, input: Input, id: Id) -> Option<Expression> {
    let (hir, _) = db.hir(input).unwrap();
    hir.find(&id).map(|it| it.to_owned())
}
fn all_hir_ids(db: &dyn HirDb, input: Input) -> Option<Vec<Id>> {
    let (hir, _) = db.hir(input)?;
    let mut ids = vec![];
    hir.collect_all_ids(&mut ids);
    log::info!("all HIR IDs: {:?}", ids);
    Some(ids)
}

impl Expression {
    fn collect_all_ids(&self, ids: &mut Vec<Id>) {
        match self {
            Expression::Int(_) => {}
            Expression::Text(_) => {}
            Expression::Reference(_) => {}
            Expression::Symbol(_) => {}
            Expression::Struct(entries) => {
                for (key_id, value_id) in entries.iter() {
                    ids.push(key_id.to_owned());
                    ids.push(value_id.to_owned());
                }
            }
            Expression::Lambda(Lambda { body, .. }) => {
                // TODO: list parameter IDs?
                // for (index, _) in parameters.iter().enumerate() {
                //     ids.push(first_id.to_owned() + index);
                // }
                body.collect_all_ids(ids);
            }
            Expression::Body(body) => body.collect_all_ids(ids),
            Expression::Call { arguments, .. } => {
                ids.extend(arguments.iter().cloned());
            }
            Expression::Error => {}
        }
    }
}
impl Body {
    fn collect_all_ids(&self, ids: &mut Vec<Id>) {
        ids.extend(self.expressions.keys().into_iter().cloned());
        for expression in self.expressions.values() {
            expression.collect_all_ids(ids);
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)]
pub struct Id(pub Vec<usize>);
impl Id {
    pub fn parent(&self) -> Option<Id> {
        match self.0.len() {
            0 => panic!("HIR ID is empty."),
            1 => None,
            _ => Some(Id(self.0[..self.0.len() - 1].to_vec())),
        }
    }
}
impl Add<usize> for Id {
    type Output = Self;

    fn add(self, rhs: usize) -> Self::Output {
        assert!(!self.0.is_empty());
        let mut vec = self.0[..self.0.len() - 1].to_vec();
        vec.push(self.0.last().unwrap() + rhs);
        Id(vec)
    }
}
impl Display for Id {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "HirId({:?})", self.0)
    }
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Expression {
    Int(u64),
    Text(String),
    Reference(Id),
    Symbol(String),
    Struct(HashMap<Id, Id>),
    Lambda(Lambda),
    Body(Body),
    Call { function: Id, arguments: Vec<Id> },
    Error,
}
impl Expression {
    pub fn nothing() -> Self {
        Expression::Symbol("Nothing".to_owned())
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Lambda {
    pub first_id: Id,
    pub parameters: Vec<String>,
    pub body: Body,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Body {
    pub expressions: LinkedHashMap<Id, Expression>,
    pub identifiers: HashMap<Id, String>,
}

impl Body {
    pub fn new() -> Self {
        Self {
            expressions: LinkedHashMap::new(),
            identifiers: HashMap::new(),
        }
    }
    pub fn push(&mut self, id: Id, expression: Expression, identifier: Option<String>) {
        self.expressions.insert(id.to_owned(), expression);
        if let Some(identifier) = identifier {
            self.identifiers.insert(id, identifier);
        }
    }
    pub fn out_id(&self) -> &Id {
        self.expressions.keys().last().unwrap()
    }
}

impl fmt::Display for Expression {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Expression::Int(int) => write!(f, "int {}", int),
            Expression::Text(text) => write!(f, "text {:?}", text),
            Expression::Reference(reference) => write!(f, "reference {}", reference),
            Expression::Symbol(symbol) => write!(f, "symbol {}", symbol),
            Expression::Struct(entries) => {
                write!(
                    f,
                    "struct [\n{}\n]",
                    entries
                        .iter()
                        .map(|(id, value)| format!("  {}: {}", id, value))
                        .join(",\n"),
                )
            }
            Expression::Lambda(lambda) => {
                write!(
                    f,
                    "lambda [\n{}\n]",
                    lambda
                        .to_string()
                        .lines()
                        .map(|line| format!("  {}", line))
                        .join("\n"),
                )
            }
            Expression::Body(body) => {
                write!(
                    f,
                    "body [\n{}\n]",
                    body.to_string()
                        .lines()
                        .map(|line| format!("  {}", line))
                        .join("\n"),
                )
            }
            Expression::Call {
                function,
                arguments,
            } => {
                assert!(arguments.len() > 0, "A call needs to have arguments.");
                write!(f, "call {} with {}", function, arguments.iter().join(" "))
            }
            Expression::Error => write!(f, "<error>"),
        }
    }
}
impl fmt::Display for Lambda {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} parameters\n", self.parameters.len())?;
        write!(f, "{}", self.body)?;
        Ok(())
    }
}
impl fmt::Display for Body {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for (id, expression) in self.expressions.iter() {
            write!(f, "{} = {}\n", id, expression)?;
        }
        Ok(())
    }
}

impl Expression {
    fn find(&self, id: &Id) -> Option<&Self> {
        match self {
            Expression::Int { .. } => None,
            Expression::Text { .. } => None,
            Expression::Reference { .. } => None,
            Expression::Symbol { .. } => None,
            Expression::Struct(_) => None,
            Expression::Lambda(Lambda { body, .. }) => body.find(id),
            Expression::Body(body) => body.find(id),
            Expression::Call { .. } => None,
            Expression::Error { .. } => None,
        }
    }
}
impl Body {
    fn find(&self, id: &Id) -> Option<&Expression> {
        if let Some(expression) = self.expressions.get(id) {
            Some(expression)
        } else {
            self.expressions
                .iter()
                .filter(|(key, _)| key <= &id)
                .max_by_key(|(key, _)| key.0.to_owned())?
                .1
                .find(id)
        }
    }
}
<commit_msg>feat(compiler): add hir::Id::root()<commit_after>use std::{
    fmt::{self, Display, Formatter},
    ops::Add,
};

use im::HashMap;
use itertools::Itertools;
use linked_hash_map::LinkedHashMap;

use crate::input::Input;

use super::ast_to_hir::AstToHir;

#[salsa::query_group(HirDbStorage)]
pub trait HirDb: AstToHir {
    fn find_expression(&self, input: Input, id: Id) -> Option<Expression>;
    fn all_hir_ids(&self, input: Input) -> Option<Vec<Id>>;
}
fn find_expression(db: &dyn HirDb, input: Input, id: Id) -> Option<Expression> {
    let (hir, _) = db.hir(input).unwrap();
    if id == Id::root() {
        return Some(Expression::Body(hir.as_ref().to_owned()));
    }

    hir.find(&id).map(|it| it.to_owned())
}
fn all_hir_ids(db: &dyn HirDb, input: Input) -> Option<Vec<Id>> {
    let (hir, _) = db.hir(input)?;
    let mut ids = vec![];
    hir.collect_all_ids(&mut ids);
    log::info!("all HIR IDs: {:?}", ids);
    Some(ids)
}

impl Expression {
    fn collect_all_ids(&self, ids: &mut Vec<Id>) {
        match self {
            Expression::Int(_) => {}
            Expression::Text(_) => {}
            Expression::Reference(_) => {}
            Expression::Symbol(_) => {}
            Expression::Struct(entries) => {
                for (key_id, value_id) in entries.iter() {
                    ids.push(key_id.to_owned());
                    ids.push(value_id.to_owned());
                }
            }
            Expression::Lambda(Lambda { body, .. }) => {
                // TODO: list parameter IDs?
                // for (index, _) in parameters.iter().enumerate() {
                //     ids.push(first_id.to_owned() + index);
                // }
                body.collect_all_ids(ids);
            }
            Expression::Body(body) => body.collect_all_ids(ids),
            Expression::Call { arguments, .. } => {
                ids.extend(arguments.iter().cloned());
            }
            Expression::Error => {}
        }
    }
}
impl Body {
    fn collect_all_ids(&self, ids: &mut Vec<Id>) {
        ids.extend(self.expressions.keys().into_iter().cloned());
        for expression in self.expressions.values() {
            expression.collect_all_ids(ids);
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)]
pub struct Id(pub Vec<usize>);
impl Id {
    pub fn root() -> Self {
        Id(vec![])
    }
    pub fn parent(&self) -> Option<Id> {
        match self.0.len() {
            0 => None,
            _ => Some(Id(self.0[..self.0.len() - 1].to_vec())),
        }
    }
}
impl Add<usize> for Id {
    type Output = Self;

    fn add(self, rhs: usize) -> Self::Output {
        let mut vec = self.0[..self.0.len() - 1].to_vec();
        vec.push(self.0.last().unwrap() + rhs);
        Id(vec)
    }
}
impl Display for Id {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "HirId({:?})", self.0)
    }
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Expression {
    Int(u64),
    Text(String),
    Reference(Id),
    Symbol(String),
    Struct(HashMap<Id, Id>),
    Lambda(Lambda),
    Body(Body),
    Call { function: Id, arguments: Vec<Id> },
    Error,
}
impl Expression {
    pub fn nothing() -> Self {
        Expression::Symbol("Nothing".to_owned())
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Lambda {
    pub first_id: Id,
    pub parameters: Vec<String>,
    pub body: Body,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Body {
    pub expressions: LinkedHashMap<Id, Expression>,
    pub identifiers: HashMap<Id, String>,
}

impl Body {
    pub fn new() -> Self {
        Self {
            expressions: LinkedHashMap::new(),
            identifiers: HashMap::new(),
        }
    }
    pub fn push(&mut self, id: Id, expression: Expression, identifier: Option<String>) {
        self.expressions.insert(id.to_owned(), expression);
        if let Some(identifier) = identifier {
            self.identifiers.insert(id, identifier);
        }
    }
    pub fn out_id(&self) -> &Id {
        self.expressions.keys().last().unwrap()
    }
}

impl fmt::Display for Expression {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Expression::Int(int) => write!(f, "int {}", int),
            Expression::Text(text) => write!(f, "text {:?}", text),
            Expression::Reference(reference) => write!(f, "reference {}", reference),
            Expression::Symbol(symbol) => write!(f, "symbol {}", symbol),
            Expression::Struct(entries) => {
                write!(
                    f,
                    "struct [\n{}\n]",
                    entries
                        .iter()
                        .map(|(id, value)| format!("  {}: {}", id, value))
                        .join(",\n"),
                )
            }
            Expression::Lambda(lambda) => {
                write!(
                    f,
                    "lambda [\n{}\n]",
                    lambda
                        .to_string()
                        .lines()
                        .map(|line| format!("  {}", line))
                        .join("\n"),
                )
            }
            Expression::Body(body) => {
                write!(
                    f,
                    "body [\n{}\n]",
                    body.to_string()
                        .lines()
                        .map(|line| format!("  {}", line))
                        .join("\n"),
                )
            }
            Expression::Call {
                function,
                arguments,
            } => {
                assert!(arguments.len() > 0, "A call needs to have arguments.");
                write!(f, "call {} with {}", function, arguments.iter().join(" "))
            }
            Expression::Error => write!(f, "<error>"),
        }
    }
}
impl fmt::Display for Lambda {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} parameters\n", self.parameters.len())?;
        write!(f, "{}", self.body)?;
        Ok(())
    }
}
impl fmt::Display for Body {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for (id, expression) in self.expressions.iter() {
            write!(f, "{} = {}\n", id, expression)?;
        }
        Ok(())
    }
}

impl Expression {
    fn find(&self, id: &Id) -> Option<&Self> {
        match self {
            Expression::Int { .. } => None,
            Expression::Text { .. } => None,
            Expression::Reference { .. } => None,
            Expression::Symbol { .. } => None,
            Expression::Struct(_) => None,
            Expression::Lambda(Lambda { body, .. }) => body.find(id),
            Expression::Body(body) => body.find(id),
            Expression::Call { .. } => None,
            Expression::Error { .. } => None,
        }
    }
}
impl Body {
    fn find(&self, id: &Id) -> Option<&Expression> {
        if let Some(expression) = self.expressions.get(id) {
            Some(expression)
        } else {
            self.expressions
                .iter()
                .filter(|(key, _)| key <= &id)
                .max_by_key(|(key, _)| key.0.to_owned())?
                .1
                .find(id)
        }
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::collections::hash_map::HashMap;

#[derive(PartialEq)]
pub struct Entry {
    pub path: PathBuf,
    pub index: HashMap<char, Vec<usize>>,
}

impl Entry {
    /// Compares the query string to the entry,
    /// and returns a score between 0 and 1.
    pub fn similarity(&self, query: &str) -> f32 {
        // Exact matches produce a perfect score.
        if query == self.path.to_string_lossy() {
            return 1.0;
        }

        let mut overall_score = 0.0;
        let path_length = self.path.to_string_lossy().chars().count();

        let mut last_char = ' ';

        for (query_char_index, query_char) in query.chars().enumerate() {
            let mut character_score = 0.0;

            // Look for the query's character in the path's index, bumping
            // the character score up for each occurrence in the path.
            match self.index.get(&query_char) {
                Some(occurrences) => character_score += occurrences.len() as f32,
                None => {
                    // If this query character doesn't exist in the path,
                    // penalize the overall score.
                    overall_score -= 10.0;
                },
            }

            // Check for consecutive character matches.
            if query_char_index > 0 {
                // Lookup the previous query character's matching indices in the
                // path; we'll check to see if they're the preceding character.
                match self.index.get(&last_char) {
                    Some(occurrences) => {
                        // If the last query character matched the previous path
                        // character, there are at least two consecutive characters
                        // that match; bump the character score to account for that.
                        if occurrences.contains(&(query_char_index-1)) {
                            character_score += 1.0;
                        }
                    },
                    None => (),
                }
            }

            // Limit the character score to a maximum value
            // of "1" and add it to the overall score.
            character_score /= path_length as f32;
            overall_score += character_score;

            // Track the current char so that we can check
            // for consecutive matches on the next iteration.
            last_char = query_char;
        }

        // Return an overall score, limited to a maximum value of "1".
        (overall_score / path_length as f32).max(0.0)
    }
}

fn index_path(path: &str) -> HashMap<char, Vec<usize>> {
    let mut index: HashMap<char, Vec<usize>> = HashMap::new();
    for (char_index, path_char) in path.chars().enumerate() {
        if index.contains_key(&path_char) {
            match index.get_mut(&path_char) {
               Some(occurrences) => occurrences.push(char_index),
               None => ()
            }
        } else {
           index.insert(path_char, vec![char_index]);
        }
    }

    index
}

pub fn new(path: String) -> Entry {
    Entry{
        // Build the index before we transfer ownership of path.
        index: index_path(&path),
        path: PathBuf::from(path),
    }
}

mod tests {
    use super::new;

    #[test]
    fn similarity_correctly_scores_perfect_matches() {
        let entry = new("src/hound.rs".to_string());
        assert_eq!(entry.similarity("src/hound.rs"), 1.0);
    }

    #[test]
    fn similarity_correctly_scores_completely_different_terms() {
        let entry = new("src".to_string());
        assert_eq!(entry.similarity("lib"), 0.0);
    }

    #[test]
    fn similarity_scores_based_on_term_length() {
        let long_entry = new("houndhound".to_string());
        let differing_length_score = long_entry.similarity("houn");

        // Don't use a perfect match, since those product a perfect score.
        let short_entry = new("hound".to_string());
        let same_length_score = short_entry.similarity("houn");

        assert!(same_length_score > differing_length_score);
    }

    #[test]
    fn similarity_score_increases_for_consecutive_matches() {
        let entry = new("hound".to_string());

        // Don't use a perfect match, since those product a perfect score.
        let properly_ordered_score = entry.similarity("houn");

        let improperly_ordered_score = entry.similarity("nuoh");
        assert!(properly_ordered_score > improperly_ordered_score);
    }

    #[test]
    fn similarity_score_decreases_for_non_matching_characters() {
        let entry = new("hound".to_string());

        // Don't use a perfect match, since those product a perfect score.
        let non_matching_score = entry.similarity("houns");

        let subset_score = entry.similarity("houn");
        assert!(subset_score > non_matching_score);
    }
}
<commit_msg>Add test attribute to entry tests module.<commit_after>use std::path::PathBuf;
use std::collections::hash_map::HashMap;

#[derive(PartialEq)]
pub struct Entry {
    pub path: PathBuf,
    pub index: HashMap<char, Vec<usize>>,
}

impl Entry {
    /// Compares the query string to the entry,
    /// and returns a score between 0 and 1.
    pub fn similarity(&self, query: &str) -> f32 {
        // Exact matches produce a perfect score.
        if query == self.path.to_string_lossy() {
            return 1.0;
        }

        let mut overall_score = 0.0;
        let path_length = self.path.to_string_lossy().chars().count();

        let mut last_char = ' ';

        for (query_char_index, query_char) in query.chars().enumerate() {
            let mut character_score = 0.0;

            // Look for the query's character in the path's index, bumping
            // the character score up for each occurrence in the path.
            match self.index.get(&query_char) {
                Some(occurrences) => character_score += occurrences.len() as f32,
                None => {
                    // If this query character doesn't exist in the path,
                    // penalize the overall score.
                    overall_score -= 10.0;
                },
            }

            // Check for consecutive character matches.
            if query_char_index > 0 {
                // Lookup the previous query character's matching indices in the
                // path; we'll check to see if they're the preceding character.
                match self.index.get(&last_char) {
                    Some(occurrences) => {
                        // If the last query character matched the previous path
                        // character, there are at least two consecutive characters
                        // that match; bump the character score to account for that.
                        if occurrences.contains(&(query_char_index-1)) {
                            character_score += 1.0;
                        }
                    },
                    None => (),
                }
            }

            // Limit the character score to a maximum value
            // of "1" and add it to the overall score.
            character_score /= path_length as f32;
            overall_score += character_score;

            // Track the current char so that we can check
            // for consecutive matches on the next iteration.
            last_char = query_char;
        }

        // Return an overall score, limited to a maximum value of "1".
        (overall_score / path_length as f32).max(0.0)
    }
}

fn index_path(path: &str) -> HashMap<char, Vec<usize>> {
    let mut index: HashMap<char, Vec<usize>> = HashMap::new();
    for (char_index, path_char) in path.chars().enumerate() {
        if index.contains_key(&path_char) {
            match index.get_mut(&path_char) {
               Some(occurrences) => occurrences.push(char_index),
               None => ()
            }
        } else {
           index.insert(path_char, vec![char_index]);
        }
    }

    index
}

pub fn new(path: String) -> Entry {
    Entry{
        // Build the index before we transfer ownership of path.
        index: index_path(&path),
        path: PathBuf::from(path),
    }
}

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

    #[test]
    fn similarity_correctly_scores_perfect_matches() {
        let entry = new("src/hound.rs".to_string());
        assert_eq!(entry.similarity("src/hound.rs"), 1.0);
    }

    #[test]
    fn similarity_correctly_scores_completely_different_terms() {
        let entry = new("src".to_string());
        assert_eq!(entry.similarity("lib"), 0.0);
    }

    #[test]
    fn similarity_scores_based_on_term_length() {
        let long_entry = new("houndhound".to_string());
        let differing_length_score = long_entry.similarity("houn");

        // Don't use a perfect match, since those product a perfect score.
        let short_entry = new("hound".to_string());
        let same_length_score = short_entry.similarity("houn");

        assert!(same_length_score > differing_length_score);
    }

    #[test]
    fn similarity_score_increases_for_consecutive_matches() {
        let entry = new("hound".to_string());

        // Don't use a perfect match, since those product a perfect score.
        let properly_ordered_score = entry.similarity("houn");

        let improperly_ordered_score = entry.similarity("nuoh");
        assert!(properly_ordered_score > improperly_ordered_score);
    }

    #[test]
    fn similarity_score_decreases_for_non_matching_characters() {
        let entry = new("hound".to_string());

        // Don't use a perfect match, since those product a perfect score.
        let non_matching_score = entry.similarity("houns");

        let subset_score = entry.similarity("houn");
        assert!(subset_score > non_matching_score);
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Timothée Ravier
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::io::{Error, ErrorKind, Result};

use ffi::*;
use handle::Handle;

pub struct MessageBuilder {
    destination_handles: Vec<Handle>,
    handles: Vec<Handle>,
    fds: Vec<u64>,
    data: Vec<Vec<u8>>,
}

impl MessageBuilder {
    pub fn new() -> MessageBuilder {
        MessageBuilder {
            destination_handles: vec![],
            handles: vec![],
            fds: vec![],
            data: vec![],
        }
    }

    pub fn add_destinations(&mut self, handles: &mut Vec<Handle>)  {
        if handles.is_empty() {
            return
        }
        debug!("Adding destinations: {:?}", handles);
        self.destination_handles.append(handles);
    }

    pub fn add_handles(&mut self, handles: &mut Vec<Handle>) {
        if handles.is_empty() {
            return
        }
        debug!("Adding handles: {:?}", handles);
        self.handles.append(handles);
    }

    pub fn add_data(&mut self, data: Vec<u8>) {
        if data.is_empty() {
            return
        }
        self.data.push(data);
    }

    pub fn add_fds(&mut self, fds: &mut Vec<u64>) {
        if fds.is_empty() {
            return
        }
        self.fds.append(fds);
    }

    // TODO: Add phantomdata?
    // pub fn build(self) -> Result<bus1_cmd_send> {
    pub fn build(&mut self) -> Result<bus1_cmd_send> {
        let mut cmd_send: bus1_cmd_send = Default::default();

        if self.destination_handles.len() == 0 {
            return Err(Error::new(ErrorKind::Other, "No destination handles"));
        }
        cmd_send.ptr_destinations = self.destination_handles.as_mut_ptr() as *mut u64;
        cmd_send.n_destinations = self.destination_handles.len() as u64;

        cmd_send.ptr_handles = self.handles.as_mut_ptr() as *mut u64;
        cmd_send.n_handles = self.handles.len() as u64;

        // TODO: fds

        // TODO: data
        // if data.len() != 0 {
        //     cmd_send.ptr_vecs = vec![
        //         iovec {
        //             iov_base: data.as_mut_ptr() as *mut c_void,
        //             iov_len: data.len() as size_t
        //         }
        //     ].as_mut_ptr() as *mut u64;
        //     cmd_send.n_vecs = 1;
        // }

        Ok(cmd_send)
    }
}
<commit_msg>messagebuilder: do not set empty handle array in messages<commit_after>// Copyright 2016 Timothée Ravier
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::io::{Error, ErrorKind, Result};

use ffi::*;
use handle::Handle;

pub struct MessageBuilder {
    destination_handles: Vec<Handle>,
    handles: Vec<Handle>,
    fds: Vec<u64>,
    data: Vec<Vec<u8>>,
}

impl MessageBuilder {
    pub fn new() -> MessageBuilder {
        MessageBuilder {
            destination_handles: vec![],
            handles: vec![],
            fds: vec![],
            data: vec![],
        }
    }

    pub fn add_destinations(&mut self, handles: &mut Vec<Handle>)  {
        if handles.is_empty() {
            return
        }
        debug!("Adding destinations: {:?}", handles);
        self.destination_handles.append(handles);
    }

    pub fn add_handles(&mut self, handles: &mut Vec<Handle>) {
        if handles.is_empty() {
            return
        }
        debug!("Adding handles: {:?}", handles);
        self.handles.append(handles);
    }

    pub fn add_data(&mut self, data: Vec<u8>) {
        if data.is_empty() {
            return
        }
        self.data.push(data);
    }

    pub fn add_fds(&mut self, fds: &mut Vec<u64>) {
        if fds.is_empty() {
            return
        }
        self.fds.append(fds);
    }

    // TODO: Add phantomdata?
    // pub fn build(self) -> Result<bus1_cmd_send> {
    pub fn build(&mut self) -> Result<bus1_cmd_send> {
        let mut cmd_send: bus1_cmd_send = Default::default();

        if self.destination_handles.len() == 0 {
            return Err(Error::new(ErrorKind::Other, "No destination handles"));
        }
        cmd_send.ptr_destinations = self.destination_handles.as_mut_ptr() as *mut u64;
        cmd_send.n_destinations = self.destination_handles.len() as u64;

        if self.handles.len() != 0 {
            cmd_send.ptr_handles = self.handles.as_mut_ptr() as *mut u64;
            cmd_send.n_handles = self.handles.len() as u64;
        }

        if self.fds.len() != 0 {
            // TODO
            unimplemented!();
        }

        // TODO: data
        // if data.len() != 0 {
        //     cmd_send.ptr_vecs = vec![
        //         iovec {
        //             iov_base: data.as_mut_ptr() as *mut c_void,
        //             iov_len: data.len() as size_t
        //         }
        //     ].as_mut_ptr() as *mut u64;
        //     cmd_send.n_vecs = 1;
        // }

        Ok(cmd_send)
    }
}
<|endoftext|>


<commit_before>use crate::io;
use std::fs::File;
use flate2::read::GzDecoder;

pub struct MultiFile {
    files_iterator: Box<dyn Iterator<Item = String>>,
    current_file: Option<Box<dyn io::Read>>,
}

impl MultiFile {
    pub fn new(filenames: Vec<String>) -> MultiFile {
        MultiFile {
            files_iterator: Box::new(filenames.into_iter()),
            current_file: None,
        }
    }
}

impl io::Read for MultiFile {
    fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
        let read_size = match self.current_file {
            Some(ref mut file) => file.read(buf),
            None => {
                self.current_file = match &self.files_iterator.next() {
                    Some(file) if file.ends_with(".gz") => Some(Box::new(
                        GzDecoder::new(File::open(file)?),
                    )),
                    Some(file) => Some(Box::new(File::open(file)?)),
                    None => {
                        return Ok(0);
                    }
                };
                return self.read(&mut buf);
            }
        };

        match read_size {
            Ok(0) => {
                // EOF, proceed with next file
                self.current_file = None;
                self.read(&mut buf)
            }
            Ok(read_size) => Ok(read_size),
            Err(err) => Err(err),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io;
    use std::io::Read;
    use std::io::BufRead;

    use super::*;

    #[test]
    fn test_read_single() {
        let filenames = vec![String::from("src/test/simple-1.log")];
        let input = MultiFile::new(filenames);

        let reader = io::BufReader::new(input);

        let result = reader.lines().count();
        assert_eq!(result, 4);
    }

    #[test]
    fn test_read_all() {
        let filenames = vec![
            String::from("src/test/simple-1.log"),
            String::from("src/test/simple-2.log"),
        ];
        let input = MultiFile::new(filenames);

        let reader = io::BufReader::new(input);

        let result = reader.lines().count();
        assert_eq!(result, 8);
    }

    #[test]
    fn test_read_non_existent() {
        let filenames = vec![String::from("src/test/non-existent.log")];
        let mut input = MultiFile::new(filenames);
        let mut buffer = [0; 10];
        let result = input.read(&mut buffer);

        assert!(result.is_err());
    }

    #[test]
    fn test_read_second_non_existent() {
        let filenames = vec![
            String::from("src/test/empty.log"),
            String::from("src/test/non-existent.log"),
        ];
        let mut input = MultiFile::new(filenames);
        let mut buffer = [0; 10];
        let result = input.read(&mut buffer);

        assert!(result.is_err());
    }

    #[test]
    fn test_read_no_files_means_eof() {
        let filenames = vec![];
        let mut input = MultiFile::new(filenames);
        let mut buffer = [0; 10];
        let result = input.read(&mut buffer);

        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 0);
    }

    #[test]
    fn test_read_with_gzip() {
        let filenames = vec![
            String::from("src/test/simple-1.log"),
            String::from("src/test/simple-1.log.gz"),
        ];
        let input = MultiFile::new(filenames);

        let reader = io::BufReader::new(input);

        let result = reader.lines().count();
        assert_eq!(result, 8);
    }
}
<commit_msg>Fix false positive of `cargo fix`<commit_after>use std::io;
use std::fs::File;
use flate2::read::GzDecoder;

pub struct MultiFile {
    files_iterator: Box<dyn Iterator<Item = String>>,
    current_file: Option<Box<dyn io::Read>>,
}

impl MultiFile {
    pub fn new(filenames: Vec<String>) -> MultiFile {
        MultiFile {
            files_iterator: Box::new(filenames.into_iter()),
            current_file: None,
        }
    }
}

impl io::Read for MultiFile {
    fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
        let read_size = match self.current_file {
            Some(ref mut file) => file.read(buf),
            None => {
                self.current_file = match &self.files_iterator.next() {
                    Some(file) if file.ends_with(".gz") => Some(Box::new(
                        GzDecoder::new(File::open(file)?),
                    )),
                    Some(file) => Some(Box::new(File::open(file)?)),
                    None => {
                        return Ok(0);
                    }
                };
                return self.read(&mut buf);
            }
        };

        match read_size {
            Ok(0) => {
                // EOF, proceed with next file
                self.current_file = None;
                self.read(&mut buf)
            }
            Ok(read_size) => Ok(read_size),
            Err(err) => Err(err),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io;
    use std::io::Read;
    use std::io::BufRead;

    use super::*;

    #[test]
    fn test_read_single() {
        let filenames = vec![String::from("src/test/simple-1.log")];
        let input = MultiFile::new(filenames);

        let reader = io::BufReader::new(input);

        let result = reader.lines().count();
        assert_eq!(result, 4);
    }

    #[test]
    fn test_read_all() {
        let filenames = vec![
            String::from("src/test/simple-1.log"),
            String::from("src/test/simple-2.log"),
        ];
        let input = MultiFile::new(filenames);

        let reader = io::BufReader::new(input);

        let result = reader.lines().count();
        assert_eq!(result, 8);
    }

    #[test]
    fn test_read_non_existent() {
        let filenames = vec![String::from("src/test/non-existent.log")];
        let mut input = MultiFile::new(filenames);
        let mut buffer = [0; 10];
        let result = input.read(&mut buffer);

        assert!(result.is_err());
    }

    #[test]
    fn test_read_second_non_existent() {
        let filenames = vec![
            String::from("src/test/empty.log"),
            String::from("src/test/non-existent.log"),
        ];
        let mut input = MultiFile::new(filenames);
        let mut buffer = [0; 10];
        let result = input.read(&mut buffer);

        assert!(result.is_err());
    }

    #[test]
    fn test_read_no_files_means_eof() {
        let filenames = vec![];
        let mut input = MultiFile::new(filenames);
        let mut buffer = [0; 10];
        let result = input.read(&mut buffer);

        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 0);
    }

    #[test]
    fn test_read_with_gzip() {
        let filenames = vec![
            String::from("src/test/simple-1.log"),
            String::from("src/test/simple-1.log.gz"),
        ];
        let input = MultiFile::new(filenames);

        let reader = io::BufReader::new(input);

        let result = reader.lines().count();
        assert_eq!(result, 8);
    }
}
<|endoftext|>


<commit_before>#[crate_id = "timer"];
#[crate_type = "lib"];

extern crate extra;

static SEC_MULTIPLIER:u64 = 1000 * 1000 * 1000;
static MIN_MULTIPLIER:u64 = 60 * SEC_MULTIPLIER;
static HR_MULTIPLIER:u64 = 60 * MIN_MULTIPLIER;

pub struct Timer {
    start_time: u64,
    end_time: u64
}

impl Timer {
    pub fn new() -> Timer {
        Timer { start_time: 0, end_time: 0}
    }
    pub fn start(&mut self) -> () {
        self.start_time = extra::time::precise_time_ns();
    }
    pub fn end(&mut self) -> () {
        self.end_time = extra::time::precise_time_ns();
    }
    pub fn get_time_string(&mut self) -> ~str {
        return format_as_time(self.get_total_time());
    }
    pub fn get_total_time(&mut self) -> u64 {
        return self.end_time - self.start_time;
    }
    pub fn show_time(&mut self) -> () {
        println!("Total time: {:s}", self.get_time_string());
    }
}

pub fn format_as_time(total_time: u64) -> ~str {
    let hours = total_time / HR_MULTIPLIER;
    let minutes = (total_time
                   - hours * HR_MULTIPLIER)
        / MIN_MULTIPLIER;
    let seconds = (total_time
                   - hours * HR_MULTIPLIER
                   - minutes * MIN_MULTIPLIER)
        / SEC_MULTIPLIER;
    let nanoseconds = (total_time
                       - hours * HR_MULTIPLIER
                       - minutes * MIN_MULTIPLIER
                       - seconds * SEC_MULTIPLIER);

    let mut time_string = ~"";
    if hours > 0 {
        time_string.push_str(format!("{}:", hours as int));
    }
    if hours > 0 || minutes > 0 {
        if minutes < 10 && hours > 0 {
            time_string.push_str("0");
        }
        time_string.push_str(format!("{}:", minutes as int));
    }
    if hours > 0 || minutes > 0 || seconds > 0 {
        if seconds < 10 && (minutes > 0 || hours > 0) {
            // HACK: format!("%02?.", seconds) doesn't zero pad
            time_string.push_str("0");
        }
        time_string.push_str(format!("{}.", seconds as int));
        // nanoseconds don't need to be quite as accurate if we measure seconds
        let ns_as_string = format!("{:.5?}", (nanoseconds as f64) / (SEC_MULTIPLIER as f64));
        time_string.push_str(format!("{:s}", ns_as_string.slice(2, 5)));
    } else {
        time_string.push_str(format!("{:s}", format_number(nanoseconds)));
    }

    if hours > 0 {
        time_string.push_str(" hr");
    } else if minutes > 0 {
        time_string.push_str(" min");
    } else if seconds > 0 {
        time_string.push_str(" sec");
    } else {
        time_string.push_str(" ns");
    }

    //time_string += format!(" ({})", total_time);

    return time_string;
}

fn format_number(num: u64) -> ~str {
    let repr = num.to_str();
    let mut ret_val = ~"";
    let mut index = 0;
    let length = repr.len();

    while index < length {
        ret_val.push_str(repr.slice(index, index + 1));

        if (length - index - 1) % 3 == 0 && length > index + 1{
            ret_val.push_str(",");
        }
        index += 1;
    }

    return ret_val
}

#[test]
fn format_number_test() {
    let num1 = 123456789;
    let num2 = 12345678;
    let num3 = 1234;

    assert!(format_number(num1) == ~"123,456,789");
    assert!(format_number(num2) == ~"12,345,678");
    assert!(format_number(num3) == ~"1,234");
}

#[test]
fn format_as_time_test() {
    let num1 = 2000;    // ns
    let num2 = 3 * SEC_MULTIPLIER + 141591234;
    let num3 = 1 * MIN_MULTIPLIER + 5 * SEC_MULTIPLIER + 98765432;
    let num4 = 3 * HR_MULTIPLIER + num3;

    assert!(format_as_time(num1) == ~"2,000 ns");
    assert!(format_as_time(num2) == ~"3.141 sec");
    assert!(format_as_time(num3) == ~"1:05.098 min");
    assert!(format_as_time(num4) == ~"3:01:05.098 hr");
}
<commit_msg>Update for moved `time` crate<commit_after>#[crate_id = "timer"];
#[crate_type = "lib"];

extern crate time;

static SEC_MULTIPLIER:u64 = 1000 * 1000 * 1000;
static MIN_MULTIPLIER:u64 = 60 * SEC_MULTIPLIER;
static HR_MULTIPLIER:u64 = 60 * MIN_MULTIPLIER;

pub struct Timer {
    start_time: u64,
    end_time: u64
}

impl Timer {
    pub fn new() -> Timer {
        Timer { start_time: 0, end_time: 0}
    }
    pub fn start(&mut self) -> () {
        self.start_time = time::precise_time_ns();
    }
    pub fn end(&mut self) -> () {
        self.end_time = time::precise_time_ns();
    }
    pub fn get_time_string(&mut self) -> ~str {
        return format_as_time(self.get_total_time());
    }
    pub fn get_total_time(&mut self) -> u64 {
        return self.end_time - self.start_time;
    }
    pub fn show_time(&mut self) -> () {
        println!("Total time: {:s}", self.get_time_string());
    }
}

pub fn format_as_time(total_time: u64) -> ~str {
    let hours = total_time / HR_MULTIPLIER;
    let minutes = (total_time
                   - hours * HR_MULTIPLIER)
        / MIN_MULTIPLIER;
    let seconds = (total_time
                   - hours * HR_MULTIPLIER
                   - minutes * MIN_MULTIPLIER)
        / SEC_MULTIPLIER;
    let nanoseconds = total_time
                       - hours * HR_MULTIPLIER
                       - minutes * MIN_MULTIPLIER
                       - seconds * SEC_MULTIPLIER;

    let mut time_string = ~"";
    if hours > 0 {
        time_string.push_str(format!("{}:", hours as int));
    }
    if hours > 0 || minutes > 0 {
        if minutes < 10 && hours > 0 {
            time_string.push_str("0");
        }
        time_string.push_str(format!("{}:", minutes as int));
    }
    if hours > 0 || minutes > 0 || seconds > 0 {
        if seconds < 10 && (minutes > 0 || hours > 0) {
            // HACK: format!("%02?.", seconds) doesn't zero pad
            time_string.push_str("0");
        }
        time_string.push_str(format!("{}.", seconds as int));
        // nanoseconds don't need to be quite as accurate if we measure seconds
        let ns_as_string = format!("{:.5?}", (nanoseconds as f64) / (SEC_MULTIPLIER as f64));
        time_string.push_str(format!("{:s}", ns_as_string.slice(2, 5)));
    } else {
        time_string.push_str(format!("{:s}", format_number(nanoseconds)));
    }

    if hours > 0 {
        time_string.push_str(" hr");
    } else if minutes > 0 {
        time_string.push_str(" min");
    } else if seconds > 0 {
        time_string.push_str(" sec");
    } else {
        time_string.push_str(" ns");
    }

    //time_string += format!(" ({})", total_time);

    return time_string;
}

fn format_number(num: u64) -> ~str {
    let repr = num.to_str();
    let mut ret_val = ~"";
    let mut index = 0;
    let length = repr.len();

    while index < length {
        ret_val.push_str(repr.slice(index, index + 1));

        if (length - index - 1) % 3 == 0 && length > index + 1{
            ret_val.push_str(",");
        }
        index += 1;
    }

    return ret_val
}

#[test]
fn format_number_test() {
    let num1 = 123456789;
    let num2 = 12345678;
    let num3 = 1234;

    assert!(format_number(num1) == ~"123,456,789");
    assert!(format_number(num2) == ~"12,345,678");
    assert!(format_number(num3) == ~"1,234");
}

#[test]
fn format_as_time_test() {
    let num1 = 2000;    // ns
    let num2 = 3 * SEC_MULTIPLIER + 141591234;
    let num3 = 1 * MIN_MULTIPLIER + 5 * SEC_MULTIPLIER + 98765432;
    let num4 = 3 * HR_MULTIPLIER + num3;

    assert!(format_as_time(num1) == ~"2,000 ns");
    assert!(format_as_time(num2) == ~"3.141 sec");
    assert!(format_as_time(num3) == ~"1:05.098 min");
    assert!(format_as_time(num4) == ~"3:01:05.098 hr");
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use std::collections::hash_map::HashMap;
use std::io::BufReader;
use std::io::prelude::*;
use std::process::ChildStdin;
use std::process::Command;
use std::process::Stdio;
use std::sync::mpsc;
use std::thread;

use serde_json;
use serde_json::builder::*;
use serde_json::Value;

pub struct Core {
    stdin: ChildStdin,
    pub update_rx: mpsc::Receiver<Value>,
    rpc_rx: mpsc::Receiver<(u64,Value)>, // ! A simple piping works only for synchronous calls.
    rpc_index: u64,
    current_view: String,
    views: HashMap<String, String>,
}

impl Core {
    pub fn new(executable: &str, file: &str) -> Core {
        // spawn the core process
        let process = Command::new(executable)
                                .arg(file)
                                .stdout(Stdio::piped())
                                .stdin(Stdio::piped())
                                .stderr(Stdio::piped())
                                .env("RUST_BACKTRACE", "1")
                                .spawn()
                                .unwrap_or_else(|e| { panic!("failed to execute core: {}", e) });

        let (update_tx, update_rx) = mpsc::channel();
        let (rpc_tx, rpc_rx) = mpsc::channel();
        let stdout = process.stdout.unwrap();
        thread::spawn(move || {
            for line in BufReader::new(stdout).lines() {
                if let Ok(data) = serde_json::from_slice::<Value>(line.unwrap().as_bytes()) {
                    let req = data.as_object().unwrap();
                    info!("<<< {:?}", req);
                    if let (Some(id), Some(result)) = (req.get("id"), req.get("result")) {
                        rpc_tx.send((id.as_u64().unwrap(), result.clone())).unwrap();
                        info!(">>> {:?}", (id.as_u64().unwrap(), result.clone()));
                    } else if let (Some(method), Some(params)) = (req.get("method"), req.get("params")) {
                        if method.as_str().unwrap() == "update" {
                            update_tx.send(params.clone()).unwrap();
                        } else {
                            panic!("Unknown method {:?}.", method.as_str().unwrap());
                        }
                    } else {
                        panic!("Could not parse the core output: {:?}", req);
                    }
                }
            }
        });

        let stderr = process.stderr.unwrap();
        thread::spawn(move || {
            let buf_reader = BufReader::new(stderr);
            for line in buf_reader.lines() {
                if let Ok(line) = line {
                    error!("[core] {}", line);
                }
            }
        });

        let stdin = process.stdin.unwrap();

        let mut core = Core {
            stdin: stdin,
            update_rx: update_rx,
            rpc_rx: rpc_rx,
            rpc_index: 0,
            current_view: "".into(),
            views: HashMap::new(),
        };
        let view_id = core.new_view(Some(file.to_string())).as_str().unwrap().to_string();
        core.views.insert(view_id.clone(), file.to_string());
        core.current_view = view_id;
        core
    }

    /// Build and send a JSON RPC request, returning the associated request ID to pair it with
    /// the response
    fn request(&mut self, method: &str, params: Value) -> u64 {
        self.rpc_index += 1;
        let message = ObjectBuilder::new()
            .insert("id", self.rpc_index)
            .insert("method", method)
            .insert("params", params)
            .build();
        self.send(&message);
        self.rpc_index
    }

    /// Build and send a JSON RPC notification. No synchronous response is expected, so
    /// there is no ID.
    fn notify(&mut self, method: &str, params: Value) {
        let message = ObjectBuilder::new()
            .insert("method", method)
            .insert("params", params)
            .build();
        self.send(&message);
    }

    /// Serialize JSON object and send it to the server
    fn send(&mut self, message: &Value) {
        let mut str_msg = serde_json::ser::to_string(&message).unwrap();
        str_msg.push('\n');
        self.stdin.write(str_msg.as_bytes()).unwrap();
    }

    fn call_sync(&mut self, method: &str, params: Value) -> Value {
        let i = self.request(method, params);
        let (id,result) = self.rpc_rx.recv().unwrap();
        assert_eq!(i, id);
        result
    }

    fn call_edit(&mut self, method: &str, params: Option<Value>) {
        let obj = ObjectBuilder::new()
            .insert("method", method)
            .insert("view_id", &self.current_view)
            .insert("params", params.unwrap_or(ArrayBuilder::new().build()));
        let built_obj = obj.build();
        info!(">>> {:?}", built_obj);
        self.notify("edit", built_obj);
    }

    fn call_edit_sync(&mut self, method: &str, params: Option<Value>) -> Value{
        let obj = ObjectBuilder::new()
            .insert("method", method)
            .insert("view_id", &self.current_view)
            .insert("params", params.unwrap_or(ArrayBuilder::new().build()));
        self.call_sync("edit", obj.build())
    }

    pub fn new_view(&mut self, file_path: Option<String>) -> Value {
        let mut obj = ObjectBuilder::new();
        if file_path.is_some() {
            obj = obj.insert("file_path", file_path.unwrap());
        }
        self.call_sync("new_view", obj.build())
    }

    pub fn save(&mut self) {
        let save_params = ObjectBuilder::new()
            .insert("view_id", &self.current_view)
            .insert("file_path", self.views.get(&self.current_view).unwrap())
            .build();
        self.request("save", save_params);
    }

    pub fn open(&mut self, filename: &str) {
        self.call_edit("open", Some(ObjectBuilder::new().insert("filename", filename).build()));
    }

    pub fn left(&mut self) { self.call_edit("move_left", None); }
    pub fn left_sel(&mut self) { self.call_edit("move_left_and_modify_selection", None); }

    pub fn right(&mut self) { self.call_edit("move_right", None); }
    pub fn right_sel(&mut self) { self.call_edit("move_right_and_modify_selection", None); }

    pub fn up(&mut self) { self.call_edit("move_up", None); }
    pub fn up_sel(&mut self) { self.call_edit("move_up_and_modify_selection", None); }

    pub fn down(&mut self) { self.call_edit("move_down", None); }
    pub fn down_sel(&mut self) { self.call_edit("move_down_and_modify_selection", None); }

    pub fn del(&mut self) { self.call_edit("delete_backward", None); }

    pub fn page_up(&mut self) { self.call_edit("page_up", None); }
    pub fn page_up_sel(&mut self) { self.call_edit("page_up_and_modify_selection", None); }

    pub fn page_down(&mut self) { self.call_edit("page_down", None); }
    pub fn page_down_sel(&mut self) { self.call_edit("page_down_and_modify_selection", None); }

    pub fn insert_newline(&mut self) { self.call_edit("insert_newline", None); }

    pub fn f1(&mut self) { self.call_edit("debug_rewrap", None); }

    pub fn f2(&mut self) { self.call_edit("debug_test_fg_spans", None); }

    pub fn char(&mut self, ch: char) {
        self.call_edit("insert", Some(ObjectBuilder::new().insert("chars", ch).build()));
    }

    pub fn scroll(&mut self, start: u64, end: u64) {
        self.call_edit("scroll", Some(ArrayBuilder::new().push(start).push(end).build()));
    }

    pub fn click(&mut self, line: u64, column: u64) {
        self.call_edit("click", Some(ArrayBuilder::new().push(line).push(column).push(0).push(1).build()));
    }
    pub fn drag(&mut self, line: u64, column: u64) {
        self.call_edit("drag", Some(ArrayBuilder::new().push(line).push(column).push(0).push(1).build()));
    }

    pub fn copy(&mut self) -> String {
        self.call_edit_sync("copy", None).as_str().map(|x|x.into()).unwrap()
    }
    pub fn cut(&mut self) -> String {
        self.call_edit_sync("cut", None).as_str().map(|x|x.into()).unwrap()
    }
    pub fn paste(&mut self, s: String) {
        self.call_edit("insert", Some(ObjectBuilder::new().insert("chars", s).build()));
    }

    #[allow(dead_code)]
    pub fn test(&mut self) {
        self.render_lines(0, 10);
    }

    pub fn render_lines(&mut self, _start: u64, _end: u64) {
        unimplemented!()
        // self.rpc_index += 1;
        // println!("render_lines");
        // let value = ArrayBuilder::new()
        //     .push("rpc")
        //     .push_object(|builder| builder
        //         .insert("index", self.rpc_index)
        //         .insert_array("request", |builder| builder
        //             .push("render_lines")
        //             .push_object(|builder| builder
        //                 .insert("first_line", _start)
        //                 .insert("last_line", _end)
        //             )
        //         )
        //     ).unwrap();
        // self.write(value);
    }

    pub fn render_lines_sync(&mut self, _start: u64, _end: u64) -> Value {
        unimplemented!()
        // self.render_lines(_start, _end);
        // let value = self.rpc_rx.recv().unwrap();
        // let object = value.as_object().unwrap();
        // assert_eq!(self.rpc_index, object.get("index").unwrap().as_u64().unwrap());
        // object.get("result").unwrap().clone()
    }
}
<commit_msg>Adds support for all current backend requests in the recv thread<commit_after>#![allow(dead_code)]
use std::collections::hash_map::HashMap;
use std::io::BufReader;
use std::io::prelude::*;
use std::process::ChildStdin;
use std::process::Command;
use std::process::Stdio;
use std::sync::mpsc;
use std::thread;

use serde_json;
use serde_json::builder::*;
use serde_json::Value;

pub struct Core {
    stdin: ChildStdin,
    pub update_rx: mpsc::Receiver<Value>,
    rpc_rx: mpsc::Receiver<(u64,Value)>, // ! A simple piping works only for synchronous calls.
    rpc_index: u64,
    current_view: String,
    views: HashMap<String, String>,
}

impl Core {
    pub fn new(executable: &str, file: &str) -> Core {
        // spawn the core process
        let process = Command::new(executable)
                                .arg(file)
                                .stdout(Stdio::piped())
                                .stdin(Stdio::piped())
                                .stderr(Stdio::piped())
                                .env("RUST_BACKTRACE", "1")
                                .spawn()
                                .unwrap_or_else(|e| { panic!("failed to execute core: {}", e) });

        let (update_tx, update_rx) = mpsc::channel();
        let (rpc_tx, rpc_rx) = mpsc::channel();
        let stdout = process.stdout.unwrap();
        thread::spawn(move || {
            for line in BufReader::new(stdout).lines() {
                if let Ok(data) = serde_json::from_slice::<Value>(line.unwrap().as_bytes()) {
                    let req = data.as_object().unwrap();
                    info!("<<< {:?}", req);
                    if let (Some(id), Some(result)) = (req.get("id"), req.get("result")) {
                        rpc_tx.send((id.as_u64().unwrap(), result.clone())).unwrap();
                        info!(">>> {:?}", (id.as_u64().unwrap(), result.clone()));
                    } else if let (Some(method), Some(params)) = (req.get("method"), req.get("params")) {
                        let meth = method.as_str().unwrap();
                        if meth == "set_style" || meth == "scroll_to" || meth == "update" {
                            let request = ArrayBuilder::new().push(method.clone()).push(params.clone()).build();
                            update_tx.send(request).unwrap();
                        } else {
                            panic!("Unknown method {:?}.", method.as_str().unwrap());
                        }
                    } else {
                        panic!("Could not parse the core output: {:?}", req);
                    }
                }
            }
        });

        let stderr = process.stderr.unwrap();
        thread::spawn(move || {
            let buf_reader = BufReader::new(stderr);
            for line in buf_reader.lines() {
                if let Ok(line) = line {
                    error!("[core] {}", line);
                }
            }
        });

        let stdin = process.stdin.unwrap();

        let mut core = Core {
            stdin: stdin,
            update_rx: update_rx,
            rpc_rx: rpc_rx,
            rpc_index: 0,
            current_view: "".into(),
            views: HashMap::new(),
        };
        let view_id = core.new_view(Some(file.to_string())).as_str().unwrap().to_string();
        core.views.insert(view_id.clone(), file.to_string());
        core.current_view = view_id;
        core
    }

    /// Build and send a JSON RPC request, returning the associated request ID to pair it with
    /// the response
    fn request(&mut self, method: &str, params: Value) -> u64 {
        self.rpc_index += 1;
        let message = ObjectBuilder::new()
            .insert("id", self.rpc_index)
            .insert("method", method)
            .insert("params", params)
            .build();
        self.send(&message);
        self.rpc_index
    }

    /// Build and send a JSON RPC notification. No synchronous response is expected, so
    /// there is no ID.
    fn notify(&mut self, method: &str, params: Value) {
        let message = ObjectBuilder::new()
            .insert("method", method)
            .insert("params", params)
            .build();
        self.send(&message);
    }

    /// Serialize JSON object and send it to the server
    fn send(&mut self, message: &Value) {
        let mut str_msg = serde_json::ser::to_string(&message).unwrap();
        str_msg.push('\n');
        self.stdin.write(str_msg.as_bytes()).unwrap();
    }

    fn call_sync(&mut self, method: &str, params: Value) -> Value {
        let i = self.request(method, params);
        let (id,result) = self.rpc_rx.recv().unwrap();
        assert_eq!(i, id);
        result
    }

    fn call_edit(&mut self, method: &str, params: Option<Value>) {
        let obj = ObjectBuilder::new()
            .insert("method", method)
            .insert("view_id", &self.current_view)
            .insert("params", params.unwrap_or(ArrayBuilder::new().build()));
        let built_obj = obj.build();
        info!(">>> {:?}", built_obj);
        self.notify("edit", built_obj);
    }

    fn call_edit_sync(&mut self, method: &str, params: Option<Value>) -> Value{
        let obj = ObjectBuilder::new()
            .insert("method", method)
            .insert("view_id", &self.current_view)
            .insert("params", params.unwrap_or(ArrayBuilder::new().build()));
        self.call_sync("edit", obj.build())
    }

    pub fn new_view(&mut self, file_path: Option<String>) -> Value {
        let mut obj = ObjectBuilder::new();
        if file_path.is_some() {
            obj = obj.insert("file_path", file_path.unwrap());
        }
        self.call_sync("new_view", obj.build())
    }

    pub fn save(&mut self) {
        let save_params = ObjectBuilder::new()
            .insert("view_id", &self.current_view)
            .insert("file_path", self.views.get(&self.current_view).unwrap())
            .build();
        self.request("save", save_params);
    }

    pub fn open(&mut self, filename: &str) {
        self.call_edit("open", Some(ObjectBuilder::new().insert("filename", filename).build()));
    }

    pub fn left(&mut self) { self.call_edit("move_left", None); }
    pub fn left_sel(&mut self) { self.call_edit("move_left_and_modify_selection", None); }

    pub fn right(&mut self) { self.call_edit("move_right", None); }
    pub fn right_sel(&mut self) { self.call_edit("move_right_and_modify_selection", None); }

    pub fn up(&mut self) { self.call_edit("move_up", None); }
    pub fn up_sel(&mut self) { self.call_edit("move_up_and_modify_selection", None); }

    pub fn down(&mut self) { self.call_edit("move_down", None); }
    pub fn down_sel(&mut self) { self.call_edit("move_down_and_modify_selection", None); }

    pub fn del(&mut self) { self.call_edit("delete_backward", None); }

    pub fn page_up(&mut self) { self.call_edit("page_up", None); }
    pub fn page_up_sel(&mut self) { self.call_edit("page_up_and_modify_selection", None); }

    pub fn page_down(&mut self) { self.call_edit("page_down", None); }
    pub fn page_down_sel(&mut self) { self.call_edit("page_down_and_modify_selection", None); }

    pub fn insert_newline(&mut self) { self.call_edit("insert_newline", None); }

    pub fn f1(&mut self) { self.call_edit("debug_rewrap", None); }

    pub fn f2(&mut self) { self.call_edit("debug_test_fg_spans", None); }

    pub fn char(&mut self, ch: char) {
        self.call_edit("insert", Some(ObjectBuilder::new().insert("chars", ch).build()));
    }

    pub fn scroll(&mut self, start: u64, end: u64) {
        self.call_edit("scroll", Some(ArrayBuilder::new().push(start).push(end).build()));
    }

    pub fn click(&mut self, line: u64, column: u64) {
        self.call_edit("click", Some(ArrayBuilder::new().push(line).push(column).push(0).push(1).build()));
    }
    pub fn drag(&mut self, line: u64, column: u64) {
        self.call_edit("drag", Some(ArrayBuilder::new().push(line).push(column).push(0).push(1).build()));
    }

    pub fn copy(&mut self) -> String {
        self.call_edit_sync("copy", None).as_str().map(|x|x.into()).unwrap()
    }
    pub fn cut(&mut self) -> String {
        self.call_edit_sync("cut", None).as_str().map(|x|x.into()).unwrap()
    }
    pub fn paste(&mut self, s: String) {
        self.call_edit("insert", Some(ObjectBuilder::new().insert("chars", s).build()));
    }

    #[allow(dead_code)]
    pub fn test(&mut self) {
        self.render_lines(0, 10);
    }

    pub fn render_lines(&mut self, _start: u64, _end: u64) {
        unimplemented!()
        // self.rpc_index += 1;
        // println!("render_lines");
        // let value = ArrayBuilder::new()
        //     .push("rpc")
        //     .push_object(|builder| builder
        //         .insert("index", self.rpc_index)
        //         .insert_array("request", |builder| builder
        //             .push("render_lines")
        //             .push_object(|builder| builder
        //                 .insert("first_line", _start)
        //                 .insert("last_line", _end)
        //             )
        //         )
        //     ).unwrap();
        // self.write(value);
    }

    pub fn render_lines_sync(&mut self, _start: u64, _end: u64) -> Value {
        unimplemented!()
        // self.render_lines(_start, _end);
        // let value = self.rpc_rx.recv().unwrap();
        // let object = value.as_object().unwrap();
        // assert_eq!(self.rpc_index, object.get("index").unwrap().as_u64().unwrap());
        // object.get("result").unwrap().clone()
    }
}
<|endoftext|>