<commit_before>//! Lua functionality

use hlua;
use hlua::{Lua, LuaError};
use hlua::any::AnyLuaValue;

use std::thread;

use std::fs::{File};
use std::path::Path;
use std::io::Write;

use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

lazy_static! {
    /// Sends requests to the lua thread
    static ref SENDER: Mutex<Sender<LuaQuery>> = {
        let (tx, rx) = channel::<LuaQuery>();
        Mutex::new(tx)
    };

    /// Receives data back from the lua thread
    /// This should only be accessed by the lua thread itself.
    static ref RECEIVER: Mutex<Receiver<LuaResponse>> = {
        let (tx, rx) = channel::<LuaResponse>();
        Mutex::new(rx)
    };

    /// Whether the lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

/// Messages sent to the lua thread
pub enum LuaQuery {
    /// Halt the lua thread
    Terminate,
    // Restart the lua thread
    Restart,
    /// Execute a string
    Execute(String),
    /// Execute a file
    ExecuteFile(String),
    /// Get a variable
    GetVariable(String),
    /// Set a value
    SetValue {
        name: Box<::std::borrow::Borrow<str> + Sized>,
        val: Box<hlua::Push<&'static mut Lua<'static>> + Sized>
    },
    /// Create a new array
    EmptyArray(String),
    /// Unused send type
    Unused,
}

/// Messages received from lua thread
pub enum LuaResponse {
    /// Lua variable obtained
    Variable(Option<AnyLuaValue>),
    /// Lua error
    Error(hlua::LuaError),
    /// A function is returned
    Function(hlua::functions_read::LuaFunction<String>)
}

unsafe impl Send for LuaQuery { }
unsafe impl Send for LuaResponse { }
unsafe impl Sync for LuaQuery { }
unsafe impl Sync for LuaResponse { }

/// Send a value to the lua thread
pub fn send(query: LuaQuery) {
    SENDER.lock().unwrap().send(query).unwrap();
}

/// Initialize the lua thread
pub fn init() {
    trace!("Initializing...");
    let (query_tx, query_rx) = channel::<LuaQuery>();
    let (answer_tx, answer_rx) = channel::<LuaResponse>();
    {
        let mut sender = SENDER.lock().unwrap();
        let mut receiver = RECEIVER.lock().unwrap();

        *sender = query_tx;
        *receiver = answer_rx;
    }

    thread::spawn(move || {
        trace!("thread: Inside thread!");
        let sender = answer_tx;
        let receiver = query_rx;
        let mut lua = Lua::new();
        trace!("thread: Loading libraries...");
        lua.openlibs();
        trace!("thread: Libraries loaded");
        trace!("thread: Testing hello world...");
        let mut file = File::create("/tmp/init.lua").unwrap();
        file.write(b"print('Hello world!')").unwrap();
        lua.execute_from_reader::<(), File>(File::open("/tmp/init.lua")
                                            .unwrap()).unwrap();
        trace!("thread: Done!");
        trace!("thread: Entering loop...");
        thread_main_loop(sender, receiver, &mut lua);
    });
    trace!("Created thread. Init finished.");
}

fn thread_main_loop(sender: Sender<LuaResponse>, receiver: Receiver<LuaQuery>,
                    lua: &mut Lua) {
    loop {
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                thread_handle_message(&sender, message, lua);
            }
        }
    }
}

fn thread_handle_message(sender: &Sender<LuaResponse>, request: LuaQuery, lua: &mut Lua) {
    match request {
        LuaQuery::Terminate => {
            trace!("thread: Received terminate signal");

            info!("thread: Lua thread terminating!");
            return;
        },

        LuaQuery::Restart => {
            trace!("thread: Received restart signal!");

            error!("thread: Lua thread restart not supported!");
            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("thread: Received request to execute code");
            trace!("thread: Executing {:?}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("thread: Error executing code: {:?}", error);
                    let response = LuaResponse::Error(error);

                    thread_send(&sender, response);
                }
                Ok(_) => {
                    // This is gonna be really spammy one day
                    trace!("thread: Code executed okay.");
                }
            }
        },

        LuaQuery::ExecuteFile(name) => {
            trace!("thread: Received request to execute file {}", name);
            info!("thread: Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("thread: Error executing {}!", name);

                    thread_send(&sender, LuaResponse::Error(err));
                }
                else {
                    trace!("thread: Execution of {} successful.", name);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(&sender, LuaResponse::Error(read_error));
            }
        },

        LuaQuery::GetVariable(varname) => {
            trace!("thread: Received request to get variable {}", varname);
            let var_result = lua.get(varname.as_str());

            match var_result {
                Some(var) => {
                    thread_send(&sender, LuaResponse::Variable(Some(var)));
                }
                None => {
                    warn!("thread: Unable to get variable {}", varname);

                    thread_send(&sender, LuaResponse::Variable(None));
                }
            }
        },

        LuaQuery::SetValue { name: name, val: val } => {

        },

        LuaQuery::EmptyArray(name) => {

        },

        _ => {
            panic!("Unimplemented send type for lua thread!");
        }
    }
}

fn thread_send(sender: &Sender<LuaResponse>, response: LuaResponse)
               -> Result<(), String> {
    trace!("Called thread_send");
    match sender.send(response) {
        Ok(()) => Ok(()),
        Err(e) => {
            error!("thread: Unable to broadcast response!");
            error!("thread: Shutting down in response to inability to continue!");
            panic!("Lua thread unable to communicate with main thread, shutting down!");
        }
    }
}
<commit_msg>Change thread_send to return (), keep its lines < 80<commit_after>//! Lua functionality

use hlua;
use hlua::{Lua, LuaError};
use hlua::any::AnyLuaValue;

use std::thread;

use std::fs::{File};
use std::path::Path;
use std::io::Write;

use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

lazy_static! {
    /// Sends requests to the lua thread
    static ref SENDER: Mutex<Sender<LuaQuery>> = {
        let (tx, rx) = channel::<LuaQuery>();
        Mutex::new(tx)
    };

    /// Receives data back from the lua thread
    /// This should only be accessed by the lua thread itself.
    static ref RECEIVER: Mutex<Receiver<LuaResponse>> = {
        let (tx, rx) = channel::<LuaResponse>();
        Mutex::new(rx)
    };

    /// Whether the lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

/// Messages sent to the lua thread
pub enum LuaQuery {
    /// Halt the lua thread
    Terminate,
    // Restart the lua thread
    Restart,
    /// Execute a string
    Execute(String),
    /// Execute a file
    ExecuteFile(String),
    /// Get a variable
    GetVariable(String),
    /// Set a value
    SetValue {
        name: Box<::std::borrow::Borrow<str> + Sized>,
        val: Box<hlua::Push<&'static mut Lua<'static>> + Sized>
    },
    /// Create a new array
    EmptyArray(String),
    /// Unused send type
    Unused,
}

/// Messages received from lua thread
pub enum LuaResponse {
    /// Lua variable obtained
    Variable(Option<AnyLuaValue>),
    /// Lua error
    Error(hlua::LuaError),
    /// A function is returned
    Function(hlua::functions_read::LuaFunction<String>)
}

unsafe impl Send for LuaQuery { }
unsafe impl Send for LuaResponse { }
unsafe impl Sync for LuaQuery { }
unsafe impl Sync for LuaResponse { }

/// Send a value to the lua thread
pub fn send(query: LuaQuery) {
    SENDER.lock().unwrap().send(query).unwrap();
}

/// Initialize the lua thread
pub fn init() {
    trace!("Initializing...");
    let (query_tx, query_rx) = channel::<LuaQuery>();
    let (answer_tx, answer_rx) = channel::<LuaResponse>();
    {
        let mut sender = SENDER.lock().unwrap();
        let mut receiver = RECEIVER.lock().unwrap();

        *sender = query_tx;
        *receiver = answer_rx;
    }

    thread::spawn(move || {
        trace!("thread: Inside thread!");
        let sender = answer_tx;
        let receiver = query_rx;
        let mut lua = Lua::new();
        trace!("thread: Loading libraries...");
        lua.openlibs();
        trace!("thread: Libraries loaded");
        trace!("thread: Testing hello world...");
        let mut file = File::create("/tmp/init.lua").unwrap();
        file.write(b"print('Hello world!')").unwrap();
        lua.execute_from_reader::<(), File>(File::open("/tmp/init.lua")
                                            .unwrap()).unwrap();
        trace!("thread: Done!");
        trace!("thread: Entering loop...");
        thread_main_loop(sender, receiver, &mut lua);
    });
    trace!("Created thread. Init finished.");
}

fn thread_main_loop(sender: Sender<LuaResponse>, receiver: Receiver<LuaQuery>,
                    lua: &mut Lua) {
    loop {
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                thread_handle_message(&sender, message, lua);
            }
        }
    }
}

fn thread_handle_message(sender: &Sender<LuaResponse>, request: LuaQuery, lua: &mut Lua) {
    match request {
        LuaQuery::Terminate => {
            trace!("thread: Received terminate signal");

            info!("thread: Lua thread terminating!");
            return;
        },

        LuaQuery::Restart => {
            trace!("thread: Received restart signal!");

            error!("thread: Lua thread restart not supported!");
            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("thread: Received request to execute code");
            trace!("thread: Executing {:?}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("thread: Error executing code: {:?}", error);
                    let response = LuaResponse::Error(error);

                    thread_send(&sender, response);
                }
                Ok(_) => {
                    // This is gonna be really spammy one day
                    trace!("thread: Code executed okay.");
                }
            }
        },

        LuaQuery::ExecuteFile(name) => {
            trace!("thread: Received request to execute file {}", name);
            info!("thread: Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("thread: Error executing {}!", name);

                    thread_send(&sender, LuaResponse::Error(err));
                }
                else {
                    trace!("thread: Execution of {} successful.", name);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(&sender, LuaResponse::Error(read_error));
            }
        },

        LuaQuery::GetVariable(varname) => {
            trace!("thread: Received request to get variable {}", varname);
            let var_result = lua.get(varname.as_str());

            match var_result {
                Some(var) => {
                    thread_send(&sender, LuaResponse::Variable(Some(var)));
                }
                None => {
                    warn!("thread: Unable to get variable {}", varname);

                    thread_send(&sender, LuaResponse::Variable(None));
                }
            }
        },

        LuaQuery::SetValue { name: name, val: val } => {

        },

        LuaQuery::EmptyArray(name) => {

        },

        _ => {
            panic!("Unimplemented send type for lua thread!");
        }
    }
}

fn thread_send(sender: &Sender<LuaResponse>, response: LuaResponse) {
    trace!("Called thread_send");
    match sender.send(response) {
        Err(e) => {
            error!("thread: Unable to broadcast response!");
            error!("thread: Shutting down in response to inability \
                    to continue!");
            panic!("Lua thread unable to communicate with main thread, \
                    shutting down!");
        }
        Ok(_) => {}
    }
}
<|endoftext|>


<commit_before>use unix_socket::UnixStream;

use std::io;
use std::io::{Read, Write};

const LVMETAD_PATH: &'static str = "/run/lvm/lvmetad.socket";

fn response(stream: &mut UnixStream) -> io::Result<Vec<u8>> {
    let mut response = [0; 32];
    let mut v = Vec::new();

    loop {
        let bytes_read = try!(stream.read(&mut response));

        v.extend(&response[..bytes_read]);

        if v.ends_with(b"\n##\n") {
            // drop the end marker
            let len = v.len() - 4;
            v.truncate(len);
            return Ok(v);
        }
    }
}

fn open_lvmetad() {

    request(b"hello", false);
//    lvmetad_request(b"vg_list", true);
//    lvmetad_request(b"pv_list", true);
//    lvmetad_request(b"dump", false);

}

pub fn request(s: &[u8], token: bool) -> io::Result<Vec<u8>>{

    let mut stream = UnixStream::connect(LVMETAD_PATH).unwrap();
    stream.write_all(b"request = \"").unwrap();
    stream.write_all(s).unwrap();
    stream.write_all(b"\"\n").unwrap();
    if token {
        stream.write_all(b"token = \"filter:0\"").unwrap();
        stream.write_all(b"\n").unwrap();
    }
    stream.write_all(b"\n##\n").unwrap();

    let response = try!(response(&mut stream));

    Ok(response)
}
<commit_msg>make lvmetad stuff work better<commit_after>use unix_socket::UnixStream;

use std::io::{Result, Read, Write};
use std::io::Error;
use std::io::ErrorKind::Other;

use parser::{LvmTextMap, TextMapOps, into_textmap};

const LVMETAD_PATH: &'static str = "/run/lvm/lvmetad.socket";

fn collect_response(stream: &mut UnixStream) -> Result<Vec<u8>> {
    let mut response = [0; 32];
    let mut v = Vec::new();

    loop {
        let bytes_read = try!(stream.read(&mut response));

        v.extend(&response[..bytes_read]);

        if v.ends_with(b"\n##\n") {
            // drop the end marker
            let len = v.len() - 4;
            v.truncate(len);
            return Ok(v);
        }
    }
}

pub fn _request(s: &[u8], token: Option<&[u8]>, stream: &mut UnixStream, args: Option<&[&[u8]]>) -> Result<Vec<u8>> {
    try!(stream.write_all(b"request = \""));
    try!(stream.write_all(s));
    try!(stream.write_all(b"\"\n"));
    if let Some(token) = token {
        try!(stream.write_all(b"token = \""));
        try!(stream.write_all(token));
        try!(stream.write_all(b"\"\n"));
        try!(stream.write_all(b"\n"));
    }
    if let Some(args) = args {
        for arg in args {
            try!(stream.write_all(arg));
            try!(stream.write_all(b"\n"));
        }
    }

    try!(stream.write_all(b"\n##\n"));

    collect_response(stream)
}

pub fn request(s: &[u8], args: Option<&[&[u8]]>) -> Result<LvmTextMap> {
    let err = || Error::new(Other, "response parsing error");
    let token = b"0";

    let mut stream = try!(UnixStream::connect(LVMETAD_PATH));

    let mut response = try!(_request(s, Some(token), &mut stream, args)
        .and_then(|r| into_textmap(&r)));

    if try!(response.string_from_textmap("response").ok_or(err())) == "token_mismatch" {
        try!(_request(b"token_update", Some(token), &mut stream, None));
        response = try!(_request(s, Some(token), &mut stream, args)
            .and_then(|r| into_textmap(&r)));
    }

    if try!(response.string_from_textmap("response").ok_or(err())) != "OK" {
        let reason = match response.string_from_textmap("reason") {
            Some(x) => x,
            None => "no reason given",
        };
        return Err(Error::new(Other, reason));
    }

    response.remove("response");

    Ok(response)
}
<|endoftext|>


<commit_before>extern crate itertools;
use itertools::Itertools;

/// Encrypt the input string using square cryptography
pub fn encrypt(input: &str) -> String {
    let prepared = prepare(input);
    if prepared.is_empty() {
        return String::new();
    }

    let (cols, rows) = dimensions(prepared.len());

    let mut output = String::with_capacity(input.len());
    for chunk_iterator in SquareIndexer::new(rows, cols).chunks(cols).into_iter() {
        for ch_idx in chunk_iterator {
            if ch_idx < prepared.len() {
                output.push(prepared[ch_idx]);
            }
        }
        output.push(' ');
    }

    // we know there's one extra space at the end
    output.pop();

    output
}

/// Construct a vector of characters from the given input.
///
/// Constrain it to the allowed chars: lowercase ascii letters.
/// We construct a vector here because the length of the input
/// matters when constructing the output, so we need to know
/// how many input chars there are. We could treat it as a stream
/// and just stream twice, but collecting it into a vector works
/// equally well and might be a bit faster.
fn prepare(input: &str) -> Vec<char> {
    let mut output = Vec::with_capacity(input.len());

    output.extend(
        input
            .chars()
            .filter(|&c| c.is_ascii() && !c.is_whitespace() && !c.is_ascii_punctuation())
            .map(|c| c.to_ascii_lowercase()),
    );

    // add space padding to the end such that the actual string returned
    // forms a perfect rectangle
    let (r, c) = dimensions(output.len());
    let padding_qty = (r * c) - output.len();
    for _ in 0..padding_qty {
        output.push(' ');
    }

    output.shrink_to_fit();

    output
}

/// Get the dimensions of the appropriate bounding rectangle for this encryption
///
/// To find `(rows, cols)` such that `cols >= rows && cols - rows <= 1`, we find
/// the least square greater than or equal to the message length. Its square root
/// is the cols. If the message length is a perfect square, `rows` is the same.
/// Otherwise, it is one less.
fn dimensions(length: usize) -> (usize, usize) {
    let cols = (length as f64).sqrt().ceil() as usize;
    let rows = if cols * cols == length {
        cols
    } else {
        cols - 1
    };
    (rows, cols)
}

/// Iterator over the indices of the appropriate chars of the output.
///
/// For a (2, 3) (r, c) grid, yields (0, 3, 1, 4, 2, 5).
/// Does no bounds checking or space insertion: that's handled elsewhere.
#[derive(Debug)]
struct SquareIndexer {
    rows: usize,
    cols: usize,
    cur_row: usize,
    cur_col: usize,
    max_value: usize,
}

impl SquareIndexer {
    fn new(rows: usize, cols: usize) -> SquareIndexer {
        SquareIndexer {
            rows,
            cols,
            cur_row: 0,
            cur_col: 0,
            max_value: rows * cols,
        }
    }
}

impl Iterator for SquareIndexer {
    type Item = usize;
    fn next(&mut self) -> Option<usize> {
        let value = self.cur_row + (self.cur_col * self.rows);
        let output = if value < self.max_value && self.cur_row < self.rows {
            Some(value)
        } else {
            None
        };

        // now increment internal state to next value
        self.cur_col += 1;
        if self.cur_col >= self.cols {
            self.cur_col = 0;
            self.cur_row += 1;
        }

        output
    }
}
<commit_msg>crypto-square: replace repeated push with resize (#1025)<commit_after>extern crate itertools;
use itertools::Itertools;

/// Encrypt the input string using square cryptography
pub fn encrypt(input: &str) -> String {
    let prepared = prepare(input);
    if prepared.is_empty() {
        return String::new();
    }

    let (cols, rows) = dimensions(prepared.len());

    let mut output = String::with_capacity(input.len());
    for chunk_iterator in SquareIndexer::new(rows, cols).chunks(cols).into_iter() {
        for ch_idx in chunk_iterator {
            if ch_idx < prepared.len() {
                output.push(prepared[ch_idx]);
            }
        }
        output.push(' ');
    }

    // we know there's one extra space at the end
    output.pop();

    output
}

/// Construct a vector of characters from the given input.
///
/// Constrain it to the allowed chars: lowercase ascii letters.
/// We construct a vector here because the length of the input
/// matters when constructing the output, so we need to know
/// how many input chars there are. We could treat it as a stream
/// and just stream twice, but collecting it into a vector works
/// equally well and might be a bit faster.
fn prepare(input: &str) -> Vec<char> {
    let mut output = Vec::with_capacity(input.len());

    output.extend(
        input
            .chars()
            .filter(|&c| c.is_ascii() && !c.is_whitespace() && !c.is_ascii_punctuation())
            .map(|c| c.to_ascii_lowercase()),
    );

    // add space padding to the end such that the actual string returned
    // forms a perfect rectangle
    let (r, c) = dimensions(output.len());
    output.resize(r * c, ' ');

    output.shrink_to_fit();

    output
}

/// Get the dimensions of the appropriate bounding rectangle for this encryption
///
/// To find `(rows, cols)` such that `cols >= rows && cols - rows <= 1`, we find
/// the least square greater than or equal to the message length. Its square root
/// is the cols. If the message length is a perfect square, `rows` is the same.
/// Otherwise, it is one less.
fn dimensions(length: usize) -> (usize, usize) {
    let cols = (length as f64).sqrt().ceil() as usize;
    let rows = if cols * cols == length {
        cols
    } else {
        cols - 1
    };
    (rows, cols)
}

/// Iterator over the indices of the appropriate chars of the output.
///
/// For a (2, 3) (r, c) grid, yields (0, 3, 1, 4, 2, 5).
/// Does no bounds checking or space insertion: that's handled elsewhere.
#[derive(Debug)]
struct SquareIndexer {
    rows: usize,
    cols: usize,
    cur_row: usize,
    cur_col: usize,
    max_value: usize,
}

impl SquareIndexer {
    fn new(rows: usize, cols: usize) -> SquareIndexer {
        SquareIndexer {
            rows,
            cols,
            cur_row: 0,
            cur_col: 0,
            max_value: rows * cols,
        }
    }
}

impl Iterator for SquareIndexer {
    type Item = usize;
    fn next(&mut self) -> Option<usize> {
        let value = self.cur_row + (self.cur_col * self.rows);
        let output = if value < self.max_value && self.cur_row < self.rows {
            Some(value)
        } else {
            None
        };

        // now increment internal state to next value
        self.cur_col += 1;
        if self.cur_col >= self.cols {
            self.cur_col = 0;
            self.cur_row += 1;
        }

        output
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use super::{Drawable, BoundingBox, MeasureMode};
use ::platform::Context;
use ::paint::{Canvas, Point, Rect};
use std::cmp::Ordering;
use std::slice::{Iter, IterMut};

pub struct AbsoluteLayout<'a> {
    children: Vec<Child<'a>>,
    bounding_box: BoundingBox,

    baseline: Option<f32>,
    axis: Option<f32>,
}

pub struct Child<'a> {
    drawable: Box<Drawable+'a>,
    params: AbsoluteLayoutParams
}

impl<'a> Child<'a> {
    pub fn drawable(&self) -> &Drawable {
        self.drawable.as_ref()
    }

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

pub struct AbsoluteLayoutParams {
    position: Point
}

impl AbsoluteLayoutParams {
    pub fn new(point: Point) -> AbsoluteLayoutParams {
        AbsoluteLayoutParams { position: point }
    }
}

impl<'a> Drawable for AbsoluteLayout<'a> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        for child in &self.children {
            child.drawable.draw(canvas, &(pen_pos+&child.params.position))
        }
    }

    fn calculate(&mut self, context: &Context, _: &MeasureMode, _: &MeasureMode) {
        for child in self.children.iter_mut() {
            child.drawable.calculate(context, &MeasureMode::Wrap,&MeasureMode::Wrap);
        }

        let end_x_calc = |child: &Child|
            child.drawable.bounding_box().width() + child.params.position.x();

        let width = self.children.iter().max_by(|c1, c2| {
            end_x_calc(*c1).partial_cmp(&end_x_calc(*c2)).unwrap_or(Ordering::Less)
        }).and_then(|c| {
            Some(end_x_calc(c))
        }).unwrap_or(0f32);

        let end_y_calc = |child: &Child|
            child.drawable.bounding_box().height() + child.params.position.y();

        let height = self.children.iter().max_by(|c1, c2| {
            end_y_calc(*c1).partial_cmp(&end_y_calc(*c2)).unwrap_or(Ordering::Less)
        }).and_then(|c| {
            Some(end_y_calc(c))
        }).unwrap_or(0f32);

        self.bounding_box = BoundingBox {
            rect: Rect::new(width, height),
            baseline: self.baseline.unwrap_or(height),
            axis: self.axis.unwrap_or(height/2f32),
        }
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}

impl<'a> AbsoluteLayout<'a> {
    pub fn new() -> AbsoluteLayout<'a> {
        AbsoluteLayout {
            children: Vec::new(),
            bounding_box: BoundingBox::default(),
            baseline: None,
            axis: None,
        }
    }

    pub fn add_child(&mut self, child: Box<Drawable + 'a>, params: AbsoluteLayoutParams) {
        self.children.push(Child { drawable: child, params });
    }

    pub fn remove_child_at(&mut self, index: usize) {
        self.children.remove(index);
    }

    pub fn clear(&mut self) {
        self.children.clear();
    }

    pub fn set_baseline(&mut self, baseline: Option<f32>) {
        self.baseline = baseline;
    }

    pub fn set_axis(&mut self, axis: Option<f32>) {
        self.axis = axis;
    }

    pub fn set_child_params(&mut self, index: usize, params: AbsoluteLayoutParams) {
        if let Some(val) = self.children.get_mut(index) {
            val.params = params;
        }
    }

    pub fn iter(&self) -> Iter<Child<'a>> {
        self.children.iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<Child<'a>> {
        self.children.iter_mut()
    }
}<commit_msg>API to disable calculating child layout<commit_after>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use super::{Drawable, BoundingBox, MeasureMode};
use ::platform::Context;
use ::paint::{Canvas, Point, Rect};
use std::cmp::Ordering;
use std::slice::{Iter, IterMut};

pub struct AbsoluteLayout<'a> {
    children: Vec<Child<'a>>,
    bounding_box: BoundingBox,

    baseline: Option<f32>,
    axis: Option<f32>,

    calculate_child_bounds: bool,
}

pub struct Child<'a> {
    drawable: Box<Drawable+'a>,
    params: AbsoluteLayoutParams
}

impl<'a> Child<'a> {
    pub fn drawable(&self) -> &Drawable {
        self.drawable.as_ref()
    }

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

pub struct AbsoluteLayoutParams {
    position: Point
}

impl AbsoluteLayoutParams {
    pub fn new(point: Point) -> AbsoluteLayoutParams {
        AbsoluteLayoutParams { position: point }
    }
}

impl<'a> Drawable for AbsoluteLayout<'a> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        for child in &self.children {
            child.drawable.draw(canvas, &(pen_pos+&child.params.position))
        }
    }

    fn calculate(&mut self, context: &Context, _: &MeasureMode, _: &MeasureMode) {
        if self.calculate_child_bounds {
            for child in self.children.iter_mut() {
                child.drawable.calculate(context, &MeasureMode::Wrap,&MeasureMode::Wrap);
            }
        }

        let end_x_calc = |child: &Child|
            child.drawable.bounding_box().width() + child.params.position.x();

        let width = self.children.iter().max_by(|c1, c2| {
            end_x_calc(*c1).partial_cmp(&end_x_calc(*c2)).unwrap_or(Ordering::Less)
        }).and_then(|c| {
            Some(end_x_calc(c))
        }).unwrap_or(0f32);

        let end_y_calc = |child: &Child|
            child.drawable.bounding_box().height() + child.params.position.y();

        let height = self.children.iter().max_by(|c1, c2| {
            end_y_calc(*c1).partial_cmp(&end_y_calc(*c2)).unwrap_or(Ordering::Less)
        }).and_then(|c| {
            Some(end_y_calc(c))
        }).unwrap_or(0f32);

        self.bounding_box = BoundingBox {
            rect: Rect::new(width, height),
            baseline: self.baseline.unwrap_or(height),
            axis: self.axis.unwrap_or(height/2f32),
        }
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}

impl<'a> AbsoluteLayout<'a> {
    pub fn new() -> AbsoluteLayout<'a> {
        AbsoluteLayout {
            children: Vec::new(),
            bounding_box: BoundingBox::default(),
            baseline: None,
            axis: None,
            calculate_child_bounds: true
        }
    }

    pub fn add_child(&mut self, child: Box<Drawable + 'a>, params: AbsoluteLayoutParams) {
        self.children.push(Child { drawable: child, params });
    }

    pub fn remove_child_at(&mut self, index: usize) {
        self.children.remove(index);
    }

    pub fn clear(&mut self) {
        self.children.clear();
    }

    pub fn set_baseline(&mut self, baseline: Option<f32>) {
        self.baseline = baseline;
    }

    pub fn set_axis(&mut self, axis: Option<f32>) {
        self.axis = axis;
    }

    pub fn set_child_params(&mut self, index: usize, params: AbsoluteLayoutParams) {
        if let Some(val) = self.children.get_mut(index) {
            val.params = params;
        }
    }

    pub fn iter(&self) -> Iter<Child<'a>> {
        self.children.iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<Child<'a>> {
        self.children.iter_mut()
    }

    pub fn should_calculate_child_bounds(&mut self, calculate: bool) {
        self.calculate_child_bounds = calculate;
    }

    pub fn is_calculating_child_bounds(&self) -> bool {
        self.calculate_child_bounds
    }
}<|endoftext|>


<commit_before>use std::rc::Rc;

use super::super::api::*;
use super::super::rel::*;
use super::super::exec::*;

pub struct SqrtFunction {
}

impl ScalarFunction for SqrtFunction {

    fn name(&self) -> String {
        "sqrt".to_string()
    }

    fn execute(&self, args: Vec<Rc<ColumnData>>) -> Result<Rc<ColumnData>,Box<String>> {
        match args[0].as_ref() {
            &ColumnData::Float(ref v) => Ok(Rc::new(ColumnData::Float(v.iter().map(|v| v.sqrt()).collect()))),
            &ColumnData::Double(ref v) => Ok(Rc::new(ColumnData::Double(v.iter().map(|v| v.sqrt()).collect()))),
//            &ColumnData::Int(ref v) => Ok(ColumnData::Int(v.iter().map(|v| v.sqrt()).collect())),
//            &ColumnData::UnsignedInt(ref v) => Ok(ColumnData::UnsignedInt(v.iter().map(|v| v.sqrt()).collect())),
//            &ColumnData::Long(ref v) => Ok(ColumnData::Long(v.iter().map(|v| v.sqrt()).collect())),
//            &ColumnData::UnsignedLong(ref v) => Ok(ColumnData::UnsignedLong(v.iter().map(|v| v.sqrt()).collect())),
            _ => Err(Box::new("Unsupported arg type for sqrt".to_string()))
        }
    }

    fn args(&self) -> Vec<Field> {
        vec![
            Field::new("x", DataType::Double, false),
            Field::new("y", DataType::Double, false)
        ]
    }

    fn return_type(&self) -> DataType {
        DataType::Double
    }
}

<commit_msg>fix test regression<commit_after>use std::rc::Rc;

use super::super::api::*;
use super::super::rel::*;
use super::super::exec::*;

pub struct SqrtFunction {
}

impl ScalarFunction for SqrtFunction {

    fn name(&self) -> String {
        "sqrt".to_string()
    }

    fn execute(&self, args: Vec<Rc<ColumnData>>) -> Result<Rc<ColumnData>,Box<String>> {
        match args[0].as_ref() {
            &ColumnData::Float(ref v) => Ok(Rc::new(ColumnData::Float(v.iter().map(|v| v.sqrt()).collect()))),
            &ColumnData::Double(ref v) => Ok(Rc::new(ColumnData::Double(v.iter().map(|v| v.sqrt()).collect()))),
            &ColumnData::Int(ref v) => Ok(Rc::new(ColumnData::Double(v.iter().map(|v| (*v as f64).sqrt()).collect()))),
            &ColumnData::UnsignedInt(ref v) => Ok(Rc::new(ColumnData::Double(v.iter().map(|v| (*v as f64).sqrt()).collect()))),
            &ColumnData::Long(ref v) => Ok(Rc::new(ColumnData::Double(v.iter().map(|v| (*v as f64).sqrt()).collect()))),
            &ColumnData::UnsignedLong(ref v) => Ok(Rc::new(ColumnData::Double(v.iter().map(|v| (*v as f64).sqrt()).collect()))),
            _ => Err(Box::new("Unsupported arg type for sqrt".to_string()))
        }
    }

    fn args(&self) -> Vec<Field> {
        vec![
            Field::new("x", DataType::Double, false),
            Field::new("y", DataType::Double, false)
        ]
    }

    fn return_type(&self) -> DataType {
        DataType::Double
    }
}

<|endoftext|>


<commit_before>use std::ptr;

use gc::swiper::CardIdx;
use gc::swiper::{CARD_SIZE, CARD_SIZE_BITS};
use gc::Address;
use gc::swiper::Region;

use mem;

#[derive(Clone)]
pub struct CardTable {
    // card table boundaries for old gen (not young gen)
    // table is actually larger but we shouldn't need
    // to touch the rest
    start: Address,
    end: Address,

    // contiguous region with old generation and large space
    old_and_large: Region,

    // end of old generation and start of large space
    old_end: Address,
}

impl CardTable {
    pub fn new(start: Address, end: Address, old_and_large: Region, old_end: Address, young_size: usize) -> CardTable {
        // only keep track of card table for old gen,
        // just ignore the card table for the young gen
        let start = start.offset(young_size >> CARD_SIZE_BITS);

        let card = CardTable {
            start: start,
            end: end,
            old_and_large: old_and_large,
            old_end: old_end,
        };

        // reset card table to all 1's
        card.reset();

        card
    }

    // reset card table entries to 1 (not dirty)
    fn reset(&self) {
        let size = self.size();

        unsafe {
            ptr::write_bytes(self.start.to_mut_ptr::<u8>(), 1, size);
        }
    }

    fn size(&self) -> usize {
        self.end.offset_from(self.start)
    }

    // visits all dirty cards in region
    pub fn visit_dirty_in_old<F>(&self, end: Address, mut f: F)
    where
        F: FnMut(CardIdx),
    {
        assert!(end >= self.old_and_large.start && end <= self.old_end);
        let mut ptr = self.start;

        let no_cards = number_of_cards(end.offset_from(self.old_and_large.start));
        let end = self.start.offset(no_cards);

        while ptr < end {
            let val: u8 = unsafe { *ptr.to_ptr() };

            if val == 0 {
                f(CardIdx::from(ptr.offset_from(self.start)));
            }

            ptr = ptr.offset(1);
        }
    }

    pub fn get(&self, card: CardIdx) -> CardEntry {
        let ptr = self.start.offset(card.to_usize());
        debug_assert!(ptr < self.end);

        let val: u8 = unsafe { *ptr.to_ptr() };

        if val == 0 {
            CardEntry::Dirty
        } else {
            CardEntry::Clean
        }
    }

    pub fn set(&self, card: CardIdx, entry: CardEntry) {
        let ptr = self.start.offset(card.to_usize());
        debug_assert!(ptr < self.end);

        let val: u8 = match entry {
            CardEntry::Clean => 1,
            CardEntry::Dirty => 0,
        };

        unsafe {
            *ptr.to_mut_ptr() = val;
        }
    }

    #[inline(always)]
    pub fn is_aligned(&self, addr: Address) -> bool {
        (addr.offset_from(self.old_and_large.start) & !(CARD_SIZE - 1)) == 0
    }

    #[inline(always)]
    pub fn to_address(&self, card: CardIdx) -> Address {
        self.old_and_large.start.offset(card.to_usize() << CARD_SIZE_BITS)
    }

    #[inline(always)]
    fn card_idx_usize(&self, addr: usize) -> CardIdx {
        self.card_idx(Address::from(addr))
    }

    #[inline(always)]
    pub fn card_idx(&self, addr: Address) -> CardIdx {
        debug_assert!(self.old_and_large.contains(addr));
        let idx = addr.offset_from(self.old_and_large.start) >> CARD_SIZE_BITS;

        idx.into()
    }
}

fn number_of_cards(size: usize) -> usize {
    mem::align_usize(size, CARD_SIZE)
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum CardEntry {
    Clean,
    Dirty,
}

impl CardEntry {
    pub fn is_clean(self) -> bool {
        self == CardEntry::Clean
    }

    pub fn is_dirty(self) -> bool {
        self == CardEntry::Dirty
    }
}
<commit_msg>swiper: remove card_idx_usize<commit_after>use std::ptr;

use gc::swiper::CardIdx;
use gc::swiper::{CARD_SIZE, CARD_SIZE_BITS};
use gc::Address;
use gc::swiper::Region;

use mem;

#[derive(Clone)]
pub struct CardTable {
    // card table boundaries for old gen (not young gen)
    // table is actually larger but we shouldn't need
    // to touch the rest
    start: Address,
    end: Address,

    // contiguous region with old generation and large space
    old_and_large: Region,

    // end of old generation and start of large space
    old_end: Address,
}

impl CardTable {
    pub fn new(start: Address, end: Address, old_and_large: Region, old_end: Address, young_size: usize) -> CardTable {
        // only keep track of card table for old gen,
        // just ignore the card table for the young gen
        let start = start.offset(young_size >> CARD_SIZE_BITS);

        let card = CardTable {
            start: start,
            end: end,
            old_and_large: old_and_large,
            old_end: old_end,
        };

        // reset card table to all 1's
        card.reset();

        card
    }

    // reset card table entries to 1 (not dirty)
    fn reset(&self) {
        let size = self.size();

        unsafe {
            ptr::write_bytes(self.start.to_mut_ptr::<u8>(), 1, size);
        }
    }

    fn size(&self) -> usize {
        self.end.offset_from(self.start)
    }

    // visits all dirty cards in region
    pub fn visit_dirty_in_old<F>(&self, end: Address, mut f: F)
    where
        F: FnMut(CardIdx),
    {
        assert!(end >= self.old_and_large.start && end <= self.old_end);
        let mut ptr = self.start;

        let no_cards = number_of_cards(end.offset_from(self.old_and_large.start));
        let end = self.start.offset(no_cards);

        while ptr < end {
            let val: u8 = unsafe { *ptr.to_ptr() };

            if val == 0 {
                f(CardIdx::from(ptr.offset_from(self.start)));
            }

            ptr = ptr.offset(1);
        }
    }

    pub fn get(&self, card: CardIdx) -> CardEntry {
        let ptr = self.start.offset(card.to_usize());
        debug_assert!(ptr < self.end);

        let val: u8 = unsafe { *ptr.to_ptr() };

        if val == 0 {
            CardEntry::Dirty
        } else {
            CardEntry::Clean
        }
    }

    pub fn set(&self, card: CardIdx, entry: CardEntry) {
        let ptr = self.start.offset(card.to_usize());
        debug_assert!(ptr < self.end);

        let val: u8 = match entry {
            CardEntry::Clean => 1,
            CardEntry::Dirty => 0,
        };

        unsafe {
            *ptr.to_mut_ptr() = val;
        }
    }

    #[inline(always)]
    pub fn is_aligned(&self, addr: Address) -> bool {
        (addr.offset_from(self.old_and_large.start) & !(CARD_SIZE - 1)) == 0
    }

    #[inline(always)]
    pub fn to_address(&self, card: CardIdx) -> Address {
        self.old_and_large.start.offset(card.to_usize() << CARD_SIZE_BITS)
    }

    #[inline(always)]
    pub fn card_idx(&self, addr: Address) -> CardIdx {
        debug_assert!(self.old_and_large.contains(addr));
        let idx = addr.offset_from(self.old_and_large.start) >> CARD_SIZE_BITS;

        idx.into()
    }
}

fn number_of_cards(size: usize) -> usize {
    mem::align_usize(size, CARD_SIZE)
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum CardEntry {
    Clean,
    Dirty,
}

impl CardEntry {
    pub fn is_clean(self) -> bool {
        self == CardEntry::Clean
    }

    pub fn is_dirty(self) -> bool {
        self == CardEntry::Dirty
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::sync::atomic::Ordering;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::space::Space;
use gc::swiper::card::{CardEntry, CardTable};
use gc::swiper::{CARD_SIZE, CARD_SIZE_BITS};
use gc::swiper::crossing::CrossingMap;
use gc::swiper::old::OldGen;
use gc::swiper::Region;
use gc::swiper::young::YoungGen;
use mem;
use object::Obj;
use os;
use timer::{in_ms, Timer};

pub struct FullCollector<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    rootset: &'a [IndirectObj],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    marking_bitmap: MarkingBitmap,
    fwd_table: HashMap<Address, Address>,
    young_refs_set: HashSet<Address>,

    fwd: Address,
    fwd_end: Address,
    old_top: Address,
}

impl<'a, 'ast> FullCollector<'a, 'ast> {
    pub fn new(
        ctxt: &'a SemContext<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [IndirectObj],
    ) -> FullCollector<'a, 'ast> {
        let marking_bitmap = MarkingBitmap::new(heap.clone());

        FullCollector {
            ctxt: ctxt,
            heap: heap,
            young: young,
            old: old,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            marking_bitmap: marking_bitmap,
            fwd_table: HashMap::new(),
            young_refs_set: HashSet::new(),

            fwd: old.total.start,
            fwd_end: old.total.end,
            old_top: Address::null(),
        }
    }

    pub fn collect(&mut self) {
        let mut timer = Timer::new(self.ctxt.args.flag_gc_verbose);
        let init_size = self.old.used_region().size();

        self.mark_live();
        self.compute_forward();
        self.update_references();
        self.relocate();

        timer.stop_with(|dur| {
            let new_size = self.old.used_region().size();
            println!("GC: Full GC ({} ms, {}K->{}K size)",
                in_ms(dur), init_size / 1024, new_size / 1024);
        });
    }

    fn mark_live(&mut self) {
        let mut marking_stack: Vec<Address> = Vec::new();

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if self.heap.contains(root_ptr) {
                marking_stack.push(root_ptr);

            } else {
                debug_assert!(root_ptr.is_null() || self.perm_space.contains(root_ptr));
            }
        }

        while marking_stack.len() > 0 {
            let object_addr = marking_stack.pop().expect("stack already empty");
            let object = unsafe { &mut *object_addr.to_mut_ptr::<Obj>() };
            self.mark(object_addr);

            object.visit_reference_fields(|field| {
                let field_addr = Address::from_ptr(field.get());

                if self.heap.contains(field_addr) {
                    if !self.is_marked_addr(field_addr) {
                        marking_stack.push(field_addr);
                        self.mark(field_addr);
                    }

                } else {
                    debug_assert!(field_addr.is_null() || self.perm_space.contains(field_addr));
                }
            });
        }
    }

    fn compute_forward(&mut self) {
        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let fwd = full.allocate(object_size);
                full.fwd_table.insert(address, fwd);
            }
        });
    }

    fn update_references(&mut self) {
        self.walk_old_and_young(|full, object, address, _| {
            if full.is_marked(object) {
                let mut young_refs = false;

                object.visit_reference_fields(|field| {
                    let field_addr = Address::from_ptr(field.get());

                    if !field_addr.is_null() && !full.perm_space.contains(field_addr) {
                        let &fwd_addr = full.fwd_table.get(&field_addr).expect("forwarding address not found.");
                        field.set(fwd_addr.to_mut_ptr());

                        if full.young.contains(fwd_addr) {
                            young_refs = true;
                        }
                    }
                });

                if young_refs {
                    full.young_refs_set.insert(address);
                }
            }
        });

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if !root_ptr.is_null() && !self.perm_space.contains(root_ptr) {
                let fwd_addr = self.fwd_table.get(&root_ptr).expect("forwarding address not found.");
                root.set(fwd_addr.to_mut_ptr());
            }
        }
    }

    fn relocate(&mut self) {
        self.young.unprotect_to_space();

        self.crossing_map.set_first_object(0.into(), 0);
        let mut young_refs = false;
        let mut last_dest = Address::null();

        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let &dest = full.fwd_table.get(&address).expect("forwarding address not found.");
                object.copy_to(dest, object_size);

                if !young_refs {
                    young_refs = full.young_refs_set.contains(&address);
                }

                let next_dest = dest.offset(object_size);

                if on_different_cards(dest, next_dest) && full.old.contains(dest) {
                    full.update_crossing(next_dest);
                    full.update_card(dest, &mut young_refs);
                }

                last_dest = next_dest;
            }
        });

        if !last_dest.is_null() && !start_of_card(last_dest) && self.old.contains(last_dest) {
            self.update_card(last_dest, &mut young_refs);
        }

        let young_top;
        let old_top;

        // check if we have left the old-generation into
        // the young generation for copying objects
        if self.old_top.is_null() {
            // if not, young gen is empty
            young_top = self.young.to_space().start;
            old_top = self.fwd;

        } else {
            young_top = self.fwd;
            old_top = self.old_top;
        }

        debug_assert!(self.young.contains(young_top));
        self.young.swap_spaces(young_top);
        self.young.protect_to_space();

        debug_assert!(self.old.contains(old_top));
        self.old.free.store(old_top.to_usize(), Ordering::SeqCst);
    }

    fn walk_old_and_young<F>(&mut self, mut fct: F) where F: FnMut(&mut FullCollector, &mut Obj, Address, usize) {
        let used_region = self.old.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);

        let used_region = self.young.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);
    }

    fn walk_region<F>(&mut self, start: Address, end: Address, fct: &mut F) where F: FnMut(&mut FullCollector, &mut Obj, Address, usize) {
        let mut scan = start;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            fct(self, object, scan, object_size);

            scan = scan.offset(object_size);
        }
    }

    fn allocate(&mut self, object_size: usize) -> Address {
        let addr = self.fwd;
        let next = self.fwd.offset(object_size);

        if next <= self.fwd_end {
            self.fwd = next;
            return addr;
        }

        assert!(self.fwd_end == self.old.total.end);
        self.old_top = self.fwd;

        let young = self.young.to_space();
        self.fwd = young.start.offset(object_size);
        self.fwd_end = young.end;

        young.start
    }

    fn update_crossing(&mut self, addr: Address) {
        let offset = addr.to_usize() & (CARD_SIZE - 1);
        let offset_words = offset / (mem::ptr_width() as usize);

        let card = self.old.card_from_address(addr);

        self.crossing_map.set_first_object(card, offset_words);
    }

    fn update_card(&mut self, addr: Address, young_refs: &mut bool) {
        let card = self.old.card_from_address(addr);

        let card_entry = if *young_refs { CardEntry::Dirty } else { CardEntry:: Clean };
        self.card_table.set(card, card_entry);

        *young_refs = false;
    }

    fn is_marked(&self, obj: &Obj) -> bool {
        self.marking_bitmap.is_marked(Address::from_ptr(obj as *const _))
    }

    fn is_marked_addr(&self, addr: Address) -> bool {
        self.marking_bitmap.is_marked(addr)
    }

    fn mark(&mut self, addr: Address) {
        self.marking_bitmap.mark(addr);
    }
}

fn on_different_cards(curr: Address, next: Address) -> bool {
    (curr.to_usize() >> CARD_SIZE_BITS) != (next.to_usize() >> CARD_SIZE_BITS)
}

fn start_of_card(addr: Address) -> bool {
    (addr.to_usize() & (CARD_SIZE - 1)) == addr.to_usize()
}

pub struct MarkingBitmap {
    heap: Region,
    bitmap: Region,
}

impl MarkingBitmap {
    pub fn new(heap: Region) -> MarkingBitmap {
        let bitmap_size = mem::page_align(heap.size() / mem::ptr_width_usize() / 8);
        let bitmap_start = Address::from_ptr(os::mmap(bitmap_size, os::Writable));

        if bitmap_start.is_null() {
            panic!("could not allocate marking bitmap.");
        }

        MarkingBitmap {
            heap: heap,
            bitmap: Region::new(bitmap_start, bitmap_start.offset(bitmap_size)),
        }
    }

    pub fn mark(&mut self, addr: Address) {
        let (byte_offset, bit_offset) = self.mark_offset(addr);

        let byte = self.mark_byte(byte_offset);
        let modified_byte = byte | (1 << bit_offset);
        self.set_mark_byte(byte_offset, modified_byte);
    }

    pub fn is_marked(&self, addr: Address) -> bool {
        let (byte_offset, bit_offset) = self.mark_offset(addr);
        let byte = self.mark_byte(byte_offset);

        byte & (1 << bit_offset) != 0
    }

    fn mark_offset(&self, addr: Address) -> (usize, u8) {
        debug_assert!(self.heap.contains(addr));
        let offset = addr.offset_from(self.heap.start) / mem::ptr_width_usize();
        let byte = offset / 8;
        let bit = offset % 8;

        (byte, bit as u8)
    }

    fn mark_byte(&self, offset: usize) -> u8 {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_ptr()
        }
    }

    fn set_mark_byte(&self, offset: usize, val: u8) {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_mut_ptr() = val;
        }
    }
}

impl Drop for MarkingBitmap {
    fn drop(&mut self) {
        os::munmap(self.bitmap.start.to_ptr(), self.bitmap.size());
    }
}<commit_msg>swiper: round up size in kilo<commit_after>use std::collections::{HashMap, HashSet};
use std::sync::atomic::Ordering;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::space::Space;
use gc::swiper::card::{CardEntry, CardTable};
use gc::swiper::{CARD_SIZE, CARD_SIZE_BITS};
use gc::swiper::crossing::CrossingMap;
use gc::swiper::old::OldGen;
use gc::swiper::Region;
use gc::swiper::young::YoungGen;
use mem;
use object::Obj;
use os;
use timer::{in_ms, Timer};

pub struct FullCollector<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    rootset: &'a [IndirectObj],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    marking_bitmap: MarkingBitmap,
    fwd_table: HashMap<Address, Address>,
    young_refs_set: HashSet<Address>,

    fwd: Address,
    fwd_end: Address,
    old_top: Address,
}

impl<'a, 'ast> FullCollector<'a, 'ast> {
    pub fn new(
        ctxt: &'a SemContext<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [IndirectObj],
    ) -> FullCollector<'a, 'ast> {
        let marking_bitmap = MarkingBitmap::new(heap.clone());

        FullCollector {
            ctxt: ctxt,
            heap: heap,
            young: young,
            old: old,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            marking_bitmap: marking_bitmap,
            fwd_table: HashMap::new(),
            young_refs_set: HashSet::new(),

            fwd: old.total.start,
            fwd_end: old.total.end,
            old_top: Address::null(),
        }
    }

    pub fn collect(&mut self) {
        let mut timer = Timer::new(self.ctxt.args.flag_gc_verbose);
        let init_size = self.old.used_region().size();

        self.mark_live();
        self.compute_forward();
        self.update_references();
        self.relocate();

        timer.stop_with(|dur| {
            let new_size = self.old.used_region().size();

            println!("GC: Full GC ({} ms, {}K->{}K size)",
                in_ms(dur), in_kilo(init_size), in_kilo(new_size));
        });
    }

    fn mark_live(&mut self) {
        let mut marking_stack: Vec<Address> = Vec::new();

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if self.heap.contains(root_ptr) {
                marking_stack.push(root_ptr);

            } else {
                debug_assert!(root_ptr.is_null() || self.perm_space.contains(root_ptr));
            }
        }

        while marking_stack.len() > 0 {
            let object_addr = marking_stack.pop().expect("stack already empty");
            let object = unsafe { &mut *object_addr.to_mut_ptr::<Obj>() };
            self.mark(object_addr);

            object.visit_reference_fields(|field| {
                let field_addr = Address::from_ptr(field.get());

                if self.heap.contains(field_addr) {
                    if !self.is_marked_addr(field_addr) {
                        marking_stack.push(field_addr);
                        self.mark(field_addr);
                    }

                } else {
                    debug_assert!(field_addr.is_null() || self.perm_space.contains(field_addr));
                }
            });
        }
    }

    fn compute_forward(&mut self) {
        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let fwd = full.allocate(object_size);
                full.fwd_table.insert(address, fwd);
            }
        });
    }

    fn update_references(&mut self) {
        self.walk_old_and_young(|full, object, address, _| {
            if full.is_marked(object) {
                let mut young_refs = false;

                object.visit_reference_fields(|field| {
                    let field_addr = Address::from_ptr(field.get());

                    if !field_addr.is_null() && !full.perm_space.contains(field_addr) {
                        let &fwd_addr = full.fwd_table.get(&field_addr).expect("forwarding address not found.");
                        field.set(fwd_addr.to_mut_ptr());

                        if full.young.contains(fwd_addr) {
                            young_refs = true;
                        }
                    }
                });

                if young_refs {
                    full.young_refs_set.insert(address);
                }
            }
        });

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if !root_ptr.is_null() && !self.perm_space.contains(root_ptr) {
                let fwd_addr = self.fwd_table.get(&root_ptr).expect("forwarding address not found.");
                root.set(fwd_addr.to_mut_ptr());
            }
        }
    }

    fn relocate(&mut self) {
        self.young.unprotect_to_space();

        self.crossing_map.set_first_object(0.into(), 0);
        let mut young_refs = false;
        let mut last_dest = Address::null();

        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let &dest = full.fwd_table.get(&address).expect("forwarding address not found.");
                object.copy_to(dest, object_size);

                if !young_refs {
                    young_refs = full.young_refs_set.contains(&address);
                }

                let next_dest = dest.offset(object_size);

                if on_different_cards(dest, next_dest) && full.old.contains(dest) {
                    full.update_crossing(next_dest);
                    full.update_card(dest, &mut young_refs);
                }

                last_dest = next_dest;
            }
        });

        if !last_dest.is_null() && !start_of_card(last_dest) && self.old.contains(last_dest) {
            self.update_card(last_dest, &mut young_refs);
        }

        let young_top;
        let old_top;

        // check if we have left the old-generation into
        // the young generation for copying objects
        if self.old_top.is_null() {
            // if not, young gen is empty
            young_top = self.young.to_space().start;
            old_top = self.fwd;

        } else {
            young_top = self.fwd;
            old_top = self.old_top;
        }

        debug_assert!(self.young.contains(young_top));
        self.young.swap_spaces(young_top);
        self.young.protect_to_space();

        debug_assert!(self.old.contains(old_top));
        self.old.free.store(old_top.to_usize(), Ordering::SeqCst);
    }

    fn walk_old_and_young<F>(&mut self, mut fct: F) where F: FnMut(&mut FullCollector, &mut Obj, Address, usize) {
        let used_region = self.old.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);

        let used_region = self.young.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);
    }

    fn walk_region<F>(&mut self, start: Address, end: Address, fct: &mut F) where F: FnMut(&mut FullCollector, &mut Obj, Address, usize) {
        let mut scan = start;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            fct(self, object, scan, object_size);

            scan = scan.offset(object_size);
        }
    }

    fn allocate(&mut self, object_size: usize) -> Address {
        let addr = self.fwd;
        let next = self.fwd.offset(object_size);

        if next <= self.fwd_end {
            self.fwd = next;
            return addr;
        }

        assert!(self.fwd_end == self.old.total.end);
        self.old_top = self.fwd;

        let young = self.young.to_space();
        self.fwd = young.start.offset(object_size);
        self.fwd_end = young.end;

        young.start
    }

    fn update_crossing(&mut self, addr: Address) {
        let offset = addr.to_usize() & (CARD_SIZE - 1);
        let offset_words = offset / (mem::ptr_width() as usize);

        let card = self.old.card_from_address(addr);

        self.crossing_map.set_first_object(card, offset_words);
    }

    fn update_card(&mut self, addr: Address, young_refs: &mut bool) {
        let card = self.old.card_from_address(addr);

        let card_entry = if *young_refs { CardEntry::Dirty } else { CardEntry:: Clean };
        self.card_table.set(card, card_entry);

        *young_refs = false;
    }

    fn is_marked(&self, obj: &Obj) -> bool {
        self.marking_bitmap.is_marked(Address::from_ptr(obj as *const _))
    }

    fn is_marked_addr(&self, addr: Address) -> bool {
        self.marking_bitmap.is_marked(addr)
    }

    fn mark(&mut self, addr: Address) {
        self.marking_bitmap.mark(addr);
    }
}

fn in_kilo(size: usize) -> usize {
    (size + 1023) / 1024
}

fn on_different_cards(curr: Address, next: Address) -> bool {
    (curr.to_usize() >> CARD_SIZE_BITS) != (next.to_usize() >> CARD_SIZE_BITS)
}

fn start_of_card(addr: Address) -> bool {
    (addr.to_usize() & (CARD_SIZE - 1)) == addr.to_usize()
}

pub struct MarkingBitmap {
    heap: Region,
    bitmap: Region,
}

impl MarkingBitmap {
    pub fn new(heap: Region) -> MarkingBitmap {
        let bitmap_size = mem::page_align(heap.size() / mem::ptr_width_usize() / 8);
        let bitmap_start = Address::from_ptr(os::mmap(bitmap_size, os::Writable));

        if bitmap_start.is_null() {
            panic!("could not allocate marking bitmap.");
        }

        MarkingBitmap {
            heap: heap,
            bitmap: Region::new(bitmap_start, bitmap_start.offset(bitmap_size)),
        }
    }

    pub fn mark(&mut self, addr: Address) {
        let (byte_offset, bit_offset) = self.mark_offset(addr);

        let byte = self.mark_byte(byte_offset);
        let modified_byte = byte | (1 << bit_offset);
        self.set_mark_byte(byte_offset, modified_byte);
    }

    pub fn is_marked(&self, addr: Address) -> bool {
        let (byte_offset, bit_offset) = self.mark_offset(addr);
        let byte = self.mark_byte(byte_offset);

        byte & (1 << bit_offset) != 0
    }

    fn mark_offset(&self, addr: Address) -> (usize, u8) {
        debug_assert!(self.heap.contains(addr));
        let offset = addr.offset_from(self.heap.start) / mem::ptr_width_usize();
        let byte = offset / 8;
        let bit = offset % 8;

        (byte, bit as u8)
    }

    fn mark_byte(&self, offset: usize) -> u8 {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_ptr()
        }
    }

    fn set_mark_byte(&self, offset: usize, val: u8) {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_mut_ptr() = val;
        }
    }
}

impl Drop for MarkingBitmap {
    fn drop(&mut self) {
        os::munmap(self.bitmap.start.to_ptr(), self.bitmap.size());
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2016 Masaki Hara
//
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php

extern crate byteorder;

use self::byteorder::{LittleEndian, ByteOrder};
use std::cmp;
use std::io::{Write, Result};

const S : [u32; 64] = [
    7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
    5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
    4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
    6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
];
const K : [u32; 64] = [
    0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE,
    0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501,
    0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE,
    0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821,
    0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA,
    0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8,
    0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED,
    0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A,
    0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C,
    0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70,
    0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05,
    0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665,
    0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039,
    0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1,
    0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1,
    0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391,
];

fn update(hh: &mut [u32; 4], chunk: &[u8]) {
    let mut m : [u32; 16] = [0; 16];
    for i in 0..16 {
        m[i] = LittleEndian::read_u32(&chunk[i * 4 .. i * 4 + 4]);
    }
    let mut a : u32 = hh[0];
    let mut b : u32 = hh[1];
    let mut c : u32 = hh[2];
    let mut d : u32 = hh[3];
    for i in 0..64 {
        let f : u32;
        let g : usize;
        if i < 16 {
            f = (b & c) | (!b & d);
            g = i;
        } else if i < 32 {
            f = (d & b) | (!d & c);
            g = (5 * i + 1) % 16;
        } else if i < 48 {
            f = b ^ c ^ d;
            g = (3 * i + 5) % 16;
        } else {
            f = c ^ (b | !d);
            g = 7 * i % 16;
        }
        let tmp = d;
        d = c;
        c = b;
        b = b.wrapping_add(
            (a.wrapping_add(f)
             .wrapping_add(K[i]).wrapping_add(m[g])).rotate_left(S[i]));
        a = tmp;
    }
    hh[0] = hh[0].wrapping_add(a);
    hh[1] = hh[1].wrapping_add(b);
    hh[2] = hh[2].wrapping_add(c);
    hh[3] = hh[3].wrapping_add(d);
}

pub struct MD5Writer {
    state: [u32; 4],
    position: u64,
    buf: [u8; 64],
    bufpos: usize,
}

impl Copy for MD5Writer {}
impl Clone for MD5Writer {
    fn clone(&self) -> Self {
        return MD5Writer {
            state: self.state,
            position: self.position,
            buf: self.buf,
            bufpos: self.bufpos
        };
    }
}

impl MD5Writer {
    pub fn new() -> MD5Writer {
        return MD5Writer {
            state: [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476],
            position: 0,
            buf: [0; 64],
            bufpos: 0,
        };
    }
    pub fn sum(&self) -> [u8; 16] {
        let mut state = self.state;
        let mut buf = self.buf;
        let buflen = buf.len();
        let bufpos = self.bufpos;
        buf[self.bufpos] = 0x80;
        for i in bufpos + 1 .. buflen { buf[i] = 0; }
        if bufpos + 1 > buflen - 8 {
            update(&mut state, &buf);
            for i in 0 .. buflen { buf[i] = 0; }
        }
        LittleEndian::write_u64(&mut buf[buflen - 8 ..], self.position);
        update(&mut state, &buf);
        let mut hashbuf : [u8; 16] = [0; 16];
        for i in 0..4 {
            LittleEndian::write_u32(
                &mut hashbuf[i * 4 .. i * 4 + 4], state[i]);
        }
        return hashbuf;
    }
}

impl Write for MD5Writer {
    fn write(&mut self, mut buf: &[u8]) -> Result<usize> {
        let orig_len = buf.len();
        while buf.len() > 0 {
            let wrsize = cmp::min(self.buf.len() - self.bufpos, buf.len());
            self.buf[self.bufpos .. self.bufpos + wrsize]
                .clone_from_slice(&buf[0 .. wrsize]);
            buf = &buf[wrsize ..];
            self.position += (wrsize * 8) as u64;
            self.bufpos += wrsize;
            if self.bufpos >= self.buf.len() {
                update(&mut self.state, &self.buf);
                self.bufpos -= self.buf.len();
            }
        }
        return Ok(orig_len);
    }
    fn flush(&mut self) -> Result<()> {
        return Ok(());
    }
}
<commit_msg>Small fix in MD5.<commit_after>// Copyright (c) 2016 Masaki Hara
//
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php

extern crate byteorder;

use self::byteorder::{LittleEndian, ByteOrder};
use std::cmp;
use std::io::{Write, Result};

const S : [u32; 64] = [
    7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
    5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
    4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
    6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
];
const K : [u32; 64] = [
    0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE,
    0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501,
    0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE,
    0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821,
    0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA,
    0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8,
    0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED,
    0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A,
    0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C,
    0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70,
    0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05,
    0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665,
    0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039,
    0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1,
    0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1,
    0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391,
];

fn update(hh: &mut [u32; 4], chunk: &[u8; 64]) {
    let mut m : [u32; 16] = [0; 16];
    for i in 0..16 {
        m[i] = LittleEndian::read_u32(&chunk[i * 4 .. i * 4 + 4]);
    }
    let mut a : u32 = hh[0];
    let mut b : u32 = hh[1];
    let mut c : u32 = hh[2];
    let mut d : u32 = hh[3];
    for i in 0..64 {
        let f : u32;
        let g : usize;
        if i < 16 {
            f = (b & c) | (!b & d);
            g = i;
        } else if i < 32 {
            f = (d & b) | (!d & c);
            g = (5 * i + 1) % 16;
        } else if i < 48 {
            f = b ^ c ^ d;
            g = (3 * i + 5) % 16;
        } else {
            f = c ^ (b | !d);
            g = 7 * i % 16;
        }
        let tmp = d;
        d = c;
        c = b;
        b = b.wrapping_add(
            (a.wrapping_add(f)
             .wrapping_add(K[i]).wrapping_add(m[g])).rotate_left(S[i]));
        a = tmp;
    }
    hh[0] = hh[0].wrapping_add(a);
    hh[1] = hh[1].wrapping_add(b);
    hh[2] = hh[2].wrapping_add(c);
    hh[3] = hh[3].wrapping_add(d);
}

pub struct MD5Writer {
    state: [u32; 4],
    position: u64,
    buf: [u8; 64],
    bufpos: usize,
}

impl Copy for MD5Writer {}
impl Clone for MD5Writer {
    fn clone(&self) -> Self {
        return MD5Writer {
            state: self.state,
            position: self.position,
            buf: self.buf,
            bufpos: self.bufpos
        };
    }
}

impl MD5Writer {
    pub fn new() -> MD5Writer {
        return MD5Writer {
            state: [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476],
            position: 0,
            buf: [0; 64],
            bufpos: 0,
        };
    }
    pub fn sum(&self) -> [u8; 16] {
        let mut state = self.state;
        let mut buf = self.buf;
        let buflen = buf.len();
        let bufpos = self.bufpos;
        buf[self.bufpos] = 0x80;
        for i in bufpos + 1 .. buflen { buf[i] = 0; }
        if bufpos + 1 > buflen - 8 {
            update(&mut state, &buf);
            for i in 0 .. buflen { buf[i] = 0; }
        }
        LittleEndian::write_u64(&mut buf[buflen - 8 ..], self.position);
        update(&mut state, &buf);
        let mut hashbuf : [u8; 16] = [0; 16];
        for i in 0..4 {
            LittleEndian::write_u32(
                &mut hashbuf[i * 4 .. i * 4 + 4], state[i]);
        }
        return hashbuf;
    }
}

impl Write for MD5Writer {
    fn write(&mut self, mut buf: &[u8]) -> Result<usize> {
        let orig_len = buf.len();
        while buf.len() > 0 {
            let wrsize = cmp::min(self.buf.len() - self.bufpos, buf.len());
            self.buf[self.bufpos .. self.bufpos + wrsize]
                .clone_from_slice(&buf[0 .. wrsize]);
            buf = &buf[wrsize ..];
            self.position += (wrsize * 8) as u64;
            self.bufpos += wrsize;
            if self.bufpos >= self.buf.len() {
                update(&mut self.state, &self.buf);
                self.bufpos -= self.buf.len();
            }
        }
        return Ok(orig_len);
    }
    fn flush(&mut self) -> Result<()> {
        return Ok(());
    }
}
<|endoftext|>