<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str, ptr, mem};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char, c_void};
use super::simple_stream::bstream::Bstream;

#[link(name = "client", kind = "static")]
extern {
    fn register_writer_tx(tx: *mut c_void);
    fn register_stop_tx(tx: *mut c_void);
}

#[no_mangle]
pub extern "C" fn start(address: *const c_char,
    data_handler: extern fn(*const c_char, c_int),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    println!("Rust - start()");

    let mut r_address;
    unsafe {
        r_address = CStr::from_ptr(address);
    }
    let s_address = r_address.to_bytes();
    let host_address = match str::from_utf8(s_address) {
        Ok(safe_str) => safe_str,
        Err(_) => {
            println!("Invalid host address");
            return -1 as c_int;
        }
    };

    println!("Rust - address: {}", host_address);

    // Create and register a way to kill this client
    let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    let kill_tx = k_tx.clone();
    let mut k_tx_ptr = Box::new(k_tx);

    println!("calling register_stop_tx");

    let mut k_tx_ptr_clone = k_tx_ptr.clone();
    unsafe {
        let mut k_tx_as_void_ptr: *mut c_void = mem::transmute(k_tx_ptr_clone);
        register_stop_tx(&mut *k_tx_as_void_ptr);
    }

    // Writer thread's channel
    let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    let mut w_tx_ptr = Box::new(w_tx);
    unsafe {
        register_writer_tx(&mut *w_tx_ptr);
    }

    println!("Attempting connect to: {}", host_address);

    let result = TcpStream::connect(host_address);
    if result.is_err() {
        println!("Error connecting to {} - {}", host_address, result.unwrap_err());
        return -1 as c_int;
    }
    println!("Connected");
    on_connect_handler();

    let stream = result.unwrap();
    let client = Bstream::new(stream);

    let r_client = client.clone();
    let r_kill_tx = kill_tx.clone();

    let w_client = client.clone();
    let w_kill_tx = kill_tx.clone();

    // Start the reader thread
    thread::Builder::new()
        .name("ReaderThread".to_string())
        .spawn(move||{
            reader_thread(r_client, handler, r_kill_tx)
        }).unwrap();

    // Start the writer thread
    thread::Builder::new()
        .name("WriterThread".to_string())
        .spawn(move||{
            writer_thread(w_rx, w_client, w_kill_tx)
        }).unwrap();

    // Wait for the kill signal
    match kill_rx.recv() {
        Ok(_) => { }
        Err(e) => {
            println!("Error on kill channel: {}", e);
            return -1 as c_int;
        }
    };
    on_disconnect_handler();

    // Exit out in standard C fashion
    0 as c_int
}

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn send_to_writer(w_tx: *mut Sender<Vec<u8>>,
                                 buffer: *const c_char,
                                 count: c_int,
                                 k_tx: *mut Sender<()>) -> c_int {
    if count < 1 {
        println!("Error - count must be greater than zero");
        return -1 as c_int;
    }

    let num_elts = count as usize;
    let mut n_buffer = Vec::<u8>::with_capacity(num_elts);
    for x in 0..num_elts as isize {
        unsafe {
            n_buffer.push(ptr::read(buffer.offset(x)) as u8);
        }
    }

    unsafe {
        match (*w_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                println!("Error sending buffer: {}", e);
                let _ = (*k_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream,
                 event_handler: extern fn(*const c_char, c_int),
                 kill_tx: Sender<()>) {

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        event_handler(c_buffer.as_ptr(), buffer.len() as c_int);
                    }).unwrap();
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Reader thread finished");
    let _ = kill_tx.send(());
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream, kill_tx: Sender<()>) {
    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        println!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Writer thread finished");
    let _ = kill_tx.send(());
}
<commit_msg>Debugging<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str, ptr, mem};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char, c_void};
use super::simple_stream::bstream::Bstream;

#[link(name = "client", kind = "static")]
extern {
    fn register_writer_tx(tx: *mut Sender<Vec<u8>>);
    fn register_stop_tx(tx: *mut Sender<()>);
}

#[no_mangle]
pub extern "C" fn start(address: *const c_char,
    data_handler: extern fn(*const c_char, c_int),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    println!("Rust - start()");

    let mut r_address;
    unsafe {
        r_address = CStr::from_ptr(address);
    }
    let s_address = r_address.to_bytes();
    let host_address = match str::from_utf8(s_address) {
        Ok(safe_str) => safe_str,
        Err(_) => {
            println!("Invalid host address");
            return -1 as c_int;
        }
    };

    println!("Rust - address: {}", host_address);

    // Create and register a way to kill this client
    let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    let kill_tx = k_tx.clone();
    let mut k_tx_ptr = Box::new(k_tx);

    println!("calling register_stop_tx");
    unsafe {
        register_stop_tx(&mut *k_tx_ptr);
    }

    // Writer thread's channel
    let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    let mut w_tx_ptr = Box::new(w_tx);
    unsafe {
        register_writer_tx(&mut *w_tx_ptr);
    }

    println!("Attempting connect to: {}", host_address);

    let result = TcpStream::connect(host_address);
    if result.is_err() {
        println!("Error connecting to {} - {}", host_address, result.unwrap_err());
        return -1 as c_int;
    }
    println!("Connected");
    on_connect_handler();

    let stream = result.unwrap();
    let client = Bstream::new(stream);

    let r_client = client.clone();
    let r_kill_tx = kill_tx.clone();

    let w_client = client.clone();
    let w_kill_tx = kill_tx.clone();

    // Start the reader thread
    thread::Builder::new()
        .name("ReaderThread".to_string())
        .spawn(move||{
            reader_thread(r_client, data_handler, r_kill_tx)
        }).unwrap();

    // Start the writer thread
    thread::Builder::new()
        .name("WriterThread".to_string())
        .spawn(move||{
            writer_thread(w_rx, w_client, w_kill_tx)
        }).unwrap();

    // Wait for the kill signal
    match kill_rx.recv() {
        Ok(_) => { }
        Err(e) => {
            println!("Error on kill channel: {}", e);
            return -1 as c_int;
        }
    };
    on_disconnect_handler();

    // Exit out in standard C fashion
    0 as c_int
}

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn send_to_writer(w_tx: *mut Sender<Vec<u8>>,
                                 buffer: *const c_char,
                                 count: c_int,
                                 k_tx: *mut Sender<()>) -> c_int {
    if count < 1 {
        println!("Error - count must be greater than zero");
        return -1 as c_int;
    }

    let num_elts = count as usize;
    let mut n_buffer = Vec::<u8>::with_capacity(num_elts);
    for x in 0..num_elts as isize {
        unsafe {
            n_buffer.push(ptr::read(buffer.offset(x)) as u8);
        }
    }

    unsafe {
        match (*w_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                println!("Error sending buffer: {}", e);
                let _ = (*k_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream,
                 event_handler: extern fn(*const c_char, c_int),
                 kill_tx: Sender<()>) {

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        event_handler(c_buffer.as_ptr(), buffer.len() as c_int);
                    }).unwrap();
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Reader thread finished");
    let _ = kill_tx.send(());
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream, kill_tx: Sender<()>) {
    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        println!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Writer thread finished");
    let _ = kill_tx.send(());
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str, ptr};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char};
use super::simple_stream::bstream::Bstream;

extern "C" {
    fn register_writer_tx(tx: *mut Sender<Vec<u8>>);
    fn register_stop_tx(tx: *mut Sender<()>);
}

/// Connects to the provided address, (eg "123.123.123.123:3000") and registers
/// the on data received handler
pub extern "C" fn connect(address: *const c_char,
    handler: extern fn(*const c_char, c_int),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    let mut r_address;
    unsafe {
        r_address = CStr::from_ptr(address);
    }
    let s_address = r_address.to_bytes();
    let host_address = match str::from_utf8(s_address) {
        Ok(safe_str) => safe_str,
        Err(_) => {
            println!("Invalid host address");
            return -1 as c_int;
        }
    };

    // Create and register a way to kill this client
    let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    let kill_tx = k_tx.clone();
    let mut k_tx_ptr = Box::new(k_tx);
    unsafe {
        register_stop_tx(&mut *k_tx_ptr);
    }

    // Writer thread's channel
    let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    let mut w_tx_ptr = Box::new(w_tx);
    unsafe {
        register_writer_tx(&mut *w_tx_ptr);
    }

    let result = TcpStream::connect(host_address);
    if result.is_err() {
        println!("Error connecting to {} - {}", host_address, result.unwrap_err());
        return -1 as c_int;
    }
    println!("Connected");
    on_connect_handler();

    let stream = result.unwrap();
    let client = Bstream::new(stream);

    let r_client = client.clone();
    let r_kill_tx = kill_tx.clone();

    let w_client = client.clone();
    let w_kill_tx = kill_tx.clone();

    // Start the reader thread
    thread::Builder::new()
        .name("ReaderThread".to_string())
        .spawn(move||{
            reader_thread(r_client, handler, r_kill_tx)
        }).unwrap();

    // Start the writer thread
    thread::Builder::new()
        .name("WriterThread".to_string())
        .spawn(move||{
            writer_thread(w_rx, w_client, w_kill_tx)
        }).unwrap();

    // Wait for the kill signal
    match kill_rx.recv() {
        Ok(_) => { }
        Err(e) => {
            println!("Error on kill channel: {}", e);
            return -1 as c_int;
        }
    };
    on_disconnect_handler();

    // Exit out in standard C fashion
    0 as c_int
}

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
pub extern "C" fn send_to_writer(w_tx: *mut Sender<Vec<u8>>,
                                 buffer: *const c_char,
                                 count: c_int,
                                 k_tx: *mut Sender<()>) -> c_int {
    if count < 1 {
        println!("Error - count must be greater than zero");
        return -1 as c_int;
    }

    let num_elts = count as usize;
    let mut n_buffer = Vec::<u8>::with_capacity(num_elts);
    for x in 0..num_elts as isize {
        unsafe {
            n_buffer.push(ptr::read(buffer.offset(x)) as u8);
        }
    }

    unsafe {
        match (*w_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                println!("Error sending buffer: {}", e);
                let _ = (*k_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream,
                 event_handler: extern fn(*const c_char, c_int),
                 kill_tx: Sender<()>) {

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        event_handler(c_buffer.as_ptr(), buffer.len() as c_int);
                    }).unwrap();
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Reader thread finished");
    let _ = kill_tx.send(());
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream, kill_tx: Sender<()>) {
    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        println!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Writer thread finished");
    let _ = kill_tx.send(());
}
<commit_msg>Added no_mangle to extern fns<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str, ptr};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char};
use super::simple_stream::bstream::Bstream;

extern "C" {
    fn register_writer_tx(tx: *mut Sender<Vec<u8>>);
    fn register_stop_tx(tx: *mut Sender<()>);
}

/// Connects to the provided address, (eg "123.123.123.123:3000") and registers
/// the on data received handler
#[no_mangle]
pub extern "C" fn connect(address: *const c_char,
    handler: extern fn(*const c_char, c_int),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    let mut r_address;
    unsafe {
        r_address = CStr::from_ptr(address);
    }
    let s_address = r_address.to_bytes();
    let host_address = match str::from_utf8(s_address) {
        Ok(safe_str) => safe_str,
        Err(_) => {
            println!("Invalid host address");
            return -1 as c_int;
        }
    };

    // Create and register a way to kill this client
    let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    let kill_tx = k_tx.clone();
    let mut k_tx_ptr = Box::new(k_tx);
    unsafe {
        register_stop_tx(&mut *k_tx_ptr);
    }

    // Writer thread's channel
    let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    let mut w_tx_ptr = Box::new(w_tx);
    unsafe {
        register_writer_tx(&mut *w_tx_ptr);
    }

    let result = TcpStream::connect(host_address);
    if result.is_err() {
        println!("Error connecting to {} - {}", host_address, result.unwrap_err());
        return -1 as c_int;
    }
    println!("Connected");
    on_connect_handler();

    let stream = result.unwrap();
    let client = Bstream::new(stream);

    let r_client = client.clone();
    let r_kill_tx = kill_tx.clone();

    let w_client = client.clone();
    let w_kill_tx = kill_tx.clone();

    // Start the reader thread
    thread::Builder::new()
        .name("ReaderThread".to_string())
        .spawn(move||{
            reader_thread(r_client, handler, r_kill_tx)
        }).unwrap();

    // Start the writer thread
    thread::Builder::new()
        .name("WriterThread".to_string())
        .spawn(move||{
            writer_thread(w_rx, w_client, w_kill_tx)
        }).unwrap();

    // Wait for the kill signal
    match kill_rx.recv() {
        Ok(_) => { }
        Err(e) => {
            println!("Error on kill channel: {}", e);
            return -1 as c_int;
        }
    };
    on_disconnect_handler();

    // Exit out in standard C fashion
    0 as c_int
}

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn send_to_writer(w_tx: *mut Sender<Vec<u8>>,
                                 buffer: *const c_char,
                                 count: c_int,
                                 k_tx: *mut Sender<()>) -> c_int {
    if count < 1 {
        println!("Error - count must be greater than zero");
        return -1 as c_int;
    }

    let num_elts = count as usize;
    let mut n_buffer = Vec::<u8>::with_capacity(num_elts);
    for x in 0..num_elts as isize {
        unsafe {
            n_buffer.push(ptr::read(buffer.offset(x)) as u8);
        }
    }

    unsafe {
        match (*w_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                println!("Error sending buffer: {}", e);
                let _ = (*k_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream,
                 event_handler: extern fn(*const c_char, c_int),
                 kill_tx: Sender<()>) {

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        event_handler(c_buffer.as_ptr(), buffer.len() as c_int);
                    }).unwrap();
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Reader thread finished");
    let _ = kill_tx.send(());
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream, kill_tx: Sender<()>) {
    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        println!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Writer thread finished");
    let _ = kill_tx.send(());
}
<|endoftext|>


<commit_before>use libc;
#[cfg(not(target_env = "musl"))]
use {Errno, Result};
#[cfg(not(target_env = "musl"))]
use std::mem;

#[derive(Clone, Copy)]
pub struct UContext {
    context: libc::ucontext_t,
}

impl UContext {
    #[cfg(not(target_env = "musl"))]
    pub fn get() -> Result<UContext> {
        let mut context: libc::ucontext_t = unsafe { mem::uninitialized() };
        let res = unsafe {
            libc::getcontext(&mut context as *mut libc::ucontext_t)
        };
        Errno::result(res).map(|_| UContext { context: context })
    }

    #[cfg(not(target_env = "musl"))]
    pub fn set(&self) -> Result<()> {
        let res = unsafe {
            libc::setcontext(&self.context as *const libc::ucontext_t)
        };
        Errno::result(res).map(drop)
    }
}
<commit_msg>Auto merge of #370 - fiveop:context, r=posborne<commit_after>use libc;
#[cfg(not(target_env = "musl"))]
use {Errno, Result};
#[cfg(not(target_env = "musl"))]
use std::mem;
use sys::signal::SigSet;

#[derive(Clone, Copy)]
pub struct UContext {
    context: libc::ucontext_t,
}

impl UContext {
    #[cfg(not(target_env = "musl"))]
    pub fn get() -> Result<UContext> {
        let mut context: libc::ucontext_t = unsafe { mem::uninitialized() };
        let res = unsafe {
            libc::getcontext(&mut context as *mut libc::ucontext_t)
        };
        Errno::result(res).map(|_| UContext { context: context })
    }

    #[cfg(not(target_env = "musl"))]
    pub fn set(&self) -> Result<()> {
        let res = unsafe {
            libc::setcontext(&self.context as *const libc::ucontext_t)
        };
        Errno::result(res).map(drop)
    }

    pub fn sigmask_mut(&mut self) -> &mut SigSet {
        unsafe { mem::transmute(&mut self.context.uc_sigmask) }
    }

    pub fn sigmask(&self) -> &SigSet {
        unsafe { mem::transmute(&self.context.uc_sigmask) }
    }
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types, non_snake_case)]
extern crate ncurses;

use ncurses::ll;

use ncurses::ll::{chtype, attr_t, WINDOW};

use ncurses::NCURSES_ATTR_SHIFT;

pub fn NCURSES_BITS(mask: u32, shift: u32) -> u32 {
    mask << (shift + NCURSES_ATTR_SHIFT) as usize
}

pub const A_NORMAL: attr_t = 0u32 as attr_t;
pub const A_ATTRIBUTES: attr_t = (!0u32 << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_CHARTEXT: attr_t = (1u32 << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_COLOR: attr_t = ((((1u32) << 8) - 1u32) << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;

// pub fn A_STANDOUT() -> attr_t
// { NCURSES_BITS(1u32, 8u32) as attr_t }
//
// pub fn A_UNDERLINE() -> attr_t
// { NCURSES_BITS(1u32, 9u32) as attr_t }
//
// pub fn A_REVERSE() -> attr_t
// { NCURSES_BITS(1u32, 10u32) as attr_t }
//
// pub fn A_BLINK() -> attr_t
// { NCURSES_BITS(1u32, 11u32) as attr_t }
//
// pub fn A_DIM() -> attr_t
// { NCURSES_BITS(1u32, 12u32) as attr_t }
//

pub const A_BOLD: attr_t = (1u32 << (13u32 + NCURSES_ATTR_SHIFT)) as attr_t;

pub fn COLOR_PAIR(n: chtype) -> attr_t {
    NCURSES_BITS(n as u32, 0u32) as attr_t
}

pub fn _attrset(w: WINDOW, attributes: chtype) -> i32 {
    unsafe { wattrset(w, attributes as i32) }
}
<commit_msg>Fixed linux compilation<commit_after>#![allow(non_camel_case_types, non_snake_case)]
extern crate ncurses;

use ncurses::ll::{chtype, attr_t, WINDOW, wattrset};

use ncurses::NCURSES_ATTR_SHIFT;

pub fn NCURSES_BITS(mask: u32, shift: u32) -> u32 {
    mask << (shift + NCURSES_ATTR_SHIFT) as usize
}

pub const A_NORMAL: attr_t = 0u32 as attr_t;
pub const A_ATTRIBUTES: attr_t = (!0u32 << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_CHARTEXT: attr_t = (1u32 << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_COLOR: attr_t = ((((1u32) << 8) - 1u32) << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;

// pub fn A_STANDOUT() -> attr_t
// { NCURSES_BITS(1u32, 8u32) as attr_t }
//
// pub fn A_UNDERLINE() -> attr_t
// { NCURSES_BITS(1u32, 9u32) as attr_t }
//
// pub fn A_REVERSE() -> attr_t
// { NCURSES_BITS(1u32, 10u32) as attr_t }
//
// pub fn A_BLINK() -> attr_t
// { NCURSES_BITS(1u32, 11u32) as attr_t }
//
// pub fn A_DIM() -> attr_t
// { NCURSES_BITS(1u32, 12u32) as attr_t }
//

pub const A_BOLD: attr_t = (1u32 << (13u32 + NCURSES_ATTR_SHIFT)) as attr_t;

pub fn COLOR_PAIR(n: chtype) -> attr_t {
    NCURSES_BITS(n as u32, 0u32) as attr_t
}

pub fn _attrset(w: WINDOW, attributes: chtype) -> i32 {
    unsafe { wattrset(w, attributes as i32) }
}
<|endoftext|>


<commit_before>use std::sync::RwLock;
use std::path::{Path, PathBuf};
use std::fs;

use slog::Logger;
use kite_rocksdb::RocksDBIndexStore;

use index::Index;
use index::registry::IndexRegistry;

pub struct System {
    pub log: Logger,
    data_dir: PathBuf,
    pub indices: RwLock<IndexRegistry>,
}

impl System {
    pub fn new(log: Logger, data_dir: PathBuf) -> System {
        System {
            log: log,
            data_dir: data_dir,
            indices: RwLock::new(IndexRegistry::new()),
        }
    }

    pub fn get_indices_dir(&self) -> PathBuf {
        let mut dir = self.data_dir.clone();
        dir.push("indices");
        dir
    }

    fn load_index(&self, name: String, path: &Path) -> Result<Index, String> {
        let store = try!(RocksDBIndexStore::open(path));

        Ok(Index::new(name, store))
    }

    pub fn load_indices(&self) {
        let indices_dir = self.get_indices_dir();
        match fs::read_dir(indices_dir.clone()) {
            Ok(files) => {
                for file in files {
                    let path = file.unwrap().path();
                    let index_name: String = path.file_name().unwrap().to_str().unwrap().to_owned();

                    match self.load_index(index_name.clone().to_owned(), path.as_path()) {
                        Ok(index) => {
                            let mut indices_w = self.indices.write().unwrap();
                            let index_ref = indices_w.insert(index);
                            indices_w.names.insert_canonical(index_name.clone(), index_ref).unwrap();

                             self.log.info("[sys] loaded index", b!("index" => index_name));
                        }
                        Err(e) => {
                            self.log.error("[sys] failed to open index", b!(
                                "index" => index_name,
                                "error" => e
                            ));
                        }
                    }
                }
            }
            Err(error) => {
                self.log.error("[sys] cannot open indices directory", b!(
                    "dir" => indices_dir.to_str().unwrap(),
                    "error" => format!("{}", error)
                ));
            }
        }
    }
}
<commit_msg>Ignore files in indices dir<commit_after>use std::sync::RwLock;
use std::path::{Path, PathBuf};
use std::fs;

use slog::Logger;
use kite_rocksdb::RocksDBIndexStore;

use index::Index;
use index::registry::IndexRegistry;

pub struct System {
    pub log: Logger,
    data_dir: PathBuf,
    pub indices: RwLock<IndexRegistry>,
}

impl System {
    pub fn new(log: Logger, data_dir: PathBuf) -> System {
        System {
            log: log,
            data_dir: data_dir,
            indices: RwLock::new(IndexRegistry::new()),
        }
    }

    pub fn get_indices_dir(&self) -> PathBuf {
        let mut dir = self.data_dir.clone();
        dir.push("indices");
        dir
    }

    fn load_index(&self, name: String, path: &Path) -> Result<Index, String> {
        let store = try!(RocksDBIndexStore::open(path));

        Ok(Index::new(name, store))
    }

    pub fn load_indices(&self) {
        let indices_dir = self.get_indices_dir();
        match fs::read_dir(indices_dir.clone()) {
            Ok(files) => {
                for file in files {
                    let path = file.unwrap().path();
                    if path.is_dir() {
                        let index_name: String = path.file_name().unwrap().to_str().unwrap().to_owned();

                        match self.load_index(index_name.clone().to_owned(), path.as_path()) {
                            Ok(index) => {
                                let mut indices_w = self.indices.write().unwrap();
                                let index_ref = indices_w.insert(index);
                                indices_w.names.insert_canonical(index_name.clone(), index_ref).unwrap();

                                self.log.info("[sys] loaded index", b!("index" => index_name));
                            }
                            Err(e) => {
                                self.log.error("[sys] failed to open index", b!(
                                    "index" => index_name,
                                    "error" => e
                                ));
                            }
                        }
                    }
                }
            }
            Err(error) => {
                self.log.error("[sys] cannot open indices directory", b!(
                    "dir" => indices_dir.to_str().unwrap(),
                    "error" => format!("{}", error)
                ));
            }
        }
    }
}
<|endoftext|>


<commit_before>/* Copyright 2015 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

use std::ptr;
use iup_sys::*;
use super::{Control, UnwrapHandle};
use super::handle_rc::HandleRc;
use super::attributes::{
    OrientationAttribute,
    set_str_attribute,
    get_str_attribute_slice,
};

pub trait Container : Control {
    fn append(&self, new_child: &Control) -> Result<(), ()> {
        unsafe {
            if IupAppend(self.handle(), new_child.handle()) == ptr::null_mut() {
                Err(())
            } else {
                Ok(())
            }
        }
    }

    fn insert(&self, ref_child: Option<&Control>, new_child: &Control) -> Result<(), ()> {
        unsafe {
            let ref_child = ref_child.map(|c| c.handle()).unwrap_or(ptr::null_mut());
            if IupInsert(self.handle(), ref_child, new_child.handle()) == ptr::null_mut() {
                Err(())
            } else {
                Ok(())
            }
        }
    }

    /// Returns the number of children of the specified control.
    ///
    /// Warning: Since children are stored as a linked list, getting the count is O(n).
    fn child_count(&self) -> usize {
        unsafe {
            IupGetChildCount(self.handle()) as usize
        }
    }
}

pub trait NonDialogContainer : Container {
    fn refresh_children(&self) {
        unsafe {
            IupRefreshChildren(self.handle());
        }
    }
}

// Be sure that the Vec is not dropped before the *mut *mut Ihandle is used.
fn wrapper_to_handles(controls: Option<&[&::Control]>)
-> (Option<Vec<*mut Ihandle>>, *mut *mut Ihandle)
{
    let mut controls: Option<Vec<_>> = controls.map(|slice| {
        let mut v: Vec<*mut Ihandle> = slice.iter().map(|c| c.handle()).collect();
        v.push(ptr::null_mut()); // array has to be null terminated
        v
    });
    let p = controls.as_mut().map(|v| v.as_mut_ptr()).unwrap_or(ptr::null_mut());
    (controls, p)
}

#[derive(Clone)]
pub struct Fill(HandleRc);

impl Fill {
    pub fn new() -> Fill {
        unsafe {
            ::iup_open();
            let handle = IupFill();
            Fill(HandleRc::new(handle))
        }
    }
}

impl_control_traits!(Fill);

#[macro_export]
macro_rules! fill { // This is a macro for consistency, even though it could just be a function.
    () => { Fill::new() };
}

#[derive(Clone)]
pub struct Hbox(HandleRc);

impl Hbox {
    pub fn new(children: Option<&[&::Control]>) -> Hbox {
        unsafe {
            ::iup_open();
            let (_children, children_handles) = wrapper_to_handles(children);
            Hbox::from_handles(children_handles)
        }
    }

    pub unsafe fn from_handles(children: *mut *mut Ihandle) -> Hbox {
        let handle = IupHboxv(children);
        Hbox(HandleRc::new(handle))
    }
}

impl_control_traits!(Hbox);

impl Container for Hbox {}

#[macro_export]
macro_rules! hbox {
    ($($c:expr),*) => {
        {
            use std::ptr;
            let mut handles = Vec::new();
            $(
                // The control has to be stored in a binding to ensure it isn't dropped before
                // it is added as a child of the container. (Otherwise, the control is destroyed.)
                let c = $c;
                handles.push(c.handle());
            )*
            handles.push(ptr::null_mut());
            unsafe { Hbox::from_handles(handles.as_mut_ptr()) }
        }
    };
    ($($c:expr,)*) => { hbox!($($c),*) };
}

#[derive(Clone)]
pub struct Vbox(HandleRc);

impl Vbox {
    pub fn new(children: Option<&[&::Control]>) -> Vbox {
        unsafe {
            ::iup_open();
            let (_children, children_handles) = wrapper_to_handles(children);
            Vbox::from_handles(children_handles)
        }
    }

    pub unsafe fn from_handles(children: *mut *mut Ihandle) -> Vbox {
        let handle = IupVboxv(children);
        Vbox(HandleRc::new(handle))
    }
}

impl_control_traits!(Vbox);

impl Container for Vbox {}

#[macro_export]
macro_rules! vbox {
    ($($c:expr),*) => {
        {
            use std::ptr;
            let mut handles = Vec::new();
            $(
                // The control has to be stored in a binding to ensure it isn't dropped before
                // it is added as a child of the container. (Otherwise, the control is destroyed.)
                let c = $c;
                handles.push(c.handle());
            )*
            handles.push(ptr::null_mut());
            unsafe { Vbox::from_handles(handles.as_mut_ptr()) }
        }
    };
    ($($c:expr,)*) => { vbox!($($c),*) };
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum NumDiv {
    Fixed(u32),
    Auto,
}

#[derive(Clone)]
pub struct GridBox(HandleRc);

impl GridBox {
    pub fn new(children: Option<&[&::Control]>) -> GridBox {
        unsafe {
            ::iup_open();
            let (_children, children_handles) = wrapper_to_handles(children);
            GridBox::from_handles(children_handles)
        }
    }

    pub unsafe fn from_handles(children: *mut *mut Ihandle) -> GridBox {
        let handle = IupGridBoxv(children);
        GridBox(HandleRc::new(handle))
    }

    pub fn alignment_lin(&self, line: u32) -> ::VAlignment {
        unsafe {
            let attr = format!("ALIGNMENTLIN{}", line);
            ::VAlignment::from_str(get_str_attribute_slice(self.handle(), &attr).as_bytes())
        }
    }

    pub fn set_alignment_lin(&self, line: u32, alignment: ::VAlignment) -> &Self {
        set_str_attribute(self.handle(), &format!("ALIGNMENTLIN{}", line), alignment.to_str());
        self
    }

    pub fn alignment_lin_all(&self) -> ::VAlignment {
        unsafe {
            let s = get_str_attribute_slice(self.handle(), "ALIGNMENTLIN");
            ::VAlignment::from_str(s.as_bytes())
        }
    }

    pub fn set_alignment_lin_all(&self, alignment: ::VAlignment) -> &Self {
        set_str_attribute(self.handle(), "ALIGNMENTLIN", alignment.to_str());
        self
    }

    pub fn alignment_col(&self, column: u32) -> ::HAlignment {
        unsafe {
            let attr = format!("ALIGNMENTCOL{}", column);
            ::HAlignment::from_str(get_str_attribute_slice(self.handle(), &attr).as_bytes())
        }
    }

    pub fn set_alignment_col(&self, column: u32, alignment: ::HAlignment) -> &Self {
        set_str_attribute(self.handle(), &format!("ALIGNMENTCOL{}", column), alignment.to_str());
        self
    }

    pub fn alignment_col_all(&self) -> ::HAlignment {
        unsafe {
            let s = get_str_attribute_slice(self.handle(), "ALIGNMENTCOL");
            ::HAlignment::from_str(s.as_bytes())
        }
    }

    pub fn set_alignment_col_all(&self, alignment: ::HAlignment) -> &Self {
        set_str_attribute(self.handle(), "ALIGNMENTCOL", alignment.to_str());
        self
    }

    pub fn num_div(&self) -> NumDiv {
        unsafe {
            let s = get_str_attribute_slice(self.handle(), "NUMDIV");
            if s.as_bytes() == b"-1" {
                NumDiv::Auto
            } else {
                NumDiv::Fixed(s.parse().expect("could not convert NUMDIV to an integer"))
            }
        }
    }

    pub fn set_num_div(&self, num: NumDiv) -> &Self {
        match num {
            NumDiv::Fixed(i) => set_str_attribute(self.handle(), "NUMDIV", &i.to_string()),
            NumDiv::Auto => set_str_attribute(self.handle(), "NUMDIV", "AUTO"),
        };
        self
    }

    pub fn num_lin(&self) -> u32 {
        unsafe {
            let s = get_str_attribute_slice(self.handle(), "NUMLIN");
            s.parse().expect("could not convert NUMLIN to an integer")
        }
    }

    pub fn num_col(&self) -> u32 {
        unsafe {
            let s = get_str_attribute_slice(self.handle(), "NUMCOL");
            s.parse().expect("could not convert NUMLIN to an integer")
        }
    }
}

impl_control_traits!(GridBox);

impl Container for GridBox {}

impl OrientationAttribute for GridBox {}

#[macro_export]
macro_rules! grid_box {
    ($($c:expr),*) => {
        {
            use std::ptr;
            let mut handles = Vec::new();
            $(
                // The control has to be stored in a binding to ensure it isn't dropped before
                // it is added as a child of the container. (Otherwise, the control is destroyed.)
                let c = $c;
                handles.push(c.handle());
            )*
            handles.push(ptr::null_mut());
            unsafe { GridBox::from_handles(handles.as_mut_ptr()) }
        }
    };
    ($($c:expr,)*) => { grid_box!($($c),*) };
}
<commit_msg>Add fit_to_children methods for a column, a line, and all of them<commit_after>/* Copyright 2015 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

use std::ptr;
use iup_sys::*;
use super::{Control, UnwrapHandle};
use super::handle_rc::HandleRc;
use super::attributes::{
    OrientationAttribute,
    set_str_attribute,
    get_str_attribute_slice,
};

pub trait Container : Control {
    fn append(&self, new_child: &Control) -> Result<(), ()> {
        unsafe {
            if IupAppend(self.handle(), new_child.handle()) == ptr::null_mut() {
                Err(())
            } else {
                Ok(())
            }
        }
    }

    fn insert(&self, ref_child: Option<&Control>, new_child: &Control) -> Result<(), ()> {
        unsafe {
            let ref_child = ref_child.map(|c| c.handle()).unwrap_or(ptr::null_mut());
            if IupInsert(self.handle(), ref_child, new_child.handle()) == ptr::null_mut() {
                Err(())
            } else {
                Ok(())
            }
        }
    }

    /// Returns the number of children of the specified control.
    ///
    /// Warning: Since children are stored as a linked list, getting the count is O(n).
    fn child_count(&self) -> usize {
        unsafe {
            IupGetChildCount(self.handle()) as usize
        }
    }
}

pub trait NonDialogContainer : Container {
    fn refresh_children(&self) {
        unsafe {
            IupRefreshChildren(self.handle());
        }
    }
}

// Be sure that the Vec is not dropped before the *mut *mut Ihandle is used.
fn wrapper_to_handles(controls: Option<&[&::Control]>)
-> (Option<Vec<*mut Ihandle>>, *mut *mut Ihandle)
{
    let mut controls: Option<Vec<_>> = controls.map(|slice| {
        let mut v: Vec<*mut Ihandle> = slice.iter().map(|c| c.handle()).collect();
        v.push(ptr::null_mut()); // array has to be null terminated
        v
    });
    let p = controls.as_mut().map(|v| v.as_mut_ptr()).unwrap_or(ptr::null_mut());
    (controls, p)
}

#[derive(Clone)]
pub struct Fill(HandleRc);

impl Fill {
    pub fn new() -> Fill {
        unsafe {
            ::iup_open();
            let handle = IupFill();
            Fill(HandleRc::new(handle))
        }
    }
}

impl_control_traits!(Fill);

#[macro_export]
macro_rules! fill { // This is a macro for consistency, even though it could just be a function.
    () => { Fill::new() };
}

#[derive(Clone)]
pub struct Hbox(HandleRc);

impl Hbox {
    pub fn new(children: Option<&[&::Control]>) -> Hbox {
        unsafe {
            ::iup_open();
            let (_children, children_handles) = wrapper_to_handles(children);
            Hbox::from_handles(children_handles)
        }
    }

    pub unsafe fn from_handles(children: *mut *mut Ihandle) -> Hbox {
        let handle = IupHboxv(children);
        Hbox(HandleRc::new(handle))
    }
}

impl_control_traits!(Hbox);

impl Container for Hbox {}

#[macro_export]
macro_rules! hbox {
    ($($c:expr),*) => {
        {
            use std::ptr;
            let mut handles = Vec::new();
            $(
                // The control has to be stored in a binding to ensure it isn't dropped before
                // it is added as a child of the container. (Otherwise, the control is destroyed.)
                let c = $c;
                handles.push(c.handle());
            )*
            handles.push(ptr::null_mut());
            unsafe { Hbox::from_handles(handles.as_mut_ptr()) }
        }
    };
    ($($c:expr,)*) => { hbox!($($c),*) };
}

#[derive(Clone)]
pub struct Vbox(HandleRc);

impl Vbox {
    pub fn new(children: Option<&[&::Control]>) -> Vbox {
        unsafe {
            ::iup_open();
            let (_children, children_handles) = wrapper_to_handles(children);
            Vbox::from_handles(children_handles)
        }
    }

    pub unsafe fn from_handles(children: *mut *mut Ihandle) -> Vbox {
        let handle = IupVboxv(children);
        Vbox(HandleRc::new(handle))
    }
}

impl_control_traits!(Vbox);

impl Container for Vbox {}

#[macro_export]
macro_rules! vbox {
    ($($c:expr),*) => {
        {
            use std::ptr;
            let mut handles = Vec::new();
            $(
                // The control has to be stored in a binding to ensure it isn't dropped before
                // it is added as a child of the container. (Otherwise, the control is destroyed.)
                let c = $c;
                handles.push(c.handle());
            )*
            handles.push(ptr::null_mut());
            unsafe { Vbox::from_handles(handles.as_mut_ptr()) }
        }
    };
    ($($c:expr,)*) => { vbox!($($c),*) };
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum NumDiv {
    Fixed(u32),
    Auto,
}

#[derive(Clone)]
pub struct GridBox(HandleRc);

impl GridBox {
    pub fn new(children: Option<&[&::Control]>) -> GridBox {
        unsafe {
            ::iup_open();
            let (_children, children_handles) = wrapper_to_handles(children);
            GridBox::from_handles(children_handles)
        }
    }

    pub unsafe fn from_handles(children: *mut *mut Ihandle) -> GridBox {
        let handle = IupGridBoxv(children);
        GridBox(HandleRc::new(handle))
    }

    pub fn alignment_lin(&self, line: u32) -> ::VAlignment {
        unsafe {
            let attr = format!("ALIGNMENTLIN{}", line);
            ::VAlignment::from_str(get_str_attribute_slice(self.handle(), &attr).as_bytes())
        }
    }

    pub fn set_alignment_lin(&self, line: u32, alignment: ::VAlignment) -> &Self {
        set_str_attribute(self.handle(), &format!("ALIGNMENTLIN{}", line), alignment.to_str());
        self
    }

    pub fn alignment_lin_all(&self) -> ::VAlignment {
        unsafe {
            let s = get_str_attribute_slice(self.handle(), "ALIGNMENTLIN");
            ::VAlignment::from_str(s.as_bytes())
        }
    }

    pub fn set_alignment_lin_all(&self, alignment: ::VAlignment) -> &Self {
        set_str_attribute(self.handle(), "ALIGNMENTLIN", alignment.to_str());
        self
    }

    pub fn alignment_col(&self, column: u32) -> ::HAlignment {
        unsafe {
            let attr = format!("ALIGNMENTCOL{}", column);
            ::HAlignment::from_str(get_str_attribute_slice(self.handle(), &attr).as_bytes())
        }
    }

    pub fn set_alignment_col(&self, column: u32, alignment: ::HAlignment) -> &Self {
        set_str_attribute(self.handle(), &format!("ALIGNMENTCOL{}", column), alignment.to_str());
        self
    }

    pub fn alignment_col_all(&self) -> ::HAlignment {
        unsafe {
            let s = get_str_attribute_slice(self.handle(), "ALIGNMENTCOL");
            ::HAlignment::from_str(s.as_bytes())
        }
    }

    pub fn set_alignment_col_all(&self, alignment: ::HAlignment) -> &Self {
        set_str_attribute(self.handle(), "ALIGNMENTCOL", alignment.to_str());
        self
    }

    pub fn num_div(&self) -> NumDiv {
        unsafe {
            let s = get_str_attribute_slice(self.handle(), "NUMDIV");
            if s.as_bytes() == b"-1" {
                NumDiv::Auto
            } else {
                NumDiv::Fixed(s.parse().expect("could not convert NUMDIV to an integer"))
            }
        }
    }

    pub fn set_num_div(&self, num: NumDiv) -> &Self {
        match num {
            NumDiv::Fixed(i) => set_str_attribute(self.handle(), "NUMDIV", &i.to_string()),
            NumDiv::Auto => set_str_attribute(self.handle(), "NUMDIV", "AUTO"),
        };
        self
    }

    pub fn num_lin(&self) -> u32 {
        unsafe {
            let s = get_str_attribute_slice(self.handle(), "NUMLIN");
            s.parse().expect("could not convert NUMLIN to an integer")
        }
    }

    pub fn num_col(&self) -> u32 {
        unsafe {
            let s = get_str_attribute_slice(self.handle(), "NUMCOL");
            s.parse().expect("could not convert NUMLIN to an integer")
        }
    }

    pub fn fit_col_to_children(&self, column: u32) -> &Self {
        set_str_attribute(self.handle(), "FITTOCHILDREN\0", &format!("C{}\0", column));
        self
    }

    pub fn fit_lin_to_children(&self, line: u32) -> &Self {
        set_str_attribute(self.handle(), "FITTOCHILDREN\0", &format!("L{}\0", line));
        self
    }

    pub fn fit_all_to_children(&self) -> &Self {
        for line in 0..self.num_lin() {
            self.fit_lin_to_children(line);
        }
        for column in 0..self.num_col() {
            self.fit_col_to_children(column);
        }
        self
    }
}

impl_control_traits!(GridBox);

impl Container for GridBox {}

impl OrientationAttribute for GridBox {}

#[macro_export]
macro_rules! grid_box {
    ($($c:expr),*) => {
        {
            use std::ptr;
            let mut handles = Vec::new();
            $(
                // The control has to be stored in a binding to ensure it isn't dropped before
                // it is added as a child of the container. (Otherwise, the control is destroyed.)
                let c = $c;
                handles.push(c.handle());
            )*
            handles.push(ptr::null_mut());
            unsafe { GridBox::from_handles(handles.as_mut_ptr()) }
        }
    };
    ($($c:expr,)*) => { grid_box!($($c),*) };
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: (Apache-2.0 OR MIT)
// Derived from uBPF <https://github.com/iovisor/ubpf>
// Copyright 2015 Big Switch Networks, Inc
//      (uBPF: safety checks, originally in C)
// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
//      (Translation to Rust)

// This “verifier” performs simple checks when the eBPF program is loaded into the VM (before it is
// interpreted or JIT-compiled). It has nothing to do with the much more elaborated verifier inside
// Linux kernel. There is no verification regarding the program flow control (should be a Direct
// Acyclic Graph) or the consistency for registers usage (the verifier of the kernel assigns types
// to the registers and is much stricter).
//
// On the other hand, rbpf is not expected to run in kernel space.
//
// Improving the verifier would be nice, but this is not trivial (and Linux kernel is under GPL
// license, so we cannot copy it).
//
// Contrary to the verifier of the Linux kernel, this one does not modify the bytecode at all.

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

fn reject<S: AsRef<str>>(msg: S) -> Result<(), Error> {
    let full_msg = format!("[Verifier] Error: {}", msg.as_ref());
    Err(Error::new(ErrorKind::Other, full_msg))
}

fn check_prog_len(prog: &[u8]) -> Result<(), Error> {
    if prog.len() % ebpf::INSN_SIZE != 0 {
        reject(format!("eBPF program length must be a multiple of {:?} octets",
                       ebpf::INSN_SIZE))?;
    }
    if prog.len() > ebpf::PROG_MAX_SIZE {
        reject(format!("eBPF program length limited to {:?}, here {:?}",
                       ebpf::PROG_MAX_INSNS, prog.len() / ebpf::INSN_SIZE))?;
    }

    if prog.is_empty() {
        reject("no program set, call set_program() to load one")?;
    }
    let last_opc = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1).opc;
    if last_opc & ebpf::BPF_CLS_MASK != ebpf::BPF_JMP {
        reject("program does not end with “EXIT” instruction")?;
    }

    Ok(())
}

fn check_imm_nonzero(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), Error> {
    if insn.imm == 0 {
        reject(format!("division by 0 (insn #{insn_ptr:?})"))?;
    }

    Ok(())
}

fn check_imm_endian(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), Error> {
    match insn.imm {
        16 | 32 | 64 => Ok(()),
        _ => reject(format!("unsupported argument for LE/BE (insn #{insn_ptr:?})"))
    }
}

fn check_load_dw(prog: &[u8], insn_ptr: usize) -> Result<(), Error> {
    // We know we can reach next insn since we enforce an EXIT insn at the end of program, while
    // this function should be called only for LD_DW insn, that cannot be last in program.
    let next_insn = ebpf::get_insn(prog, insn_ptr + 1);
    if next_insn.opc != 0 {
        reject(format!("incomplete LD_DW instruction (insn #{insn_ptr:?})"))?;
    }

    Ok(())
}

fn check_jmp_offset(prog: &[u8], insn_ptr: usize) -> Result<(), Error> {
    let insn = ebpf::get_insn(prog, insn_ptr);
    if insn.off == -1 {
        reject(format!("infinite loop (insn #{insn_ptr:?})"))?;
    }

    let dst_insn_ptr = insn_ptr as isize + 1 + insn.off as isize;
    if dst_insn_ptr < 0 || dst_insn_ptr as usize >= (prog.len() / ebpf::INSN_SIZE) {
        reject(format!("jump out of code to #{dst_insn_ptr:?} (insn #{insn_ptr:?})"))?;
    }

    let dst_insn = ebpf::get_insn(prog, dst_insn_ptr as usize);
    if dst_insn.opc == 0 {
        reject(format!("jump to middle of LD_DW at #{dst_insn_ptr:?} (insn #{insn_ptr:?})"))?;
    }

    Ok(())
}

fn check_registers(insn: &ebpf::Insn, store: bool, insn_ptr: usize) -> Result<(), Error> {
    if insn.src > 10 {
        reject(format!("invalid source register (insn #{insn_ptr:?})"))?;
    }

    match (insn.dst, store) {
        (0 ..= 9, _) | (10, true) => Ok(()),
        (10, false) => reject(format!("cannot write into register r10 (insn #{insn_ptr:?})")),
        (_, _)      => reject(format!("invalid destination register (insn #{insn_ptr:?})"))
    }
}

pub fn check(prog: &[u8]) -> Result<(), Error> {
    check_prog_len(prog)?;

    let mut insn_ptr:usize = 0;
    while insn_ptr * ebpf::INSN_SIZE < prog.len() {
        let insn = ebpf::get_insn(prog, insn_ptr);
        let mut store = false;

        match insn.opc {

            // BPF_LD class
            ebpf::LD_ABS_B   => {},
            ebpf::LD_ABS_H   => {},
            ebpf::LD_ABS_W   => {},
            ebpf::LD_ABS_DW  => {},
            ebpf::LD_IND_B   => {},
            ebpf::LD_IND_H   => {},
            ebpf::LD_IND_W   => {},
            ebpf::LD_IND_DW  => {},

            ebpf::LD_DW_IMM  => {
                store = true;
                check_load_dw(prog, insn_ptr)?;
                insn_ptr += 1;
            },

            // BPF_LDX class
            ebpf::LD_B_REG   => {},
            ebpf::LD_H_REG   => {},
            ebpf::LD_W_REG   => {},
            ebpf::LD_DW_REG  => {},

            // BPF_ST class
            ebpf::ST_B_IMM   => store = true,
            ebpf::ST_H_IMM   => store = true,
            ebpf::ST_W_IMM   => store = true,
            ebpf::ST_DW_IMM  => store = true,

            // BPF_STX class
            ebpf::ST_B_REG   => store = true,
            ebpf::ST_H_REG   => store = true,
            ebpf::ST_W_REG   => store = true,
            ebpf::ST_DW_REG  => store = true,
            ebpf::ST_W_XADD  => { unimplemented!(); },
            ebpf::ST_DW_XADD => { unimplemented!(); },

            // BPF_ALU class
            ebpf::ADD32_IMM  => {},
            ebpf::ADD32_REG  => {},
            ebpf::SUB32_IMM  => {},
            ebpf::SUB32_REG  => {},
            ebpf::MUL32_IMM  => {},
            ebpf::MUL32_REG  => {},
            ebpf::DIV32_IMM  => { check_imm_nonzero(&insn, insn_ptr)?; },
            ebpf::DIV32_REG  => {},
            ebpf::OR32_IMM   => {},
            ebpf::OR32_REG   => {},
            ebpf::AND32_IMM  => {},
            ebpf::AND32_REG  => {},
            ebpf::LSH32_IMM  => {},
            ebpf::LSH32_REG  => {},
            ebpf::RSH32_IMM  => {},
            ebpf::RSH32_REG  => {},
            ebpf::NEG32      => {},
            ebpf::MOD32_IMM  => { check_imm_nonzero(&insn, insn_ptr)?; },
            ebpf::MOD32_REG  => {},
            ebpf::XOR32_IMM  => {},
            ebpf::XOR32_REG  => {},
            ebpf::MOV32_IMM  => {},
            ebpf::MOV32_REG  => {},
            ebpf::ARSH32_IMM => {},
            ebpf::ARSH32_REG => {},
            ebpf::LE         => { check_imm_endian(&insn, insn_ptr)?; },
            ebpf::BE         => { check_imm_endian(&insn, insn_ptr)?; },

            // BPF_ALU64 class
            ebpf::ADD64_IMM  => {},
            ebpf::ADD64_REG  => {},
            ebpf::SUB64_IMM  => {},
            ebpf::SUB64_REG  => {},
            ebpf::MUL64_IMM  => { check_imm_nonzero(&insn, insn_ptr)?; },
            ebpf::MUL64_REG  => {},
            ebpf::DIV64_IMM  => { check_imm_nonzero(&insn, insn_ptr)?; },
            ebpf::DIV64_REG  => {},
            ebpf::OR64_IMM   => {},
            ebpf::OR64_REG   => {},
            ebpf::AND64_IMM  => {},
            ebpf::AND64_REG  => {},
            ebpf::LSH64_IMM  => {},
            ebpf::LSH64_REG  => {},
            ebpf::RSH64_IMM  => {},
            ebpf::RSH64_REG  => {},
            ebpf::NEG64      => {},
            ebpf::MOD64_IMM  => {},
            ebpf::MOD64_REG  => {},
            ebpf::XOR64_IMM  => {},
            ebpf::XOR64_REG  => {},
            ebpf::MOV64_IMM  => {},
            ebpf::MOV64_REG  => {},
            ebpf::ARSH64_IMM => {},
            ebpf::ARSH64_REG => {},

            // BPF_JMP class
            ebpf::JA         => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JEQ_IMM    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JEQ_REG    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JGT_IMM    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JGT_REG    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JGE_IMM    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JGE_REG    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JLT_IMM    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JLT_REG    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JLE_IMM    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JLE_REG    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSET_IMM   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSET_REG   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JNE_IMM    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JNE_REG    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSGT_IMM   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSGT_REG   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSGE_IMM   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSGE_REG   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSLT_IMM   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSLT_REG   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSLE_IMM   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSLE_REG   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::CALL       => {},
            ebpf::TAIL_CALL  => { unimplemented!() },
            ebpf::EXIT       => {},

            _                => {
                reject(format!("unknown eBPF opcode {:#2x} (insn #{insn_ptr:?})", insn.opc))?;
            },
        }

        check_registers(&insn, store, insn_ptr)?;

        insn_ptr += 1;
    }

    // insn_ptr should now be equal to number of instructions.
    if insn_ptr != prog.len() / ebpf::INSN_SIZE {
        reject(format!("jumped out of code to #{insn_ptr:?}"))?;
    }

    Ok(())
}
<commit_msg>src/verifier.rs: Fix checks for divisions by zero<commit_after>// SPDX-License-Identifier: (Apache-2.0 OR MIT)
// Derived from uBPF <https://github.com/iovisor/ubpf>
// Copyright 2015 Big Switch Networks, Inc
//      (uBPF: safety checks, originally in C)
// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
//      (Translation to Rust)

// This “verifier” performs simple checks when the eBPF program is loaded into the VM (before it is
// interpreted or JIT-compiled). It has nothing to do with the much more elaborated verifier inside
// Linux kernel. There is no verification regarding the program flow control (should be a Direct
// Acyclic Graph) or the consistency for registers usage (the verifier of the kernel assigns types
// to the registers and is much stricter).
//
// On the other hand, rbpf is not expected to run in kernel space.
//
// Improving the verifier would be nice, but this is not trivial (and Linux kernel is under GPL
// license, so we cannot copy it).
//
// Contrary to the verifier of the Linux kernel, this one does not modify the bytecode at all.

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

fn reject<S: AsRef<str>>(msg: S) -> Result<(), Error> {
    let full_msg = format!("[Verifier] Error: {}", msg.as_ref());
    Err(Error::new(ErrorKind::Other, full_msg))
}

fn check_prog_len(prog: &[u8]) -> Result<(), Error> {
    if prog.len() % ebpf::INSN_SIZE != 0 {
        reject(format!("eBPF program length must be a multiple of {:?} octets",
                       ebpf::INSN_SIZE))?;
    }
    if prog.len() > ebpf::PROG_MAX_SIZE {
        reject(format!("eBPF program length limited to {:?}, here {:?}",
                       ebpf::PROG_MAX_INSNS, prog.len() / ebpf::INSN_SIZE))?;
    }

    if prog.is_empty() {
        reject("no program set, call set_program() to load one")?;
    }
    let last_opc = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1).opc;
    if last_opc & ebpf::BPF_CLS_MASK != ebpf::BPF_JMP {
        reject("program does not end with “EXIT” instruction")?;
    }

    Ok(())
}

fn check_imm_nonzero(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), Error> {
    if insn.imm == 0 {
        reject(format!("division by 0 (insn #{insn_ptr:?})"))?;
    }

    Ok(())
}

fn check_imm_endian(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), Error> {
    match insn.imm {
        16 | 32 | 64 => Ok(()),
        _ => reject(format!("unsupported argument for LE/BE (insn #{insn_ptr:?})"))
    }
}

fn check_load_dw(prog: &[u8], insn_ptr: usize) -> Result<(), Error> {
    // We know we can reach next insn since we enforce an EXIT insn at the end of program, while
    // this function should be called only for LD_DW insn, that cannot be last in program.
    let next_insn = ebpf::get_insn(prog, insn_ptr + 1);
    if next_insn.opc != 0 {
        reject(format!("incomplete LD_DW instruction (insn #{insn_ptr:?})"))?;
    }

    Ok(())
}

fn check_jmp_offset(prog: &[u8], insn_ptr: usize) -> Result<(), Error> {
    let insn = ebpf::get_insn(prog, insn_ptr);
    if insn.off == -1 {
        reject(format!("infinite loop (insn #{insn_ptr:?})"))?;
    }

    let dst_insn_ptr = insn_ptr as isize + 1 + insn.off as isize;
    if dst_insn_ptr < 0 || dst_insn_ptr as usize >= (prog.len() / ebpf::INSN_SIZE) {
        reject(format!("jump out of code to #{dst_insn_ptr:?} (insn #{insn_ptr:?})"))?;
    }

    let dst_insn = ebpf::get_insn(prog, dst_insn_ptr as usize);
    if dst_insn.opc == 0 {
        reject(format!("jump to middle of LD_DW at #{dst_insn_ptr:?} (insn #{insn_ptr:?})"))?;
    }

    Ok(())
}

fn check_registers(insn: &ebpf::Insn, store: bool, insn_ptr: usize) -> Result<(), Error> {
    if insn.src > 10 {
        reject(format!("invalid source register (insn #{insn_ptr:?})"))?;
    }

    match (insn.dst, store) {
        (0 ..= 9, _) | (10, true) => Ok(()),
        (10, false) => reject(format!("cannot write into register r10 (insn #{insn_ptr:?})")),
        (_, _)      => reject(format!("invalid destination register (insn #{insn_ptr:?})"))
    }
}

pub fn check(prog: &[u8]) -> Result<(), Error> {
    check_prog_len(prog)?;

    let mut insn_ptr:usize = 0;
    while insn_ptr * ebpf::INSN_SIZE < prog.len() {
        let insn = ebpf::get_insn(prog, insn_ptr);
        let mut store = false;

        match insn.opc {

            // BPF_LD class
            ebpf::LD_ABS_B   => {},
            ebpf::LD_ABS_H   => {},
            ebpf::LD_ABS_W   => {},
            ebpf::LD_ABS_DW  => {},
            ebpf::LD_IND_B   => {},
            ebpf::LD_IND_H   => {},
            ebpf::LD_IND_W   => {},
            ebpf::LD_IND_DW  => {},

            ebpf::LD_DW_IMM  => {
                store = true;
                check_load_dw(prog, insn_ptr)?;
                insn_ptr += 1;
            },

            // BPF_LDX class
            ebpf::LD_B_REG   => {},
            ebpf::LD_H_REG   => {},
            ebpf::LD_W_REG   => {},
            ebpf::LD_DW_REG  => {},

            // BPF_ST class
            ebpf::ST_B_IMM   => store = true,
            ebpf::ST_H_IMM   => store = true,
            ebpf::ST_W_IMM   => store = true,
            ebpf::ST_DW_IMM  => store = true,

            // BPF_STX class
            ebpf::ST_B_REG   => store = true,
            ebpf::ST_H_REG   => store = true,
            ebpf::ST_W_REG   => store = true,
            ebpf::ST_DW_REG  => store = true,
            ebpf::ST_W_XADD  => { unimplemented!(); },
            ebpf::ST_DW_XADD => { unimplemented!(); },

            // BPF_ALU class
            ebpf::ADD32_IMM  => {},
            ebpf::ADD32_REG  => {},
            ebpf::SUB32_IMM  => {},
            ebpf::SUB32_REG  => {},
            ebpf::MUL32_IMM  => {},
            ebpf::MUL32_REG  => {},
            ebpf::DIV32_IMM  => { check_imm_nonzero(&insn, insn_ptr)?; },
            ebpf::DIV32_REG  => {},
            ebpf::OR32_IMM   => {},
            ebpf::OR32_REG   => {},
            ebpf::AND32_IMM  => {},
            ebpf::AND32_REG  => {},
            ebpf::LSH32_IMM  => {},
            ebpf::LSH32_REG  => {},
            ebpf::RSH32_IMM  => {},
            ebpf::RSH32_REG  => {},
            ebpf::NEG32      => {},
            ebpf::MOD32_IMM  => { check_imm_nonzero(&insn, insn_ptr)?; },
            ebpf::MOD32_REG  => {},
            ebpf::XOR32_IMM  => {},
            ebpf::XOR32_REG  => {},
            ebpf::MOV32_IMM  => {},
            ebpf::MOV32_REG  => {},
            ebpf::ARSH32_IMM => {},
            ebpf::ARSH32_REG => {},
            ebpf::LE         => { check_imm_endian(&insn, insn_ptr)?; },
            ebpf::BE         => { check_imm_endian(&insn, insn_ptr)?; },

            // BPF_ALU64 class
            ebpf::ADD64_IMM  => {},
            ebpf::ADD64_REG  => {},
            ebpf::SUB64_IMM  => {},
            ebpf::SUB64_REG  => {},
            ebpf::MUL64_IMM  => {},
            ebpf::MUL64_REG  => {},
            ebpf::DIV64_IMM  => { check_imm_nonzero(&insn, insn_ptr)?; },
            ebpf::DIV64_REG  => {},
            ebpf::OR64_IMM   => {},
            ebpf::OR64_REG   => {},
            ebpf::AND64_IMM  => {},
            ebpf::AND64_REG  => {},
            ebpf::LSH64_IMM  => {},
            ebpf::LSH64_REG  => {},
            ebpf::RSH64_IMM  => {},
            ebpf::RSH64_REG  => {},
            ebpf::NEG64      => {},
            ebpf::MOD64_IMM  => { check_imm_nonzero(&insn, insn_ptr)?; },
            ebpf::MOD64_REG  => {},
            ebpf::XOR64_IMM  => {},
            ebpf::XOR64_REG  => {},
            ebpf::MOV64_IMM  => {},
            ebpf::MOV64_REG  => {},
            ebpf::ARSH64_IMM => {},
            ebpf::ARSH64_REG => {},

            // BPF_JMP class
            ebpf::JA         => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JEQ_IMM    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JEQ_REG    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JGT_IMM    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JGT_REG    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JGE_IMM    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JGE_REG    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JLT_IMM    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JLT_REG    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JLE_IMM    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JLE_REG    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSET_IMM   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSET_REG   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JNE_IMM    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JNE_REG    => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSGT_IMM   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSGT_REG   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSGE_IMM   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSGE_REG   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSLT_IMM   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSLT_REG   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSLE_IMM   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::JSLE_REG   => { check_jmp_offset(prog, insn_ptr)?; },
            ebpf::CALL       => {},
            ebpf::TAIL_CALL  => { unimplemented!() },
            ebpf::EXIT       => {},

            _                => {
                reject(format!("unknown eBPF opcode {:#2x} (insn #{insn_ptr:?})", insn.opc))?;
            },
        }

        check_registers(&insn, store, insn_ptr)?;

        insn_ptr += 1;
    }

    // insn_ptr should now be equal to number of instructions.
    if insn_ptr != prog.len() / ebpf::INSN_SIZE {
        reject(format!("jumped out of code to #{insn_ptr:?}"))?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! Base elements required to build views.
//!
//! Views are the main building blocks of your UI.
//!
//! A view can delegate part or all of its responsabilities to child views,
//! forming a view tree. The root of this tree is a `StackView` handled
//! directly by the `Cursive` element.
//!
//! # Layout
//!
//! The layout phase is when the size and location of each view is computed.
//!
//! Each view is given an area of the screen by the `View::layout()` method.
//! With this, the view is free to plan its content, including calling
//! `View::layout()` on its own children.
//!
//! In order to determine how much space should be given each child, parents
//! can use `View::required_size()` on them.
//!
//!
//! ### Contracts
//!
//! When building new Views, you should respect these contracts:
//!
//! * By default, `View::layout()` should be called before any call to
//!   `View::draw()` with the same available size. The only exceptions is
//!   when both following conditions are met:
//!     * The available size has not changed since the last call to
//!       `View::layout()`
//!     * `View::needs_relayout()` returns `false`
//!
//!   In this case, it is safe to omit the call to `View::layout()`.
//!
//! * The value returned by `required_size` should be an actually viable size,
//!   no matter what the request is. This means calling `View::layout()` with
//!   a size returned by `required_size` is **never** an error.

#[macro_use]
mod view_wrapper;

// Essentials components
mod any;
mod finder;
mod margins;
mod position;
mod size_cache;
mod size_constraint;
mod view_path;
mod view_trait;

// Helper bases
mod boxable;
mod identifiable;
#[cfg(feature = "unstable_scroll")]
pub mod scroll;
#[cfg(not(feature = "unstable_scroll"))]
pub(crate) mod scroll;

mod scroll_base;
mod scrollable;

mod into_boxed_view;

pub use self::any::AnyView;
pub use self::boxable::Boxable;
pub use self::finder::{Finder, Selector};
pub use self::identifiable::Identifiable;
pub use self::into_boxed_view::IntoBoxedView;
pub use self::margins::Margins;
pub use self::position::{Offset, Position};
pub use self::scroll::ScrollStrategy;
pub use self::scroll_base::ScrollBase;
pub use self::scrollable::Scrollable;
pub use self::size_cache::SizeCache;
pub use self::size_constraint::SizeConstraint;
pub use self::view_path::ViewPath;
pub use self::view_trait::View;
pub use self::view_wrapper::ViewWrapper;
<commit_msg>Disable dead code lint for unstable module<commit_after>//! Base elements required to build views.
//!
//! Views are the main building blocks of your UI.
//!
//! A view can delegate part or all of its responsabilities to child views,
//! forming a view tree. The root of this tree is a `StackView` handled
//! directly by the `Cursive` element.
//!
//! # Layout
//!
//! The layout phase is when the size and location of each view is computed.
//!
//! Each view is given an area of the screen by the `View::layout()` method.
//! With this, the view is free to plan its content, including calling
//! `View::layout()` on its own children.
//!
//! In order to determine how much space should be given each child, parents
//! can use `View::required_size()` on them.
//!
//!
//! ### Contracts
//!
//! When building new Views, you should respect these contracts:
//!
//! * By default, `View::layout()` should be called before any call to
//!   `View::draw()` with the same available size. The only exceptions is
//!   when both following conditions are met:
//!     * The available size has not changed since the last call to
//!       `View::layout()`
//!     * `View::needs_relayout()` returns `false`
//!
//!   In this case, it is safe to omit the call to `View::layout()`.
//!
//! * The value returned by `required_size` should be an actually viable size,
//!   no matter what the request is. This means calling `View::layout()` with
//!   a size returned by `required_size` is **never** an error.

#[macro_use]
mod view_wrapper;

// Essentials components
mod any;
mod finder;
mod margins;
mod position;
mod size_cache;
mod size_constraint;
mod view_path;
mod view_trait;

// Helper bases
mod boxable;
mod identifiable;
#[cfg(feature = "unstable_scroll")]
pub mod scroll;

#[cfg(not(feature = "unstable_scroll"))]
#[allow(dead_code)]
pub(crate) mod scroll;

mod scroll_base;
mod scrollable;

mod into_boxed_view;

pub use self::any::AnyView;
pub use self::boxable::Boxable;
pub use self::finder::{Finder, Selector};
pub use self::identifiable::Identifiable;
pub use self::into_boxed_view::IntoBoxedView;
pub use self::margins::Margins;
pub use self::position::{Offset, Position};
pub use self::scroll::ScrollStrategy;
pub use self::scroll_base::ScrollBase;
pub use self::scrollable::Scrollable;
pub use self::size_cache::SizeCache;
pub use self::size_constraint::SizeConstraint;
pub use self::view_path::ViewPath;
pub use self::view_trait::View;
pub use self::view_wrapper::ViewWrapper;
<|endoftext|>


<commit_before>/// This module contains the definition for bano2mimir configuration and command line arguments.
use mimir::domain::model::configuration::{ContainerConfig, PhysicalModeWeight};
use serde::{Deserialize, Serialize};
use snafu::{ResultExt, Snafu};
use std::env;
use std::path::PathBuf;

use mimir::adapters::secondary::elasticsearch::ElasticsearchStorageConfig;

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

#[derive(Debug, Snafu)]
pub enum Error {
    #[snafu(display("Config Source Error: {}", source))]
    ConfigSource { source: common::config::Error },
    #[snafu(display("Config Error: {}", source))]
    ConfigBuild { source: config::ConfigError },
    #[snafu(display("Invalid Configuration: {}", msg))]
    Invalid { msg: String },
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Settings {
    pub mode: Option<String>,
    pub elasticsearch: ElasticsearchStorageConfig,
    pub container: ContainerConfig,
    pub nb_threads: Option<usize>,
    pub physical_mode_weight: Option<Vec<PhysicalModeWeight>>,
}

#[derive(Debug, clap::Parser)]
#[clap(
    name = "ntfs2mimir",
    about = "Parsing NTFS document and indexing its content in Elasticsearch",
    version = VERSION,
    author = AUTHORS
    )]
pub struct Opts {
    /// Defines the config directory
    ///
    /// This directory must contain 'elasticsearch' and 'cosmogony2mimir' subdirectories.
    #[clap(parse(from_os_str), short = 'c', long = "config-dir")]
    pub config_dir: PathBuf,

    /// Defines the run mode in {testing, dev, prod, ...}
    ///
    /// If no run mode is provided, a default behavior will be used.
    #[clap(short = 'm', long = "run-mode")]
    pub run_mode: Option<String>,

    /// Override settings values using key=value
    #[clap(
        short = 's',
        long = "setting",
        multiple_values = false,
        multiple_occurrences = true
    )]
    pub settings: Vec<String>,

    /// Either a NTFS zipped file, or the directory in which an NTFS file has been unzipped.
    #[clap(short = 'i', long = "input", parse(from_os_str))]
    pub input: PathBuf,

    #[clap(subcommand)]
    pub cmd: Command,
}

#[derive(Debug, clap::Parser)]
pub enum Command {
    /// Execute ntfs2mimir with the given configuration
    Run,
    /// Prints ntfs2mimir's configuration
    Config,
}

// TODO Parameterize the config directory
impl Settings {
    // Read the configuration from <config-dir>/ntfs2mimir and <config-dir>/elasticsearch
    pub fn new(opts: &Opts) -> Result<Self, Error> {
        common::config::config_from(
            opts.config_dir.as_ref(),
            &["ntfs2mimir", "elasticsearch"],
            opts.run_mode.as_deref(),
            "MIMIR",
            opts.settings.clone(),
        )
        .context(ConfigSourceSnafu)?
        .try_into()
        .context(ConfigBuildSnafu)
    }
}

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

    #[test]
    fn should_return_ok_with_default_config_dir() {
        let config_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("config");
        let opts = Opts {
            config_dir,
            run_mode: None,
            settings: vec![],
            cmd: Command::Run,
            input: PathBuf::from("foo.jsonl.gz"),
        };
        let settings = Settings::new(&opts);
        assert!(
            settings.is_ok(),
            "Expected Ok, Got an Err: {}",
            settings.unwrap_err().to_string()
        );
        assert_eq!(settings.unwrap().mode, None);
    }

    #[test]
    fn should_override_elasticsearch_url_with_command_line() {
        let config_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("config");
        let opts = Opts {
            config_dir,
            run_mode: None,
            settings: vec![String::from("elasticsearch.url='http://localhost:9999'")],
            cmd: Command::Run,
            input: PathBuf::from("foo.jsonl.gz"),
        };
        let settings = Settings::new(&opts);
        assert!(
            settings.is_ok(),
            "Expected Ok, Got an Err: {}",
            settings.unwrap_err().to_string()
        );
        assert_eq!(
            settings.unwrap().elasticsearch.url.as_str(),
            "http://localhost:9999/"
        );
    }

    #[test]
    fn should_override_elasticsearch_url_environment_variable() {
        let config_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("config");
        std::env::set_var("MIMIR_ELASTICSEARCH__URL", "http://localhost:9999");
        let opts = Opts {
            config_dir,
            run_mode: None,
            settings: vec![],
            cmd: Command::Run,
            input: PathBuf::from("foo.osm.pbf"),
        };
        let settings = Settings::new(&opts);
        assert!(
            settings.is_ok(),
            "Expected Ok, Got an Err: {}",
            settings.unwrap_err().to_string()
        );
        assert_eq!(
            settings.unwrap().elasticsearch.url.as_str(),
            "http://localhost:9999/"
        );
    }
}
<commit_msg>tests added<commit_after>/// This module contains the definition for bano2mimir configuration and command line arguments.
use mimir::domain::model::configuration::{ContainerConfig, PhysicalModeWeight};
use serde::{Deserialize, Serialize};
use snafu::{ResultExt, Snafu};
use std::env;
use std::path::PathBuf;

use mimir::adapters::secondary::elasticsearch::ElasticsearchStorageConfig;

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

#[derive(Debug, Snafu)]
pub enum Error {
    #[snafu(display("Config Source Error: {}", source))]
    ConfigSource { source: common::config::Error },
    #[snafu(display("Config Error: {}", source))]
    ConfigBuild { source: config::ConfigError },
    #[snafu(display("Invalid Configuration: {}", msg))]
    Invalid { msg: String },
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Settings {
    pub mode: Option<String>,
    pub elasticsearch: ElasticsearchStorageConfig,
    pub container: ContainerConfig,
    pub nb_threads: Option<usize>,
    pub physical_mode_weight: Option<Vec<PhysicalModeWeight>>,
}

#[derive(Debug, clap::Parser)]
#[clap(
    name = "ntfs2mimir",
    about = "Parsing NTFS document and indexing its content in Elasticsearch",
    version = VERSION,
    author = AUTHORS
    )]
pub struct Opts {
    /// Defines the config directory
    ///
    /// This directory must contain 'elasticsearch' and 'cosmogony2mimir' subdirectories.
    #[clap(parse(from_os_str), short = 'c', long = "config-dir")]
    pub config_dir: PathBuf,

    /// Defines the run mode in {testing, dev, prod, ...}
    ///
    /// If no run mode is provided, a default behavior will be used.
    #[clap(short = 'm', long = "run-mode")]
    pub run_mode: Option<String>,

    /// Override settings values using key=value
    #[clap(
        short = 's',
        long = "setting",
        multiple_values = false,
        multiple_occurrences = true
    )]
    pub settings: Vec<String>,

    /// Either a NTFS zipped file, or the directory in which an NTFS file has been unzipped.
    #[clap(short = 'i', long = "input", parse(from_os_str))]
    pub input: PathBuf,

    #[clap(subcommand)]
    pub cmd: Command,
}

#[derive(Debug, clap::Parser)]
pub enum Command {
    /// Execute ntfs2mimir with the given configuration
    Run,
    /// Prints ntfs2mimir's configuration
    Config,
}

// TODO Parameterize the config directory
impl Settings {
    // Read the configuration from <config-dir>/ntfs2mimir and <config-dir>/elasticsearch
    pub fn new(opts: &Opts) -> Result<Self, Error> {
        common::config::config_from(
            opts.config_dir.as_ref(),
            &["ntfs2mimir", "elasticsearch"],
            opts.run_mode.as_deref(),
            "MIMIR",
            opts.settings.clone(),
        )
        .context(ConfigSourceSnafu)?
        .try_into()
        .context(ConfigBuildSnafu)
    }
}

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

    #[test]
    fn should_return_ok_with_default_config_dir() {
        let config_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("config");
        let opts = Opts {
            config_dir,
            run_mode: None,
            settings: vec![],
            cmd: Command::Run,
            input: PathBuf::from("foo.jsonl.gz"),
        };
        let settings = Settings::new(&opts);
        assert!(
            settings.is_ok(),
            "Expected Ok, Got an Err: {}",
            settings.unwrap_err().to_string()
        );
        let settings_unwrap = settings.unwrap();
        assert_eq!(settings_unwrap.mode, None);
        assert!(settings_unwrap.physical_mode_weight.unwrap().len() > 0);
    }

    #[test]
    fn should_override_elasticsearch_url_with_command_line() {
        let config_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("config");
        let opts = Opts {
            config_dir,
            run_mode: None,
            settings: vec![String::from("elasticsearch.url='http://localhost:9999'")],
            cmd: Command::Run,
            input: PathBuf::from("foo.jsonl.gz"),
        };
        let settings = Settings::new(&opts);
        assert!(
            settings.is_ok(),
            "Expected Ok, Got an Err: {}",
            settings.unwrap_err().to_string()
        );
        assert_eq!(
            settings.unwrap().elasticsearch.url.as_str(),
            "http://localhost:9999/"
        );
    }

    #[test]
    fn should_override_elasticsearch_url_environment_variable() {
        let config_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("config");
        std::env::set_var("MIMIR_ELASTICSEARCH__URL", "http://localhost:9999");
        let opts = Opts {
            config_dir,
            run_mode: None,
            settings: vec![],
            cmd: Command::Run,
            input: PathBuf::from("foo.osm.pbf"),
        };
        let settings = Settings::new(&opts);
        assert!(
            settings.is_ok(),
            "Expected Ok, Got an Err: {}",
            settings.unwrap_err().to_string()
        );
        assert_eq!(
            settings.unwrap().elasticsearch.url.as_str(),
            "http://localhost:9999/"
        );
    }
}
<|endoftext|>


<commit_before>//! Functions to read and write control registers.
//! See Intel Vol. 3a Section 2.5, especially Figure 2.6.

bitflags! {
    pub flags Cr0: usize {
        const CR0_ENABLE_PAGING = 1 << 31,
        const CR0_CACHE_DISABLE = 1 << 30,
        const CR0_NOT_WRITE_THROUGH = 1 << 29,
        const CR0_ALIGNMENT_MASK = 1 << 18,
        const CR0_WRITE_PROTECT = 1 << 16,
        const CR0_NUMERIC_ERROR = 1 << 5,
        const CR0_EXTENSION_TYPE = 1 << 4,
        const CR0_TASK_SWITCHED = 1 << 3,
        const CR0_EMULATE_COPROCESSOR = 1 << 2,
        const CR0_MONITOR_COPROCESSOR = 1 << 1,
        const CR0_PROTECTED_MODE = 1 << 0,
    }
}

bitflags! {
    pub flags Cr4: usize {
        const CR4_ENABLE_SMAP = 1 << 21,
        const CR4_ENABLE_SMEP = 1 << 20,
        const CR4_ENABLE_OS_XSAVE = 1 << 18,
        const CR4_ENABLE_PCID = 1 << 17,
        const CR4_ENABLE_SMX = 1 << 14,
        const CR4_ENABLE_VMX = 1 << 13,
        const CR4_UNMASKED_SSE = 1 << 10,
        const CR4_ENABLE_SSE = 1 << 9,
        const CR4_ENABLE_PPMC = 1 << 8,
        const CR4_ENABLE_GLOBAL_PAGES = 1 << 7,
        const CR4_ENABLE_MACHINE_CHECK = 1 << 6,
        const CR4_ENABLE_PAE = 1 << 5,
        const CR4_ENABLE_PSE = 1 << 4,
        const CR4_DEBUGGING_EXTENSIONS = 1 << 3,
        const CR4_TIME_STAMP_DISABLE = 1 << 2,
        const CR4_VIRTUAL_INTERRUPTS = 1 << 1,
        const CR4_ENABLE_VME = 1 << 0,
    }
}

/// Read cr0
pub unsafe fn cr0() -> Cr0 {
    let ret: usize;
    asm!("mov %cr0, $0" : "=r" (ret));
    Cr0::from_bits_truncate(ret)
}

/// Write cr0.
pub unsafe fn cr0_write(val: Cr0) {
    asm!("mov $0, %cr0" :: "r" (val.bits) : "memory");
}

/// Contains page-fault linear address.
pub unsafe fn cr2() -> usize {
    let ret: usize;
    asm!("mov %cr2, $0" : "=r" (ret));
    ret
}

/// Contains page-table root pointer.
pub unsafe fn cr3() -> u64 {
    let ret: u64;
    asm!("mov %cr3, $0" : "=r" (ret));
    ret
}

/// Switch page-table PML4 pointer.
pub unsafe fn cr3_write(val: u64) {
    asm!("mov $0, %cr3" :: "r" (val) : "memory");
}

/// Contains various flags to control operations in protected mode.
pub unsafe fn cr4() -> Cr4 {
    let ret: usize;
    asm!("mov %cr4, $0" : "=r" (ret));
    Cr4::from_bits_truncate(ret)
}

/// Write cr4.
pub unsafe fn cr4_write(val: Cr4) {
    asm!("mov $0, %cr4" :: "r" (val.bits) : "memory");
}
<commit_msg>Add missing flags for CR4 and add functions to read and write the Extended Control Register XCR0.<commit_after>//! Functions to read and write control registers.
//! See Intel Vol. 3a Section 2.5, especially Figure 2-7.

bitflags! {
    pub flags Cr0: usize {
        const CR0_ENABLE_PAGING = 1 << 31,
        const CR0_CACHE_DISABLE = 1 << 30,
        const CR0_NOT_WRITE_THROUGH = 1 << 29,
        const CR0_ALIGNMENT_MASK = 1 << 18,
        const CR0_WRITE_PROTECT = 1 << 16,
        const CR0_NUMERIC_ERROR = 1 << 5,
        const CR0_EXTENSION_TYPE = 1 << 4,
        const CR0_TASK_SWITCHED = 1 << 3,
        const CR0_EMULATE_COPROCESSOR = 1 << 2,
        const CR0_MONITOR_COPROCESSOR = 1 << 1,
        const CR0_PROTECTED_MODE = 1 << 0,
    }
}

bitflags! {
    pub flags Cr4: usize {
        const CR4_ENABLE_PROTECTION_KEY = 1 << 22,
        const CR4_ENABLE_SMAP = 1 << 21,
        const CR4_ENABLE_SMEP = 1 << 20,
        const CR4_ENABLE_OS_XSAVE = 1 << 18,
        const CR4_ENABLE_PCID = 1 << 17,
        const CR4_ENABLE_FSGSBASE = 1 << 16,
        const CR4_ENABLE_SMX = 1 << 14,
        const CR4_ENABLE_VMX = 1 << 13,
        const CR4_ENABLE_UMIP = 1 << 11,
        const CR4_UNMASKED_SSE = 1 << 10,
        const CR4_ENABLE_SSE = 1 << 9,
        const CR4_ENABLE_PPMC = 1 << 8,
        const CR4_ENABLE_GLOBAL_PAGES = 1 << 7,
        const CR4_ENABLE_MACHINE_CHECK = 1 << 6,
        const CR4_ENABLE_PAE = 1 << 5,
        const CR4_ENABLE_PSE = 1 << 4,
        const CR4_DEBUGGING_EXTENSIONS = 1 << 3,
        const CR4_TIME_STAMP_DISABLE = 1 << 2,
        const CR4_VIRTUAL_INTERRUPTS = 1 << 1,
        const CR4_ENABLE_VME = 1 << 0,
    }
}

bitflags! {
    pub flags Xcr0: usize {
        const XCR0_PKRU_STATE = 1 << 9,
        const XCR0_HI16_ZMM_STATE = 1 << 7,
        const XCR0_ZMM_HI256_STATE = 1 << 6,
        const XCR0_OPMASK_STATE = 1 << 5,
        const XCR0_BNDCSR_STATE = 1 << 4,
        const XCR0_BNDREG_STATE = 1 << 3,
        const XCR0_AVX_STATE = 1 << 2,
        const XCR0_SSE_STATE = 1 << 1,
        const XCR0_FPU_MMX_STATE = 1 << 0,
    }
}

/// Read cr0
pub unsafe fn cr0() -> Cr0 {
    let ret: usize;
    asm!("mov %cr0, $0" : "=r" (ret));
    Cr0::from_bits_truncate(ret)
}

/// Write cr0.
pub unsafe fn cr0_write(val: Cr0) {
    asm!("mov $0, %cr0" :: "r" (val.bits) : "memory");
}

/// Contains page-fault linear address.
pub unsafe fn cr2() -> usize {
    let ret: usize;
    asm!("mov %cr2, $0" : "=r" (ret));
    ret
}

/// Contains page-table root pointer.
pub unsafe fn cr3() -> u64 {
    let ret: u64;
    asm!("mov %cr3, $0" : "=r" (ret));
    ret
}

/// Switch page-table PML4 pointer.
pub unsafe fn cr3_write(val: u64) {
    asm!("mov $0, %cr3" :: "r" (val) : "memory");
}

/// Contains various flags to control operations in protected mode.
pub unsafe fn cr4() -> Cr4 {
    let ret: usize;
    asm!("mov %cr4, $0" : "=r" (ret));
    Cr4::from_bits_truncate(ret)
}

/// Write cr4.
pub unsafe fn cr4_write(val: Cr4) {
    asm!("mov $0, %cr4" :: "r" (val.bits) : "memory");
}

/// Read Extended Control Register XCR0.
/// Only supported if CR4_ENABLE_OS_XSAVE is set.
pub unsafe fn xcr0() -> Xcr0 {
    let high: u32;
    let low: u32;
    asm!("xgetbv" : "={eax}"(low), "={edx}"(high) : "{ecx}"(0));
    Xcr0::from_bits_truncate((high as usize) << 32 | low as usize)
}

/// Write to Extended Control Register XCR0.
/// Only supported if CR4_ENABLE_OS_XSAVE is set.
pub unsafe fn xcr0_write(val: Xcr0) {
    let high: u32 = (val.bits >> 32) as u32;
    let low: u32 = val.bits as u32;
    asm!("xsetbv" :: "{eax}"(low), "{ecx}"(0), "{edx}"(high));
}
<|endoftext|>


<commit_before>//! Functions to read and write control registers.
//! See Intel Vol. 3a Section 2.5, especially Figure 2.6.

bitflags! {
    pub flags Cr0: usize {
        const EnablePaging = 1 << 31,
        const CacheDisable = 1 << 30,
        const NotWriteThrough = 1 << 29,
        const AlignmentMask = 1 << 18,
        const WriteProtect = 1 << 16,
        const NumericError = 1 << 5,
        const ExtensionType = 1 << 4,
        const TaskSwitched = 1 << 3,
        const EmulateCoprocessor = 1 << 2,
        const MonitorCoprocessor = 1 << 1,
        const ProtectedMode = 1 << 0,
    }
}

bitflags! {
    pub flags Cr4: usize {
        const EnableSmap = 1 << 21,
        const EnableSmep = 1 << 20,
        const EnableOsXSave = 1 << 18,
        const EnablePcid = 1 << 17,
        const EnableSmx = 1 << 14,
        const EnableVmx = 1 << 13,
        const UnmaskedSse = 1 << 10,
        const EnableSse = 1 << 9,
        const EnablePpmc = 1 << 8,
        const EnableGlobalPages = 1 << 7,
        const EnableMachineCheck = 1 << 6,
        const EnablePae = 1 << 5,
        const EnablePse = 1 << 4,
        const DebuggingExtensions = 1 << 3,
        const TimeStampDisable = 1 << 2,
        const VirtualInterrupts = 1 << 1,
        const EnableVme = 1 << 0,
    }
}

/// Read cr0
pub unsafe fn cr0() -> Cr0 {
    let ret: usize;
    asm!("mov %cr0, $0" : "=r" (ret));
    Cr0::from_bits_truncate(ret)
}

/// Write cr0.
pub unsafe fn cr0_write(val: Cr0) {
    asm!("mov $0, %cr0" :: "r" (val.bits) : "memory");
}

/// Contains page-fault linear address.
pub unsafe fn cr2() -> usize {
    let ret: usize;
    asm!("mov %cr2, $0" : "=r" (ret));
    ret
}

/// Contains page-table root pointer.
pub unsafe fn cr3() -> usize {
    let ret: usize;
    asm!("mov %cr3, $0" : "=r" (ret));
    ret
}

/// Switch page-table PML4 pointer.
pub unsafe fn cr3_write(val: usize) {
    asm!("mov $0, %cr3" :: "r" (val) : "memory");
}

/// Contains various flags to control operations in protected mode.
pub unsafe fn cr4() -> Cr4 {
    let ret: usize;
    asm!("mov %cr4, $0" : "=r" (ret));
    Cr4::from_bits_truncate(ret)
}

/// Write cr4.
pub unsafe fn cr4_write(val: Cr4) {
    asm!("mov $0, %cr4" :: "r" (val.bits) : "memory");
}
<commit_msg>Normalize Control Register bitflags' names with the rest of the library<commit_after>//! Functions to read and write control registers.
//! See Intel Vol. 3a Section 2.5, especially Figure 2.6.

bitflags! {
    pub flags Cr0: usize {
        const CR0_ENABLE_PAGING = 1 << 31,
        const CR0_CACHE_DISABLE = 1 << 30,
        const CR0_NOT_WRITE_THROUGH = 1 << 29,
        const CR0_ALIGNMENT_MASK = 1 << 18,
        const CR0_WRITE_PROTECT = 1 << 16,
        const CR0_NUMERIC_ERROR = 1 << 5,
        const CR0_EXTENSION_TYPE = 1 << 4,
        const CR0_TASK_SWITCHED = 1 << 3,
        const CR0_EMULATE_COPROCESSOR = 1 << 2,
        const CR0_MONITOR_COPROCESSOR = 1 << 1,
        const CR0_PROTECTED_MODE = 1 << 0,
    }
}

bitflags! {
    pub flags Cr4: usize {
        const CR4_ENABLE_SMAP = 1 << 21,
        const CR4_ENABLE_SMEP = 1 << 20,
        const CR4_ENABLE_OS_XSAVE = 1 << 18,
        const CR4_ENABLE_PCID = 1 << 17,
        const CR4_ENABLE_SMX = 1 << 14,
        const CR4_ENABLE_VMX = 1 << 13,
        const CR4_UNMASKED_SSE = 1 << 10,
        const CR4_ENABLE_SSE = 1 << 9,
        const CR4_ENABLE_PPMC = 1 << 8,
        const CR4_ENABLE_GLOBAL_PAGES = 1 << 7,
        const CR4_ENABLE_MACHINE_CHECK = 1 << 6,
        const CR4_ENABLE_PAE = 1 << 5,
        const CR4_ENABLE_PSE = 1 << 4,
        const CR4_DEBUGGING_EXTENSIONS = 1 << 3,
        const CR4_TIME_STAMP_DISABLE = 1 << 2,
        const CR4_VIRTUAL_INTERRUPTS = 1 << 1,
        const CR4_ENABLE_VME = 1 << 0,
    }
}

/// Read cr0
pub unsafe fn cr0() -> Cr0 {
    let ret: usize;
    asm!("mov %cr0, $0" : "=r" (ret));
    Cr0::from_bits_truncate(ret)
}

/// Write cr0.
pub unsafe fn cr0_write(val: Cr0) {
    asm!("mov $0, %cr0" :: "r" (val.bits) : "memory");
}

/// Contains page-fault linear address.
pub unsafe fn cr2() -> usize {
    let ret: usize;
    asm!("mov %cr2, $0" : "=r" (ret));
    ret
}

/// Contains page-table root pointer.
pub unsafe fn cr3() -> usize {
    let ret: usize;
    asm!("mov %cr3, $0" : "=r" (ret));
    ret
}

/// Switch page-table PML4 pointer.
pub unsafe fn cr3_write(val: usize) {
    asm!("mov $0, %cr3" :: "r" (val) : "memory");
}

/// Contains various flags to control operations in protected mode.
pub unsafe fn cr4() -> Cr4 {
    let ret: usize;
    asm!("mov %cr4, $0" : "=r" (ret));
    Cr4::from_bits_truncate(ret)
}

/// Write cr4.
pub unsafe fn cr4_write(val: Cr4) {
    asm!("mov $0, %cr4" :: "r" (val.bits) : "memory");
}
<|endoftext|>