<commit_before>// (C)opyleft 2013 Frank Denis

/*!
 * Bindings for the GeoIP library
 */
#[desc = "Bindings for the GeoIP library."];
#[license = "BSD"];
#[crate_id = "geoip#0.1"];
#[crate_type = "rlib"];

#[warn(non_camel_case_types,
       non_uppercase_statics,
       unnecessary_qualification,
       managed_heap_memory)];

use std::c_str::CString;
use std::fmt;
use std::io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};
use std::libc::{c_void, c_char, c_int, c_ulong};

type GeoIP_ = *c_void;
type In6Addr = [u8, ..16];

struct GeoIPLookup {
    netmask: c_int
}

impl GeoIPLookup {
    fn new() -> GeoIPLookup {
        GeoIPLookup {
            netmask: 0
        }
    }
}

#[link(name = "GeoIP")]
extern {
    fn GeoIP_open(dbtype: *c_char, flags: c_int) -> GeoIP_;
    fn GeoIP_delete(db: GeoIP_);
    fn GeoIP_name_by_ipnum_gl(db: GeoIP_, ipnum: c_ulong, gl: &GeoIPLookup) -> *c_char;
    fn GeoIP_name_by_ipnum_v6_gl(db: GeoIP_, ipnum: In6Addr, gl: &GeoIPLookup) -> *c_char;
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

pub struct GeoIP {
    db: GeoIP_
}

pub struct ASInfo {
    asn: uint,
    name: ~str,
    netmask: uint
}

impl fmt::Show for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, "{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, ~str> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            GeoIP_open(file.to_c_str().unwrap(), options as c_int)
        };
        match db.is_null() {
            true => Err(format!("Can't open {}", file)),
            false => Ok(GeoIP {
                    db: db
                })
        }
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let gl = GeoIPLookup::new();
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_name_by_ipnum_gl(self.db, ipnum, &gl)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_name_by_ipnum_v6_gl(self.db, in6_addr, &gl)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let description_cstr = unsafe { CString::new(cres, true) };
        let description = match description_cstr.as_str() {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(' ', 1);
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    from_str::<uint>(asn.slice_from(2)).unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let asinfo = ASInfo {
            asn: asn,
            name: name.to_owned(),
            netmask: gl.netmask as uint
        };
        Some(asinfo)
    }
}

impl Drop for GeoIP {
    fn drop(&mut self) {
        unsafe {
            GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoIPASNum.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.contains("Telefun"));
    assert!(res.netmask == 22);
}
<commit_msg>Update inner attribute syntax<commit_after>// (C)opyleft 2013 Frank Denis

/*!
 * Bindings for the GeoIP library
 */
#![desc = "Bindings for the GeoIP library."]
#![license = "BSD"]
#![crate_id = "geoip#0.1"]
#![crate_type = "rlib"]

#![warn(non_camel_case_types,
        non_uppercase_statics,
        unnecessary_qualification,
        managed_heap_memory)]

use std::c_str::CString;
use std::fmt;
use std::io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};
use std::libc::{c_void, c_char, c_int, c_ulong};

type GeoIP_ = *c_void;
type In6Addr = [u8, ..16];

struct GeoIPLookup {
    netmask: c_int
}

impl GeoIPLookup {
    fn new() -> GeoIPLookup {
        GeoIPLookup {
            netmask: 0
        }
    }
}

#[link(name = "GeoIP")]
extern {
    fn GeoIP_open(dbtype: *c_char, flags: c_int) -> GeoIP_;
    fn GeoIP_delete(db: GeoIP_);
    fn GeoIP_name_by_ipnum_gl(db: GeoIP_, ipnum: c_ulong, gl: &GeoIPLookup) -> *c_char;
    fn GeoIP_name_by_ipnum_v6_gl(db: GeoIP_, ipnum: In6Addr, gl: &GeoIPLookup) -> *c_char;
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

pub struct GeoIP {
    db: GeoIP_
}

pub struct ASInfo {
    asn: uint,
    name: ~str,
    netmask: uint
}

impl fmt::Show for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, "{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, ~str> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            GeoIP_open(file.to_c_str().unwrap(), options as c_int)
        };
        match db.is_null() {
            true => Err(format!("Can't open {}", file)),
            false => Ok(GeoIP {
                    db: db
                })
        }
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let gl = GeoIPLookup::new();
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_name_by_ipnum_gl(self.db, ipnum, &gl)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_name_by_ipnum_v6_gl(self.db, in6_addr, &gl)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let description_cstr = unsafe { CString::new(cres, true) };
        let description = match description_cstr.as_str() {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(' ', 1);
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    from_str::<uint>(asn.slice_from(2)).unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let asinfo = ASInfo {
            asn: asn,
            name: name.to_owned(),
            netmask: gl.netmask as uint
        };
        Some(asinfo)
    }
}

impl Drop for GeoIP {
    fn drop(&mut self) {
        unsafe {
            GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoIPASNum.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.contains("Telefun"));
    assert!(res.netmask == 22);
}
<|endoftext|>


<commit_before>use std::cmp;
use std::borrow::Cow;
use std::old_io::{fs, File, FileMode, FileAccess, TempDir};

use buffer::{Buffer, Mark};
use input::Input;
use uibuf::{UIBuffer, CharColor};
use frontends::Frontend;
use overlay::{Overlay, OverlayType};
use utils;
use textobject::{Anchor, TextObject, Kind, Offset};

/// A View is an abstract Window (into a Buffer).
///
/// It draws a portion of a Buffer to a UIBuffer which in turn is drawn to the
/// screen. It maintains the status bar for the current view, the "dirty status"
/// which is whether the buffer has been modified or not and a number of other
/// pieces of information.
pub struct View {
    pub buffer: Buffer,
    pub overlay: Overlay,

    /// First character of the top line to be displayed
    top_line: Mark,

    /// Index into the top_line - used for horizontal scrolling
    left_col: usize,

    /// The current View's cursor - a reference into the Buffer
    cursor: Mark,

    /// The UIBuffer to which the View is drawn
    uibuf: UIBuffer,

    /// Number of lines from the top/bottom of the View after which vertical
    /// scrolling begins.
    threshold: usize,
}

impl View {

    pub fn new(source: Input, width: usize, height: usize) -> View {
        let mut buffer = match source {
            Input::Filename(path) => {
                match path {
                    Some(s) => Buffer::new_from_file(Path::new(s)),
                    None    => Buffer::new(),
                }
            },
            Input::Stdin(reader) => {
                Buffer::new_from_reader(reader)
            },
        };

        let cursor = Mark::Cursor(0);
        let top_line = Mark::DisplayMark(0);

        buffer.set_mark(cursor, 0);
        buffer.set_mark(top_line, 0);

        View {
            buffer: buffer,
            top_line: top_line,
            left_col: 0,
            cursor: cursor,
            uibuf: UIBuffer::new(width, height),
            overlay: Overlay::None,
            threshold: 5,
        }
    }

    /// Get the height of the View.
    ///
    /// This is the height of the UIBuffer minus the status bar height.
    pub fn get_height(&self) -> usize {
        let status_bar_height = 1;
        let uibuf_height = self.uibuf.get_height();

        uibuf_height - status_bar_height
    }

    /// Get the width of the View.
    pub fn get_width(&self) -> usize {
        self.uibuf.get_width()
    }

    /// Resize the view
    ///
    /// This involves simply changing the size of the associated UIBuffer
    pub fn resize(&mut self, width: usize, height: usize) {
        let uibuf = UIBuffer::new(width, height);
        self.uibuf = uibuf;
    }

    /// Clear the buffer
    ///
    /// Fills every cell in the UIBuffer with the space (' ') char.
    pub fn clear<T: Frontend>(&mut self, frontend: &mut T) {
        self.uibuf.fill(' ');
        self.uibuf.draw_everything(frontend);
    }

    pub fn draw<T: Frontend>(&mut self, frontend: &mut T) {
        let height = self.get_height();
        let width = self.get_width();
        let mut line = 0;
        let mut col = 0;
        for c in self.buffer.chars_from(self.top_line).unwrap() {
            if c == '\n' {
                if line == height { break; }
                for i in range(col, width) {
                    self.uibuf.update_cell_content(i, line, ' ');
                }
                col = 0;
                line += 1;
            } else {
                self.uibuf.update_cell_content(col, line, c);
                col += 1;
            }
        }

        match self.overlay {
            Overlay::None => self.draw_cursor(frontend),
            _ => {
                self.overlay.draw(frontend, &mut self.uibuf);
                self.overlay.draw_cursor(frontend);
            }
        }
        self.draw_status(frontend);
        self.uibuf.draw_everything(frontend);
    }

    fn draw_status<T: Frontend>(&mut self, frontend: &mut T) {
        let buffer_status = self.buffer.status_text();
        let mut cursor_status = self.buffer.get_mark_coords(self.cursor).unwrap_or((0,0));
        cursor_status = (cursor_status.0 + 1, cursor_status.1 + 1);
        let status_text = format!("{} ({}, {})", buffer_status, cursor_status.0, cursor_status.1).into_bytes();
        let status_text_len = status_text.len();
        let width = self.get_width();
        let height = self.get_height() - 1;

        for index in range(0, width) {
            let mut ch: char = ' ';
            if index < status_text_len {
                ch = status_text[index] as char;
            }
            self.uibuf.update_cell(index, height, ch, CharColor::Black, CharColor::Blue);
        }

        self.uibuf.draw_range(frontend, height, height+1);
    }

    fn draw_cursor<T: Frontend>(&mut self, frontend: &mut T) {
        if let Some(top_line) = self.buffer.get_mark_coords(self.top_line) {
            if let Some((x, y)) = self.buffer.get_mark_coords(self.cursor) {
                frontend.draw_cursor((x - self.left_col) as isize, y as isize - top_line.1 as isize);
            }
        }
    }

    pub fn set_overlay(&mut self, overlay_type: OverlayType) {
        match overlay_type {
            OverlayType::Prompt => {
                self.overlay = Overlay::Prompt {
                    cursor_x: 1,
                    prefix: ":",
                    data: String::new(),
                };
            }
            _ => {}
        }
    }

    pub fn move_mark(&mut self, mark: Mark, object: TextObject) {
        self.buffer.set_mark_to_object(mark, object);
        self.maybe_move_screen();
    }

    /// Update the top_line mark if necessary to keep the cursor on the screen.
    fn maybe_move_screen(&mut self) {
        if let (Some(cursor), Some((_, top_line))) = (self.buffer.get_mark_coords(self.cursor),
                                                      self.buffer.get_mark_coords(self.top_line)) {

            let width  = (self.get_width()  - self.threshold) as isize;
            let height = (self.get_height() - self.threshold) as isize;

            //left-right shifting
            self.left_col = match cursor.0 as isize - self.left_col as isize {
                x_offset if x_offset < self.threshold as isize => {
                    cmp::max(0, self.left_col as isize - (self.threshold as isize - x_offset)) as usize
                }
                x_offset if x_offset >= width => {
                    self.left_col + (x_offset - width + 1) as usize
                }
                _ => { self.left_col }
            };

            //up-down shifting
            match cursor.1 as isize - top_line as isize {
                y_offset if y_offset < self.threshold as isize && top_line > 0 => {
                    let amount = (self.threshold as isize - y_offset) as usize;
                    let obj = TextObject {
                        kind: Kind::Line(Anchor::Same),
                        offset: Offset::Backward(amount, self.top_line)
                    };
                    self.buffer.set_mark_to_object(self.top_line, obj);
                }
                y_offset if y_offset >= height => {
                    let amount = (y_offset - height + 1) as usize;
                    let obj = TextObject {
                        kind: Kind::Line(Anchor::Same),
                        offset: Offset::Forward(amount, self.top_line)
                    };
                    self.buffer.set_mark_to_object(self.top_line, obj);
                }
                _ => { }
            }
        }
    }

    // Delete chars from the first index of object to the last index of object
    pub fn delete_object(&mut self, object: TextObject) {
        self.buffer.remove_object(object);
    }

    pub fn delete_from_mark_to_object(&mut self, mark: Mark, object: TextObject) {
        use std::cmp;
        if let Some((idx, _)) = self.buffer.get_object_index(object) {
            if let Some(midx) = self.buffer.get_mark_idx(mark) {
                self.buffer.remove_from_mark_to_object(mark, object);
                self.buffer.set_mark(mark, cmp::min(idx, midx));
            }
        }
    }

    /// Insert a chacter into the buffer & update cursor position accordingly.
    pub fn insert_char(&mut self, ch: char) {
        self.buffer.insert_char(self.cursor, ch as u8);
        // NOTE: the last param to char_width here may not be correct
        if let Some(ch_width) = utils::char_width(ch, false, 4, 1) {
            let obj = TextObject {
                kind: Kind::Char,
                offset: Offset::Forward(ch_width, Mark::Cursor(0))
            };
            self.move_mark(Mark::Cursor(0), obj)
        }
    }

    pub fn undo(&mut self) {
        let point = if let Some(transaction) = self.buffer.undo() { transaction.end_point }
                    else { return; };
        self.buffer.set_mark(self.cursor, point);
        self.maybe_move_screen();
    }

    pub fn redo(&mut self) {
        let point = if let Some(transaction) = self.buffer.redo() { transaction.end_point }
                    else { return; };
        self.buffer.set_mark(self.cursor, point);
        self.maybe_move_screen();
    }

    fn save_buffer(&mut self) {
        let path = match self.buffer.file_path {
            Some(ref p) => Cow::Borrowed(p),
            None => {
                // NOTE: this should never happen, as the file path
                // should have been set inside the try_save_buffer method.
                //
                // If this runs, it probably means save_buffer has been called
                // directly, rather than try_save_buffer.
                Cow::Owned(Path::new("untitled"))
            },
        };
        let tmpdir = match TempDir::new_in(&Path::new("."), "iota") {
            Ok(d) => d,
            Err(e) => panic!("file error: {}", e)
        };

        let tmppath = tmpdir.path().join(Path::new("tmpfile"));
        let mut file = match File::open_mode(&tmppath, FileMode::Open, FileAccess::Write) {
            Ok(f) => f,
            Err(e) => panic!("file error: {}", e)
        };

        //TODO (lee): Is iteration still necessary in this format?
        for line in self.buffer.lines() {
            let result = file.write_all(&*line);

            if result.is_err() {
                // TODO(greg): figure out what to do here.
                panic!("Something went wrong while writing the file");
            }
        }

        if let Err(e) = fs::rename(&tmppath, &*path) {
            panic!("file error: {}", e);
        }
    }

    pub fn try_save_buffer(&mut self) {
        match self.buffer.file_path {
            Some(_) => self.save_buffer(),
            None => {
                let prefix = "Enter file name: ";
                self.overlay = Overlay::SavePrompt {
                    cursor_x: prefix.len(),
                    prefix: prefix,
                    data: String::new(),
                };
            },
        };
    }

}

pub fn draw_line(buf: &mut UIBuffer, line: &[u8], idx: usize, left: usize) {
    let width = buf.get_width() - 1;
    let mut wide_chars = 0;
    for line_idx in range(left, left + width) {
        if line_idx < line.len() {
            let special_char = line[line_idx] as char;
            match special_char {
                '\t'   => {
                    let w = 4 - line_idx % 4;
                    for _ in range(0, w) {
                        buf.update_cell_content(line_idx + wide_chars - left, idx, ' ');
                    }
                }
                '\n'   => buf.update_cell_content(line_idx + wide_chars - left, idx, ' '),
                _       => buf.update_cell_content(line_idx + wide_chars - left, idx,
                                                   line[line_idx] as char),
            }
            wide_chars += (line[line_idx] as char).width(false).unwrap_or(1) - 1;
        } else { buf.update_cell_content(line_idx + wide_chars - left, idx, ' '); }
    }
    if line.len() >= width {
        buf.update_cell_content(width + wide_chars, idx, '→');
    }

}

#[cfg(test)]
mod tests {

    use view::View;
    use input::Input;

    fn setup_view(testcase: &'static str) -> View {
        let mut view = View::new(Input::Filename(None), 50, 50);
        for ch in testcase.chars() {
            view.insert_char(ch);
        }
        view.buffer.set_mark(view.cursor, 0);
        view
    }

    #[test]
    fn test_insert_char() {
        let mut view = setup_view("test\nsecond");
        view.insert_char('t');

        assert_eq!(view.buffer.lines().next().unwrap(), b"ttest\n");
    }
}
<commit_msg>Fixed line drawing issue<commit_after>use std::cmp;
use std::borrow::Cow;
use std::old_io::{fs, File, FileMode, FileAccess, TempDir};

use buffer::{Buffer, Mark};
use input::Input;
use uibuf::{UIBuffer, CharColor};
use frontends::Frontend;
use overlay::{Overlay, OverlayType};
use utils;
use textobject::{Anchor, TextObject, Kind, Offset};

/// A View is an abstract Window (into a Buffer).
///
/// It draws a portion of a Buffer to a UIBuffer which in turn is drawn to the
/// screen. It maintains the status bar for the current view, the "dirty status"
/// which is whether the buffer has been modified or not and a number of other
/// pieces of information.
pub struct View {
    pub buffer: Buffer,
    pub overlay: Overlay,

    /// First character of the top line to be displayed
    top_line: Mark,

    /// Index into the top_line - used for horizontal scrolling
    left_col: usize,

    /// The current View's cursor - a reference into the Buffer
    cursor: Mark,

    /// The UIBuffer to which the View is drawn
    uibuf: UIBuffer,

    /// Number of lines from the top/bottom of the View after which vertical
    /// scrolling begins.
    threshold: usize,
}

impl View {

    pub fn new(source: Input, width: usize, height: usize) -> View {
        let mut buffer = match source {
            Input::Filename(path) => {
                match path {
                    Some(s) => Buffer::new_from_file(Path::new(s)),
                    None    => Buffer::new(),
                }
            },
            Input::Stdin(reader) => {
                Buffer::new_from_reader(reader)
            },
        };

        let cursor = Mark::Cursor(0);
        let top_line = Mark::DisplayMark(0);

        buffer.set_mark(cursor, 0);
        buffer.set_mark(top_line, 0);

        View {
            buffer: buffer,
            top_line: top_line,
            left_col: 0,
            cursor: cursor,
            uibuf: UIBuffer::new(width, height),
            overlay: Overlay::None,
            threshold: 5,
        }
    }

    /// Get the height of the View.
    ///
    /// This is the height of the UIBuffer minus the status bar height.
    pub fn get_height(&self) -> usize {
        let status_bar_height = 1;
        let uibuf_height = self.uibuf.get_height();

        uibuf_height - status_bar_height
    }

    /// Get the width of the View.
    pub fn get_width(&self) -> usize {
        self.uibuf.get_width()
    }

    /// Resize the view
    ///
    /// This involves simply changing the size of the associated UIBuffer
    pub fn resize(&mut self, width: usize, height: usize) {
        let uibuf = UIBuffer::new(width, height);
        self.uibuf = uibuf;
    }

    /// Clear the buffer
    ///
    /// Fills every cell in the UIBuffer with the space (' ') char.
    pub fn clear<T: Frontend>(&mut self, frontend: &mut T) {
        self.uibuf.fill(' ');
        self.uibuf.draw_everything(frontend);
    }

    pub fn draw<T: Frontend>(&mut self, frontend: &mut T) {
        let height = self.get_height() - 2;
        let width = self.get_width();
        let mut line = 0;
        let mut col = 0;
        for c in self.buffer.chars_from(self.top_line).unwrap() {
            if c == '\n' {
                if line == height { break; }
                for i in range(col, width) {
                    self.uibuf.update_cell_content(i, line, ' ');
                }
                col = 0;
                line += 1;
            } else {
                self.uibuf.update_cell_content(col, line, c);
                col += 1;
            }
        }

        match self.overlay {
            Overlay::None => self.draw_cursor(frontend),
            _ => {
                self.overlay.draw(frontend, &mut self.uibuf);
                self.overlay.draw_cursor(frontend);
            }
        }
        self.draw_status(frontend);
        self.uibuf.draw_everything(frontend);
    }

    fn draw_status<T: Frontend>(&mut self, frontend: &mut T) {
        let buffer_status = self.buffer.status_text();
        let mut cursor_status = self.buffer.get_mark_coords(self.cursor).unwrap_or((0,0));
        cursor_status = (cursor_status.0 + 1, cursor_status.1 + 1);
        let status_text = format!("{} ({}, {})", buffer_status, cursor_status.0, cursor_status.1).into_bytes();
        let status_text_len = status_text.len();
        let width = self.get_width();
        let height = self.get_height() - 1;

        for index in range(0, width) {
            let mut ch: char = ' ';
            if index < status_text_len {
                ch = status_text[index] as char;
            }
            self.uibuf.update_cell(index, height, ch, CharColor::Black, CharColor::Blue);
        }

        self.uibuf.draw_range(frontend, height, height+1);
    }

    fn draw_cursor<T: Frontend>(&mut self, frontend: &mut T) {
        if let Some(top_line) = self.buffer.get_mark_coords(self.top_line) {
            if let Some((x, y)) = self.buffer.get_mark_coords(self.cursor) {
                frontend.draw_cursor((x - self.left_col) as isize, y as isize - top_line.1 as isize);
            }
        }
    }

    pub fn set_overlay(&mut self, overlay_type: OverlayType) {
        match overlay_type {
            OverlayType::Prompt => {
                self.overlay = Overlay::Prompt {
                    cursor_x: 1,
                    prefix: ":",
                    data: String::new(),
                };
            }
            _ => {}
        }
    }

    pub fn move_mark(&mut self, mark: Mark, object: TextObject) {
        self.buffer.set_mark_to_object(mark, object);
        self.maybe_move_screen();
    }

    /// Update the top_line mark if necessary to keep the cursor on the screen.
    fn maybe_move_screen(&mut self) {
        if let (Some(cursor), Some((_, top_line))) = (self.buffer.get_mark_coords(self.cursor),
                                                      self.buffer.get_mark_coords(self.top_line)) {

            let width  = (self.get_width()  - self.threshold) as isize;
            let height = (self.get_height() - self.threshold) as isize;

            //left-right shifting
            self.left_col = match cursor.0 as isize - self.left_col as isize {
                x_offset if x_offset < self.threshold as isize => {
                    cmp::max(0, self.left_col as isize - (self.threshold as isize - x_offset)) as usize
                }
                x_offset if x_offset >= width => {
                    self.left_col + (x_offset - width + 1) as usize
                }
                _ => { self.left_col }
            };

            //up-down shifting
            match cursor.1 as isize - top_line as isize {
                y_offset if y_offset < self.threshold as isize && top_line > 0 => {
                    let amount = (self.threshold as isize - y_offset) as usize;
                    let obj = TextObject {
                        kind: Kind::Line(Anchor::Same),
                        offset: Offset::Backward(amount, self.top_line)
                    };
                    self.buffer.set_mark_to_object(self.top_line, obj);
                }
                y_offset if y_offset >= height => {
                    let amount = (y_offset - height + 1) as usize;
                    let obj = TextObject {
                        kind: Kind::Line(Anchor::Same),
                        offset: Offset::Forward(amount, self.top_line)
                    };
                    self.buffer.set_mark_to_object(self.top_line, obj);
                }
                _ => { }
            }
        }
    }

    // Delete chars from the first index of object to the last index of object
    pub fn delete_object(&mut self, object: TextObject) {
        self.buffer.remove_object(object);
    }

    pub fn delete_from_mark_to_object(&mut self, mark: Mark, object: TextObject) {
        use std::cmp;
        if let Some((idx, _)) = self.buffer.get_object_index(object) {
            if let Some(midx) = self.buffer.get_mark_idx(mark) {
                self.buffer.remove_from_mark_to_object(mark, object);
                self.buffer.set_mark(mark, cmp::min(idx, midx));
            }
        }
    }

    /// Insert a chacter into the buffer & update cursor position accordingly.
    pub fn insert_char(&mut self, ch: char) {
        self.buffer.insert_char(self.cursor, ch as u8);
        // NOTE: the last param to char_width here may not be correct
        if let Some(ch_width) = utils::char_width(ch, false, 4, 1) {
            let obj = TextObject {
                kind: Kind::Char,
                offset: Offset::Forward(ch_width, Mark::Cursor(0))
            };
            self.move_mark(Mark::Cursor(0), obj)
        }
    }

    pub fn undo(&mut self) {
        let point = if let Some(transaction) = self.buffer.undo() { transaction.end_point }
                    else { return; };
        self.buffer.set_mark(self.cursor, point);
        self.maybe_move_screen();
    }

    pub fn redo(&mut self) {
        let point = if let Some(transaction) = self.buffer.redo() { transaction.end_point }
                    else { return; };
        self.buffer.set_mark(self.cursor, point);
        self.maybe_move_screen();
    }

    fn save_buffer(&mut self) {
        let path = match self.buffer.file_path {
            Some(ref p) => Cow::Borrowed(p),
            None => {
                // NOTE: this should never happen, as the file path
                // should have been set inside the try_save_buffer method.
                //
                // If this runs, it probably means save_buffer has been called
                // directly, rather than try_save_buffer.
                Cow::Owned(Path::new("untitled"))
            },
        };
        let tmpdir = match TempDir::new_in(&Path::new("."), "iota") {
            Ok(d) => d,
            Err(e) => panic!("file error: {}", e)
        };

        let tmppath = tmpdir.path().join(Path::new("tmpfile"));
        let mut file = match File::open_mode(&tmppath, FileMode::Open, FileAccess::Write) {
            Ok(f) => f,
            Err(e) => panic!("file error: {}", e)
        };

        //TODO (lee): Is iteration still necessary in this format?
        for line in self.buffer.lines() {
            let result = file.write_all(&*line);

            if result.is_err() {
                // TODO(greg): figure out what to do here.
                panic!("Something went wrong while writing the file");
            }
        }

        if let Err(e) = fs::rename(&tmppath, &*path) {
            panic!("file error: {}", e);
        }
    }

    pub fn try_save_buffer(&mut self) {
        match self.buffer.file_path {
            Some(_) => self.save_buffer(),
            None => {
                let prefix = "Enter file name: ";
                self.overlay = Overlay::SavePrompt {
                    cursor_x: prefix.len(),
                    prefix: prefix,
                    data: String::new(),
                };
            },
        };
    }

}

pub fn draw_line(buf: &mut UIBuffer, line: &[u8], idx: usize, left: usize) {
    let width = buf.get_width() - 1;
    let mut wide_chars = 0;
    for line_idx in range(left, left + width) {
        if line_idx < line.len() {
            let special_char = line[line_idx] as char;
            match special_char {
                '\t'   => {
                    let w = 4 - line_idx % 4;
                    for _ in range(0, w) {
                        buf.update_cell_content(line_idx + wide_chars - left, idx, ' ');
                    }
                }
                '\n'   => buf.update_cell_content(line_idx + wide_chars - left, idx, ' '),
                _       => buf.update_cell_content(line_idx + wide_chars - left, idx,
                                                   line[line_idx] as char),
            }
            wide_chars += (line[line_idx] as char).width(false).unwrap_or(1) - 1;
        } else { buf.update_cell_content(line_idx + wide_chars - left, idx, ' '); }
    }
    if line.len() >= width {
        buf.update_cell_content(width + wide_chars, idx, '→');
    }

}

#[cfg(test)]
mod tests {

    use view::View;
    use input::Input;

    fn setup_view(testcase: &'static str) -> View {
        let mut view = View::new(Input::Filename(None), 50, 50);
        for ch in testcase.chars() {
            view.insert_char(ch);
        }
        view.buffer.set_mark(view.cursor, 0);
        view
    }

    #[test]
    fn test_insert_char() {
        let mut view = setup_view("test\nsecond");
        view.insert_char('t');

        assert_eq!(view.buffer.lines().next().unwrap(), b"ttest\n");
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! Task-local reference-counted boxes (`Rc` type)

The `Rc` type provides shared ownership of an immutable value. Destruction is deterministic, and
will occur as soon as the last owner is gone. It is marked as non-sendable because it avoids the
overhead of atomic reference counting.

The `downgrade` method can be used to create a non-owning `Weak` pointer to the box. A `Weak`
pointer can be upgraded to an `Rc` pointer, but will return `None` if the value has already been
freed.

For example, a tree with parent pointers can be represented by putting the nodes behind `Strong`
pointers, and then storing the parent pointers as `Weak` pointers.

*/

use cast::transmute;
use cell::Cell;
use clone::Clone;
use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering};
use kinds::marker;
use ops::{Deref, Drop};
use option::{Option, Some, None};
use ptr;
use ptr::RawPtr;
use rt::global_heap::exchange_free;

struct RcBox<T> {
    value: T,
    strong: Cell<uint>,
    weak: Cell<uint>
}

/// Immutable reference counted pointer type
#[unsafe_no_drop_flag]
pub struct Rc<T> {
    ptr: *mut RcBox<T>,
    nosend: marker::NoSend,
    noshare: marker::NoShare
}

impl<T> Rc<T> {
    /// Construct a new reference-counted box
    pub fn new(value: T) -> Rc<T> {
        unsafe {
            Rc {
                // there is an implicit weak pointer owned by all the
                // strong pointers, which ensures that the weak
                // destructor never frees the allocation while the
                // strong destructor is running, even if the weak
                // pointer is stored inside the strong one.
                ptr: transmute(~RcBox {
                    value: value,
                    strong: Cell::new(1),
                    weak: Cell::new(1)
                }),
                nosend: marker::NoSend,
                noshare: marker::NoShare
            }
        }
    }
}

impl<T> Rc<T> {
    /// Downgrade the reference-counted pointer to a weak reference
    pub fn downgrade(&self) -> Weak<T> {
        self.inc_weak();
        Weak {
            ptr: self.ptr,
            nosend: marker::NoSend,
            noshare: marker::NoShare
        }
    }
}

impl<T> Deref<T> for Rc<T> {
    /// Borrow the value contained in the reference-counted box
    #[inline(always)]
    fn deref<'a>(&'a self) -> &'a T {
        &self.inner().value
    }
}

#[unsafe_destructor]
impl<T> Drop for Rc<T> {
    fn drop(&mut self) {
        unsafe {
            if !self.ptr.is_null() {
                self.dec_strong();
                if self.strong() == 0 {
                    ptr::read(self.deref()); // destroy the contained object

                    // remove the implicit "strong weak" pointer now
                    // that we've destroyed the contents.
                    self.dec_weak();

                    if self.weak() == 0 {
                        exchange_free(self.ptr as *u8)
                    }
                }
            }
        }
    }
}

impl<T> Clone for Rc<T> {
    #[inline]
    fn clone(&self) -> Rc<T> {
        self.inc_strong();
        Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }
    }
}

impl<T: Eq> Eq for Rc<T> {
    #[inline(always)]
    fn eq(&self, other: &Rc<T>) -> bool { **self == **other }
    #[inline(always)]
    fn ne(&self, other: &Rc<T>) -> bool { **self != **other }
}

impl<T: TotalEq> TotalEq for Rc<T> {}

impl<T: Ord> Ord for Rc<T> {
    #[inline(always)]
    fn lt(&self, other: &Rc<T>) -> bool { **self < **other }

    #[inline(always)]
    fn le(&self, other: &Rc<T>) -> bool { **self <= **other }

    #[inline(always)]
    fn gt(&self, other: &Rc<T>) -> bool { **self > **other }

    #[inline(always)]
    fn ge(&self, other: &Rc<T>) -> bool { **self >= **other }
}

impl<T: TotalOrd> TotalOrd for Rc<T> {
    #[inline]
    fn cmp(&self, other: &Rc<T>) -> Ordering { (**self).cmp(&**other) }
}

/// Weak reference to a reference-counted box
#[unsafe_no_drop_flag]
pub struct Weak<T> {
    ptr: *mut RcBox<T>,
    nosend: marker::NoSend,
    noshare: marker::NoShare
}

impl<T> Weak<T> {
    /// Upgrade a weak reference to a strong reference
    pub fn upgrade(&self) -> Option<Rc<T>> {
        if self.strong() == 0 {
            None
        } else {
            self.inc_strong();
            Some(Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare })
        }
    }
}

#[unsafe_destructor]
impl<T> Drop for Weak<T> {
    fn drop(&mut self) {
        unsafe {
            if !self.ptr.is_null() {
                self.dec_weak();
                // the weak count starts at 1, and will only go to
                // zero if all the strong pointers have disappeared.
                if self.weak() == 0 {
                    exchange_free(self.ptr as *u8)
                }
            }
        }
    }
}

impl<T> Clone for Weak<T> {
    #[inline]
    fn clone(&self) -> Weak<T> {
        self.inc_weak();
        Weak { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }
    }
}

#[allow(missing_doc)]
trait RcBoxPtr<T> {
    fn inner<'a>(&'a self) -> &'a RcBox<T>;

    #[inline]
    fn strong(&self) -> uint { self.inner().strong.get() }

    #[inline]
    fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); }

    #[inline]
    fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); }

    #[inline]
    fn weak(&self) -> uint { self.inner().weak.get() }

    #[inline]
    fn inc_weak(&self) { self.inner().weak.set(self.weak() + 1); }

    #[inline]
    fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); }
}

impl<T> RcBoxPtr<T> for Rc<T> {
    #[inline(always)]
    fn inner<'a>(&'a self) -> &'a RcBox<T> { unsafe { &(*self.ptr) } }
}

impl<T> RcBoxPtr<T> for Weak<T> {
    #[inline(always)]
    fn inner<'a>(&'a self) -> &'a RcBox<T> { unsafe { &(*self.ptr) } }
}

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

    #[test]
    fn test_clone() {
        let x = Rc::new(RefCell::new(5));
        let y = x.clone();
        *x.borrow_mut() = 20;
        assert_eq!(*y.borrow(), 20);
    }

    #[test]
    fn test_simple() {
        let x = Rc::new(5);
        assert_eq!(*x, 5);
    }

    #[test]
    fn test_simple_clone() {
        let x = Rc::new(5);
        let y = x.clone();
        assert_eq!(*x, 5);
        assert_eq!(*y, 5);
    }

    #[test]
    fn test_destructor() {
        let x = Rc::new(~5);
        assert_eq!(**x, 5);
    }

    #[test]
    fn test_live() {
        let x = Rc::new(5);
        let y = x.downgrade();
        assert!(y.upgrade().is_some());
    }

    #[test]
    fn test_dead() {
        let x = Rc::new(5);
        let y = x.downgrade();
        drop(x);
        assert!(y.upgrade().is_none());
    }

    #[test]
    fn gc_inside() {
        // see issue #11532
        use gc::Gc;
        let a = Rc::new(RefCell::new(Gc::new(1)));
        assert!(a.try_borrow_mut().is_some());
    }

    #[test]
    fn weak_self_cyclic() {
        struct Cycle {
            x: RefCell<Option<Weak<Cycle>>>
        }

        let a = Rc::new(Cycle { x: RefCell::new(None) });
        let b = a.clone().downgrade();
        *a.x.borrow_mut() = Some(b);

        // hopefully we don't double-free (or leak)...
    }
}
<commit_msg>Hide trait rc::RcBoxPtr from docs<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! Task-local reference-counted boxes (`Rc` type)

The `Rc` type provides shared ownership of an immutable value. Destruction is deterministic, and
will occur as soon as the last owner is gone. It is marked as non-sendable because it avoids the
overhead of atomic reference counting.

The `downgrade` method can be used to create a non-owning `Weak` pointer to the box. A `Weak`
pointer can be upgraded to an `Rc` pointer, but will return `None` if the value has already been
freed.

For example, a tree with parent pointers can be represented by putting the nodes behind `Strong`
pointers, and then storing the parent pointers as `Weak` pointers.

*/

use cast::transmute;
use cell::Cell;
use clone::Clone;
use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering};
use kinds::marker;
use ops::{Deref, Drop};
use option::{Option, Some, None};
use ptr;
use ptr::RawPtr;
use rt::global_heap::exchange_free;

struct RcBox<T> {
    value: T,
    strong: Cell<uint>,
    weak: Cell<uint>
}

/// Immutable reference counted pointer type
#[unsafe_no_drop_flag]
pub struct Rc<T> {
    ptr: *mut RcBox<T>,
    nosend: marker::NoSend,
    noshare: marker::NoShare
}

impl<T> Rc<T> {
    /// Construct a new reference-counted box
    pub fn new(value: T) -> Rc<T> {
        unsafe {
            Rc {
                // there is an implicit weak pointer owned by all the
                // strong pointers, which ensures that the weak
                // destructor never frees the allocation while the
                // strong destructor is running, even if the weak
                // pointer is stored inside the strong one.
                ptr: transmute(~RcBox {
                    value: value,
                    strong: Cell::new(1),
                    weak: Cell::new(1)
                }),
                nosend: marker::NoSend,
                noshare: marker::NoShare
            }
        }
    }
}

impl<T> Rc<T> {
    /// Downgrade the reference-counted pointer to a weak reference
    pub fn downgrade(&self) -> Weak<T> {
        self.inc_weak();
        Weak {
            ptr: self.ptr,
            nosend: marker::NoSend,
            noshare: marker::NoShare
        }
    }
}

impl<T> Deref<T> for Rc<T> {
    /// Borrow the value contained in the reference-counted box
    #[inline(always)]
    fn deref<'a>(&'a self) -> &'a T {
        &self.inner().value
    }
}

#[unsafe_destructor]
impl<T> Drop for Rc<T> {
    fn drop(&mut self) {
        unsafe {
            if !self.ptr.is_null() {
                self.dec_strong();
                if self.strong() == 0 {
                    ptr::read(self.deref()); // destroy the contained object

                    // remove the implicit "strong weak" pointer now
                    // that we've destroyed the contents.
                    self.dec_weak();

                    if self.weak() == 0 {
                        exchange_free(self.ptr as *u8)
                    }
                }
            }
        }
    }
}

impl<T> Clone for Rc<T> {
    #[inline]
    fn clone(&self) -> Rc<T> {
        self.inc_strong();
        Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }
    }
}

impl<T: Eq> Eq for Rc<T> {
    #[inline(always)]
    fn eq(&self, other: &Rc<T>) -> bool { **self == **other }
    #[inline(always)]
    fn ne(&self, other: &Rc<T>) -> bool { **self != **other }
}

impl<T: TotalEq> TotalEq for Rc<T> {}

impl<T: Ord> Ord for Rc<T> {
    #[inline(always)]
    fn lt(&self, other: &Rc<T>) -> bool { **self < **other }

    #[inline(always)]
    fn le(&self, other: &Rc<T>) -> bool { **self <= **other }

    #[inline(always)]
    fn gt(&self, other: &Rc<T>) -> bool { **self > **other }

    #[inline(always)]
    fn ge(&self, other: &Rc<T>) -> bool { **self >= **other }
}

impl<T: TotalOrd> TotalOrd for Rc<T> {
    #[inline]
    fn cmp(&self, other: &Rc<T>) -> Ordering { (**self).cmp(&**other) }
}

/// Weak reference to a reference-counted box
#[unsafe_no_drop_flag]
pub struct Weak<T> {
    ptr: *mut RcBox<T>,
    nosend: marker::NoSend,
    noshare: marker::NoShare
}

impl<T> Weak<T> {
    /// Upgrade a weak reference to a strong reference
    pub fn upgrade(&self) -> Option<Rc<T>> {
        if self.strong() == 0 {
            None
        } else {
            self.inc_strong();
            Some(Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare })
        }
    }
}

#[unsafe_destructor]
impl<T> Drop for Weak<T> {
    fn drop(&mut self) {
        unsafe {
            if !self.ptr.is_null() {
                self.dec_weak();
                // the weak count starts at 1, and will only go to
                // zero if all the strong pointers have disappeared.
                if self.weak() == 0 {
                    exchange_free(self.ptr as *u8)
                }
            }
        }
    }
}

impl<T> Clone for Weak<T> {
    #[inline]
    fn clone(&self) -> Weak<T> {
        self.inc_weak();
        Weak { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }
    }
}

#[doc(hidden)]
trait RcBoxPtr<T> {
    fn inner<'a>(&'a self) -> &'a RcBox<T>;

    #[inline]
    fn strong(&self) -> uint { self.inner().strong.get() }

    #[inline]
    fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); }

    #[inline]
    fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); }

    #[inline]
    fn weak(&self) -> uint { self.inner().weak.get() }

    #[inline]
    fn inc_weak(&self) { self.inner().weak.set(self.weak() + 1); }

    #[inline]
    fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); }
}

impl<T> RcBoxPtr<T> for Rc<T> {
    #[inline(always)]
    fn inner<'a>(&'a self) -> &'a RcBox<T> { unsafe { &(*self.ptr) } }
}

impl<T> RcBoxPtr<T> for Weak<T> {
    #[inline(always)]
    fn inner<'a>(&'a self) -> &'a RcBox<T> { unsafe { &(*self.ptr) } }
}

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

    #[test]
    fn test_clone() {
        let x = Rc::new(RefCell::new(5));
        let y = x.clone();
        *x.borrow_mut() = 20;
        assert_eq!(*y.borrow(), 20);
    }

    #[test]
    fn test_simple() {
        let x = Rc::new(5);
        assert_eq!(*x, 5);
    }

    #[test]
    fn test_simple_clone() {
        let x = Rc::new(5);
        let y = x.clone();
        assert_eq!(*x, 5);
        assert_eq!(*y, 5);
    }

    #[test]
    fn test_destructor() {
        let x = Rc::new(~5);
        assert_eq!(**x, 5);
    }

    #[test]
    fn test_live() {
        let x = Rc::new(5);
        let y = x.downgrade();
        assert!(y.upgrade().is_some());
    }

    #[test]
    fn test_dead() {
        let x = Rc::new(5);
        let y = x.downgrade();
        drop(x);
        assert!(y.upgrade().is_none());
    }

    #[test]
    fn gc_inside() {
        // see issue #11532
        use gc::Gc;
        let a = Rc::new(RefCell::new(Gc::new(1)));
        assert!(a.try_borrow_mut().is_some());
    }

    #[test]
    fn weak_self_cyclic() {
        struct Cycle {
            x: RefCell<Option<Weak<Cycle>>>
        }

        let a = Rc::new(Cycle { x: RefCell::new(None) });
        let b = a.clone().downgrade();
        *a.x.borrow_mut() = Some(b);

        // hopefully we don't double-free (or leak)...
    }
}
<|endoftext|>


<commit_before>use std::ptr;

use libc;
use ffi;

use Wrapper;
use super::{Integer, Context};

#[derive(Debug)]
pub struct Point {
    raw: ffi::gcry_mpi_point_t,
}

impl Drop for Point {
    fn drop(&mut self) {
        unsafe {
            ffi::gcry_mpi_point_release(self.raw);
        }
    }
}

impl Clone for Point {
    fn clone(&self) -> Point {
        let (x, y, z) = self.coords();
        let point = unsafe {
            Point::from_raw(ffi::gcry_mpi_point_snatch_set(ptr::null_mut(), x.into_raw(),
                                                           y.into_raw(), z.into_raw()))
        };
        point
    }

    fn clone_from(&mut self, source: &Point) {
        let (x, y, z) = source.coords();
        unsafe {
            ffi::gcry_mpi_point_snatch_set(self.raw, x.into_raw(), y.into_raw(), z.into_raw());
        }
    }
}

unsafe impl Wrapper for Point {
    type Raw = ffi::gcry_mpi_point_t;

    unsafe fn from_raw(raw: ffi::gcry_mpi_point_t) -> Point {
        debug_assert!(!raw.is_null());
        Point { raw: raw }
    }

    fn as_raw(&self) -> ffi::gcry_mpi_point_t {
        self.raw
    }
}

impl Point {
    pub fn zero() -> Point {
        Point::new(0)
    }

    pub fn new(nbits: usize) -> Point {
        unsafe {
            Point {
                raw: ffi::gcry_mpi_point_new(nbits as libc::c_uint)
            }
        }
    }

    pub fn from(x: Option<Integer>, y: Option<Integer>, z: Option<Integer>) -> Point {
        unsafe {
            let x = x.map_or(ptr::null_mut(), |v| v.into_raw());
            let y = y.map_or(ptr::null_mut(), |v| v.into_raw());
            let z = z.map_or(ptr::null_mut(), |v| v.into_raw());
            Point::from_raw(ffi::gcry_mpi_point_snatch_set(ptr::null_mut(), x, y, z))
        }
    }

    pub fn set(&mut self, x: Option<Integer>, y: Option<Integer>, z: Option<Integer>) {
        unsafe {
            let x = x.map_or(ptr::null_mut(), |v| v.into_raw());
            let y = y.map_or(ptr::null_mut(), |v| v.into_raw());
            let z = z.map_or(ptr::null_mut(), |v| v.into_raw());
            ffi::gcry_mpi_point_snatch_set(self.raw, x, y, z);
        }
    }

    pub fn to_coords(&self) -> (Integer, Integer, Integer) {
        let x = Integer::default();
        let y = Integer::default();
        let z = Integer::default();
        unsafe {
            ffi::gcry_mpi_point_get(x.as_raw(), y.as_raw(), z.as_raw(), self.raw);
        }
        (x, y, z)
    }

    pub fn into_coords(self) -> (Integer, Integer, Integer) {
        let x = Integer::default();
        let y = Integer::default();
        let z = Integer::default();
        unsafe {
            ffi::gcry_mpi_point_snatch_get(x.as_raw(), y.as_raw(), z.as_raw(), self.into_raw());
        }
        (x, y, z)
    }

    pub fn get_affine(&self, ctx: &Context) -> Option<(Integer, Integer)> {
        let x = Integer::default();
        let y = Integer::default();
        let result = unsafe {
            ffi::gcry_mpi_ec_get_affine(x.as_raw(), y.as_raw(), self.raw, ctx.as_raw())
        };
        if result == 0 {
            Some((x, y))
        } else {
            None
        }
    }

    pub fn on_curve(&self, ctx: &Context) -> bool {
        unsafe {
            ffi::gcry_mpi_ec_curve_point(self.raw, ctx.as_raw()) != 0
        }
    }

    pub fn add(self, other: &Point, ctx: &Context) -> Point {
        unsafe {
            ffi::gcry_mpi_ec_add(self.raw, self.raw, other.raw, ctx.as_raw());
        }
        self
    }

    pub fn mul(self, n: &Integer, ctx: &Context) -> Point {
        unsafe {
            ffi::gcry_mpi_ec_mul(self.raw, n.as_raw(), self.raw, ctx.as_raw());
        }
        self
    }
}

impl Default for Point {
    fn default() -> Point {
        Point::new(0)
    }
}
<commit_msg>Fix build<commit_after>use std::ptr;

use libc;
use ffi;

use Wrapper;
use super::{Integer, Context};

#[derive(Debug)]
pub struct Point {
    raw: ffi::gcry_mpi_point_t,
}

impl Drop for Point {
    fn drop(&mut self) {
        unsafe {
            ffi::gcry_mpi_point_release(self.raw);
        }
    }
}

impl Clone for Point {
    fn clone(&self) -> Point {
        let (x, y, z) = self.to_coords();
        let point = unsafe {
            Point::from_raw(ffi::gcry_mpi_point_snatch_set(ptr::null_mut(), x.into_raw(),
                                                           y.into_raw(), z.into_raw()))
        };
        point
    }

    fn clone_from(&mut self, source: &Point) {
        let (x, y, z) = source.to_coords();
        unsafe {
            ffi::gcry_mpi_point_snatch_set(self.raw, x.into_raw(), y.into_raw(), z.into_raw());
        }
    }
}

unsafe impl Wrapper for Point {
    type Raw = ffi::gcry_mpi_point_t;

    unsafe fn from_raw(raw: ffi::gcry_mpi_point_t) -> Point {
        debug_assert!(!raw.is_null());
        Point { raw: raw }
    }

    fn as_raw(&self) -> ffi::gcry_mpi_point_t {
        self.raw
    }
}

impl Point {
    pub fn zero() -> Point {
        Point::new(0)
    }

    pub fn new(nbits: usize) -> Point {
        unsafe {
            Point {
                raw: ffi::gcry_mpi_point_new(nbits as libc::c_uint)
            }
        }
    }

    pub fn from(x: Option<Integer>, y: Option<Integer>, z: Option<Integer>) -> Point {
        unsafe {
            let x = x.map_or(ptr::null_mut(), |v| v.into_raw());
            let y = y.map_or(ptr::null_mut(), |v| v.into_raw());
            let z = z.map_or(ptr::null_mut(), |v| v.into_raw());
            Point::from_raw(ffi::gcry_mpi_point_snatch_set(ptr::null_mut(), x, y, z))
        }
    }

    pub fn set(&mut self, x: Option<Integer>, y: Option<Integer>, z: Option<Integer>) {
        unsafe {
            let x = x.map_or(ptr::null_mut(), |v| v.into_raw());
            let y = y.map_or(ptr::null_mut(), |v| v.into_raw());
            let z = z.map_or(ptr::null_mut(), |v| v.into_raw());
            ffi::gcry_mpi_point_snatch_set(self.raw, x, y, z);
        }
    }

    pub fn to_coords(&self) -> (Integer, Integer, Integer) {
        let x = Integer::default();
        let y = Integer::default();
        let z = Integer::default();
        unsafe {
            ffi::gcry_mpi_point_get(x.as_raw(), y.as_raw(), z.as_raw(), self.raw);
        }
        (x, y, z)
    }

    pub fn into_coords(self) -> (Integer, Integer, Integer) {
        let x = Integer::default();
        let y = Integer::default();
        let z = Integer::default();
        unsafe {
            ffi::gcry_mpi_point_snatch_get(x.as_raw(), y.as_raw(), z.as_raw(), self.into_raw());
        }
        (x, y, z)
    }

    pub fn get_affine(&self, ctx: &Context) -> Option<(Integer, Integer)> {
        let x = Integer::default();
        let y = Integer::default();
        let result = unsafe {
            ffi::gcry_mpi_ec_get_affine(x.as_raw(), y.as_raw(), self.raw, ctx.as_raw())
        };
        if result == 0 {
            Some((x, y))
        } else {
            None
        }
    }

    pub fn on_curve(&self, ctx: &Context) -> bool {
        unsafe {
            ffi::gcry_mpi_ec_curve_point(self.raw, ctx.as_raw()) != 0
        }
    }

    pub fn add(self, other: &Point, ctx: &Context) -> Point {
        unsafe {
            ffi::gcry_mpi_ec_add(self.raw, self.raw, other.raw, ctx.as_raw());
        }
        self
    }

    pub fn mul(self, n: &Integer, ctx: &Context) -> Point {
        unsafe {
            ffi::gcry_mpi_ec_mul(self.raw, n.as_raw(), self.raw, ctx.as_raw());
        }
        self
    }
}

impl Default for Point {
    fn default() -> Point {
        Point::new(0)
    }
}
<|endoftext|>


<commit_before>use std::io::{TempDir, MemWriter};
use std::str::from_utf8;
use schema;
use buffer;

#[deriving(Show, Eq, Hash)]
struct Register {
	record: schema::Record,
	datatype: schema::SqlType,
}

impl Register {
	fn new(rec: schema::Record, typ: schema::SqlType) -> Register {
		Register {
			record: rec,
			datatype: typ,
		}
	}

	fn set_int(&mut self, val: int) {
		// TODO
	}

	fn get_int(&self) -> int {
		self.record.to_int()
	}

	fn set_str(&mut self) {
		// TODO
	}

	fn get_str<'a>(&'a self) -> &'a str {
		let d = self.record.get_data();
		from_utf8(d).unwrap()
	}
}

impl Ord for Register {
	fn lt(&self, other: &Register) -> bool {
		// not the most robust implementation
		self.get_int() < other.get_int()
	}
}

trait Operatorish<T>: Iterator<T> {
	//fn open();
	//fn close(&self);
}

struct TableScan<'a, 'b> {
	relation: schema::Relation,
	segment: &'a mut schema::SPSegment<'b>,
	current: uint,
}

impl<'a, 'b> TableScan<'a, 'b> {
	fn new(rel: schema::Relation, seg: &'a mut schema::SPSegment<'b>) -> TableScan<'a, 'b> {
		TableScan {
			relation: rel,
			segment: seg,
			current: 0,
		}
	}
}

impl<'a, 'b> Operatorish<Vec<Register>> for TableScan<'a, 'b> {
}

impl<'a, 'b> Iterator<Vec<Register>> for TableScan<'a, 'b> {
	fn next(&mut self) -> Option<Vec<Register>> {
		if (self.current as u64) < self.relation.inserted {
			let tup = self.relation.get(self.segment, self.current);
			let mut res = tup.move_iter().map(|(v, t)| Register::new(v, t)).
				collect::<Vec<Register>>();
			debug!("TS: {}", res);
			self.current += 1;
			Some(res)
		} else {
			None
		}
	}
}

struct Print<'a, T, V> {
	input: T,
	output: &'a mut V,
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Print<'a, T, V> {
	fn new(input: T, output: &'a mut V) -> Print<'a, T, V> {
		Print {
			input: input,
			output: output
		}
	}
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Iterator<Vec<Register>> for Print<'a, T, V> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			Some(reg) => {
				for item in reg.iter() {
					match item.datatype {
						schema::Varchar(_) => self.output.write(item.get_str().as_bytes()),
						schema::Integer => self.output.write(
							format!("{}", item.get_int()).as_bytes())
					};
					self.output.write(", ".as_bytes());
				}
				self.output.write("\n".as_bytes());
				Some(reg)
			},
			None => None,
		}
	}
}

struct Project<T> {
	input: T,
	registerids: Vec<uint>,
}

impl<T: Operatorish<Vec<Register>>> Project<T> {
	fn new(input: T, regs: Vec<uint>) -> Project<T> {
		Project {
			input: input,
			registerids: regs,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for Project<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			None => None,
			Some(mut reg) => {
				let mut res = Vec::with_capacity(self.registerids.len());
				let mut regids = self.registerids.clone();
				regids.reverse();
				for index in regids.move_iter() {
					let value = reg.remove(index);
					let v = match value {
						None => fail!("Projection doesn't have vield {}", index),
						Some(v) => v,
					};
					res.push(v);
				}
				Some(res)
			}
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for Project<T> {
}

#[deriving(Show)]
enum Selectable {
	Varchar(~str),
	Integer(int),
}

struct Select<T> {
	input: T,
	index: uint,
	value: Selectable,
}

impl<T: Operatorish<Vec<Register>>> Select<T> {
	fn new(input: T, index: uint, value: Selectable) -> Select<T> {
		Select {
			input: input,
			index: index,
			value: value,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for Select<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		// initial value
		let mut cur = self.input.next();
		while cur.is_some() {
			// we made sure cur is Some(…), so we can unwrap safely
			let reg = cur.unwrap();

			// check what we got to select for and retrieve values
			// accordingly
			match self.value {
				// comparing to a string
				Varchar(ref v) => {
					println!("Comparing {} with {}",
						reg.get(self.index).get_str(),
						v);
					// getting the register value as string
					if reg.get(self.index).get_str() == *v {
						return Some(reg)
					} else {
						// not equal, skip to next entry
						cur = self.input.next();
						continue
					}
				},
				// comparing to a number
				Integer(v) => {
					// compare against reg as integer
					if reg.get(self.index).get_int() == v {
						return Some(reg)
					} else {
						// not equal, skip to next entry
						cur = self.input.next();
						continue
					}
				}
			}
		}
		// no more entries, signal iterator exhaustion
		None
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for Select<T> {
}

struct HashJoin<T> {
	left: T,
	right: T,
	on: (uint, uint),
}

impl<T: Operatorish<Vec<Register>>> HashJoin<T> {
	fn new(left: T, right: T, on: (uint, uint)) -> HashJoin<T> {
		// TODO create hashmap of 'left'
		HashJoin {
			left: left,
			right: right,
			on: on,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for HashJoin<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		None
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for HashJoin<T> {
}

#[test]
fn simple_tablescan() {
	let dir = match TempDir::new("tablescan") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment {id: 1, manager: &mut manager};

	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	let age = schema::Column::new(~"age", schema::Integer, vec!(schema::NotNull));
	let mut relation = schema::Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Alice"), schema::Record::from_int(20)));
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Bob"), schema::Record::from_int(40)));

	{
		let mut ts = TableScan::new(relation.clone(), &mut seg);
		for tuple in ts {
			println!("Got entry {}", tuple);
		}
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), &mut seg);
			let mut pr = Print::new(ts, &mut mw);
			// force write by iterating, strange API
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), &mut seg);
			let mut pr = Project::new(ts, vec!(0));
			let mut pr = Print::new(pr, &mut mw);
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), &mut seg);
			let mut se = Select::new(ts, 1, Integer(20));
			let mut pr = Print::new(se, &mut mw);
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), &mut seg);
			let mut se = Select::new(ts, 0, Varchar(~"Bob"));
			let mut pr = Print::new(se, &mut mw);
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	assert!(false);
}

#[test]
fn simple_hashjoin() {
	let dir = match TempDir::new("hashjoin") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment {id: 1, manager: &mut manager};

	let id = schema::Column::new(~"id", schema::Integer, vec!(schema::NotNull));
	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	let mut people = schema::Relation::new(~"Person");
	people.add_column(id);
	people.add_column(name);
	people.insert(&mut seg, vec!(schema::Record::from_int(0), schema::Record::from_str(~"Alice")));
	people.insert(&mut seg, vec!(schema::Record::from_int(1), schema::Record::from_str(~"Bob")));

	let mut mw = MemWriter::new();
	let mut ts = TableScan::new(people, &mut seg);
	let mut se = Select::new(ts, 0, Integer(0));
	{
		let mut pr = Print::new(se, &mut mw);
		for _ in pr {}
	}
	println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());

	assert!(false);
}
<commit_msg>Add more test data to do a join on<commit_after>use std::io::{TempDir, MemWriter};
use std::str::from_utf8;
use schema;
use buffer;

#[deriving(Show, Eq, Hash)]
struct Register {
	record: schema::Record,
	datatype: schema::SqlType,
}

impl Register {
	fn new(rec: schema::Record, typ: schema::SqlType) -> Register {
		Register {
			record: rec,
			datatype: typ,
		}
	}

	fn set_int(&mut self, val: int) {
		// TODO
	}

	fn get_int(&self) -> int {
		self.record.to_int()
	}

	fn set_str(&mut self) {
		// TODO
	}

	fn get_str<'a>(&'a self) -> &'a str {
		let d = self.record.get_data();
		from_utf8(d).unwrap()
	}
}

impl Ord for Register {
	fn lt(&self, other: &Register) -> bool {
		// not the most robust implementation
		self.get_int() < other.get_int()
	}
}

trait Operatorish<T>: Iterator<T> {
	//fn open();
	//fn close(&self);
}

struct TableScan<'a, 'b> {
	relation: schema::Relation,
	segment: &'a mut schema::SPSegment<'b>,
	current: uint,
}

impl<'a, 'b> TableScan<'a, 'b> {
	fn new(rel: schema::Relation, seg: &'a mut schema::SPSegment<'b>) -> TableScan<'a, 'b> {
		TableScan {
			relation: rel,
			segment: seg,
			current: 0,
		}
	}
}

impl<'a, 'b> Operatorish<Vec<Register>> for TableScan<'a, 'b> {
}

impl<'a, 'b> Iterator<Vec<Register>> for TableScan<'a, 'b> {
	fn next(&mut self) -> Option<Vec<Register>> {
		if (self.current as u64) < self.relation.inserted {
			let tup = self.relation.get(self.segment, self.current);
			let mut res = tup.move_iter().map(|(v, t)| Register::new(v, t)).
				collect::<Vec<Register>>();
			debug!("TS: {}", res);
			self.current += 1;
			Some(res)
		} else {
			None
		}
	}
}

struct Print<'a, T, V> {
	input: T,
	output: &'a mut V,
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Print<'a, T, V> {
	fn new(input: T, output: &'a mut V) -> Print<'a, T, V> {
		Print {
			input: input,
			output: output
		}
	}
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Iterator<Vec<Register>> for Print<'a, T, V> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			Some(reg) => {
				for item in reg.iter() {
					match item.datatype {
						schema::Varchar(_) => self.output.write(item.get_str().as_bytes()),
						schema::Integer => self.output.write(
							format!("{}", item.get_int()).as_bytes())
					};
					self.output.write(", ".as_bytes());
				}
				self.output.write("\n".as_bytes());
				Some(reg)
			},
			None => None,
		}
	}
}

struct Project<T> {
	input: T,
	registerids: Vec<uint>,
}

impl<T: Operatorish<Vec<Register>>> Project<T> {
	fn new(input: T, regs: Vec<uint>) -> Project<T> {
		Project {
			input: input,
			registerids: regs,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for Project<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			None => None,
			Some(mut reg) => {
				let mut res = Vec::with_capacity(self.registerids.len());
				let mut regids = self.registerids.clone();
				regids.reverse();
				for index in regids.move_iter() {
					let value = reg.remove(index);
					let v = match value {
						None => fail!("Projection doesn't have vield {}", index),
						Some(v) => v,
					};
					res.push(v);
				}
				Some(res)
			}
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for Project<T> {
}

#[deriving(Show)]
enum Selectable {
	Varchar(~str),
	Integer(int),
}

struct Select<T> {
	input: T,
	index: uint,
	value: Selectable,
}

impl<T: Operatorish<Vec<Register>>> Select<T> {
	fn new(input: T, index: uint, value: Selectable) -> Select<T> {
		Select {
			input: input,
			index: index,
			value: value,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for Select<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		// initial value
		let mut cur = self.input.next();
		while cur.is_some() {
			// we made sure cur is Some(…), so we can unwrap safely
			let reg = cur.unwrap();

			// check what we got to select for and retrieve values
			// accordingly
			match self.value {
				// comparing to a string
				Varchar(ref v) => {
					println!("Comparing {} with {}",
						reg.get(self.index).get_str(),
						v);
					// getting the register value as string
					if reg.get(self.index).get_str() == *v {
						return Some(reg)
					} else {
						// not equal, skip to next entry
						cur = self.input.next();
						continue
					}
				},
				// comparing to a number
				Integer(v) => {
					// compare against reg as integer
					if reg.get(self.index).get_int() == v {
						return Some(reg)
					} else {
						// not equal, skip to next entry
						cur = self.input.next();
						continue
					}
				}
			}
		}
		// no more entries, signal iterator exhaustion
		None
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for Select<T> {
}

struct HashJoin<T> {
	left: T,
	right: T,
	on: (uint, uint),
}

impl<T: Operatorish<Vec<Register>>> HashJoin<T> {
	fn new(left: T, right: T, on: (uint, uint)) -> HashJoin<T> {
		// TODO create hashmap of 'left'
		HashJoin {
			left: left,
			right: right,
			on: on,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for HashJoin<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		None
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for HashJoin<T> {
}

#[test]
fn simple_tablescan() {
	let dir = match TempDir::new("tablescan") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment {id: 1, manager: &mut manager};

	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	let age = schema::Column::new(~"age", schema::Integer, vec!(schema::NotNull));
	let mut relation = schema::Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Alice"), schema::Record::from_int(20)));
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Bob"), schema::Record::from_int(40)));

	{
		let mut ts = TableScan::new(relation.clone(), &mut seg);
		for tuple in ts {
			println!("Got entry {}", tuple);
		}
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), &mut seg);
			let mut pr = Print::new(ts, &mut mw);
			// force write by iterating, strange API
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), &mut seg);
			let mut pr = Project::new(ts, vec!(0));
			let mut pr = Print::new(pr, &mut mw);
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), &mut seg);
			let mut se = Select::new(ts, 1, Integer(20));
			let mut pr = Print::new(se, &mut mw);
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), &mut seg);
			let mut se = Select::new(ts, 0, Varchar(~"Bob"));
			let mut pr = Print::new(se, &mut mw);
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	assert!(false);
}

#[test]
fn simple_hashjoin() {
	let dir = match TempDir::new("hashjoin") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment {id: 1, manager: &mut manager};

	let mut people = schema::Relation::new(~"Person");
	let id = schema::Column::new(~"id", schema::Integer, vec!(schema::NotNull));
	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	people.add_column(id);
	people.add_column(name);
	people.insert(&mut seg, vec!(schema::Record::from_int(0), schema::Record::from_str(~"Alice")));
	people.insert(&mut seg, vec!(schema::Record::from_int(1), schema::Record::from_str(~"Bob")));
	people.insert(&mut seg, vec!(schema::Record::from_int(2), schema::Record::from_str(~"Eve")));
	people.insert(&mut seg, vec!(schema::Record::from_int(3), schema::Record::from_str(~"Mallory")));
	let mut oses = schema::Relation::new(~"OSes");
	let ident = schema::Column::new(~"ident", schema::Integer, vec!(schema::NotNull));
	let os = schema::Column::new(~"OS", schema::Varchar(128), vec!(schema::NotNull));
	oses.add_column(ident);
	oses.add_column(os);
	oses.insert(&mut seg, vec!(schema::Record::from_int(0), schema::Record::from_str(~"Plan 9")));
	oses.insert(&mut seg, vec!(schema::Record::from_int(1), schema::Record::from_str(~"NetBSD")));
	oses.insert(&mut seg, vec!(schema::Record::from_int(3), schema::Record::from_str(~"GNU/Linux")));

	let mut mw = MemWriter::new();
	let mut ts = TableScan::new(people, &mut seg);
	let mut se = Select::new(ts, 0, Integer(0));
	{
		let mut pr = Print::new(se, &mut mw);
		for _ in pr {}
	}
	println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());

	assert!(false);
}
<|endoftext|>


<commit_before>use regex::Regex;
use std::path::PathBuf;
use std::result::Result;
use subprocess::{Exec, Redirection};

const LOOP_BACKING_DEVICE_BASENAME: &'static str = "flaglock6-home";
const LOOP_DEVICE_PARTITION_LABEL: &'static str = "fl6";
const RSYNC_DOT_NET_REMOTE_DIR: &'static str = "usw-s007.rsync.net:./";

#[derive(Debug)]
pub enum AuricError {
    Invocation(String),
    Io(String),
    Subprocess(String),
    NotFound,
}

impl From<subprocess::PopenError> for AuricError {
    fn from(err: subprocess::PopenError) -> AuricError {
        AuricError::Subprocess(err.to_string())
    }
}
struct SshfsManager {
    mountpoint: PathBuf,
}

struct LoopManager {
    target: Regex,
    backing: PathBuf,
}

struct LuksManager {
    device: PathBuf,
}

impl SshfsManager {
    pub fn new() -> Result<SshfsManager, AuricError> {
        let xdg_runtime_dir = match std::env::var("XDG_RUNTIME_DIR") {
            Ok(val) => val,
            Err(e) => {
                return Err(AuricError::Invocation(format!(
                    "fatal error getting ${{XDG_RUNTIME_DIR}}: ``{}''",
                    e
                )))
            }
        };
        let mut mountpoint = PathBuf::new();
        mountpoint.push(xdg_runtime_dir);
        mountpoint.push("rsync.net-mountpoint");

        Ok(SshfsManager {
            mountpoint: mountpoint,
        })
    }

    fn ensure_mountpoint_is_dir(&self) -> Result<(), AuricError> {
        if self.mountpoint.is_dir() {
            return Ok(());
        }
        std::fs::create_dir(self.mountpoint.as_path())
            .map_err(|e| AuricError::Io(format!("bad mountpoint: ``{}''", e)))
    }

    // Does _not_ ensure that backing device exists.
    pub fn loop_backing_device_path(&self) -> PathBuf {
        let mut result: PathBuf = self.mountpoint.clone();
        result.push(LOOP_BACKING_DEVICE_BASENAME);
        result
    }

    pub fn loop_backing_device_present(&self) -> bool {
        self.loop_backing_device_path().is_file()
    }

    pub fn mount(&self) -> Result<(), AuricError> {
        self.ensure_mountpoint_is_dir()?;
        let result = Exec::cmd("sshfs")
            .arg("-o")
            .arg("allow_other")
            .arg(RSYNC_DOT_NET_REMOTE_DIR)
            .arg(&self.mountpoint)
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "sshfs failed: ``{}''",
                result.stderr_str()
            )));
        }
        Ok(())
    }

    pub fn unmount(&self) -> Result<(), AuricError> {
        let result = Exec::cmd("fusermount")
            .arg("-u")
            .arg(&self.mountpoint)
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "fusermount -u failed: ``{}''",
                result.stderr_str()
            )));
        }
        Ok(())
    }
}

impl LoopManager {
    pub fn new(backing: &PathBuf) -> LoopManager {
        let target = format!(
            r"^(/dev/loop\d)(\s+\d+){{4}}\s+({})\s+",
            backing.to_str().unwrap()
        );
        LoopManager {
            target: Regex::new(&target).unwrap(),
            backing: backing.clone(),
        }
    }

    pub fn find(&self) -> Result<PathBuf, AuricError> {
        let result = Exec::cmd("sudo")
            .arg("losetup")
            .arg("-l")
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "failed to list loop devices: ``{}''",
                result.stderr_str()
            )));
        }

        for line in result.stdout_str().lines() {
            if let Some(captures) = self.target.captures(line) {
                return Ok(PathBuf::from(captures.get(1).unwrap().as_str()));
            }
        }
        Err(AuricError::NotFound)
    }

    pub fn attach(&self) -> Result<(), AuricError> {
        let result = Exec::cmd("udisksctl")
            .arg("loop-setup")
            .arg("-f")
            .arg(&self.backing)
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "failed to attach loop device: ``{}''",
                result.stderr_str()
            )));
        }
        Ok(())
    }

    // Note that the loop device will linger if the volume remains
    // unlocked. Prefer not to call this before locking.
    pub fn detach(&self) -> Result<(), AuricError> {
        let attached_loop = match self.find() {
            Ok(path) => path,
            Err(e) => {
                if let AuricError::NotFound = e {
                    return Ok(());
                }
                return Err(e);
            }
        };
        let result = Exec::cmd("udisksctl")
            .arg("loop-delete")
            .arg("-b")
            .arg(&attached_loop)
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "failed to detach loop device: ``{}''",
                result.stderr_str()
            )));
        }
        Ok(())
    }
}

impl LuksManager {
    pub fn new() -> LuksManager {
        let mut device = PathBuf::from("/dev/disk/by-label");
        device.push(LOOP_DEVICE_PARTITION_LABEL);
        LuksManager { device: device }
    }

    // `locked_device` is necessary as an external argument because no
    // device mapping exists in a pre-unlock world, so we need to target
    // the loop device directly.
    pub fn unlock(&self, locked_device: &PathBuf) -> Result<(), AuricError> {
        let result = Exec::cmd("udisksctl")
            .arg("unlock")
            .arg("-b")
            .arg(locked_device)
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "failed to unlock {}: ``{}''",
                locked_device.to_str().unwrap(),
                result.stderr_str()
            )));
        }
        Ok(())
    }

    // No extra argument is needed here (c.f. `self::unlock()`) because
    // we can go straight after the well-known device available in
    // /dev/disk/by-label.
    pub fn lock(&self) -> Result<(), AuricError> {
        let result = Exec::cmd("udisksctl")
            .arg("lock")
            .arg("-b")
            .arg(&self.device)
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "failed to lock {}: ``{}''",
                self.device.to_str().unwrap(),
                result.stderr_str()
            )));
        }
        Ok(())
    }
}

fn main_impl() -> Result<(), AuricError> {
    println!("Hello there!");
    Ok(())
}

fn main() {
    std::process::exit(match main_impl() {
        Ok(_) => 0,
        Err(e) => {
            eprintln!("{:?}", e);
            1
        }
    });
}
<commit_msg>apricot-auric: Extend LuksManager<commit_after>use regex::Regex;
use std::path::PathBuf;
use std::result::Result;
use subprocess::{Exec, Redirection};

const LOOP_BACKING_DEVICE_BASENAME: &'static str = "flaglock6-home";
const LOOP_DEVICE_PARTITION_LABEL: &'static str = "fl6";
const RSYNC_DOT_NET_REMOTE_DIR: &'static str = "usw-s007.rsync.net:./";

#[derive(Debug)]
pub enum AuricError {
    Invocation(String),
    Io(String),
    Subprocess(String),
    NotFound,
}

impl From<subprocess::PopenError> for AuricError {
    fn from(err: subprocess::PopenError) -> AuricError {
        AuricError::Subprocess(err.to_string())
    }
}
struct SshfsManager {
    mountpoint: PathBuf,
}

struct LoopManager {
    target: Regex,
    backing: PathBuf,
}

struct LuksManager {
    device: PathBuf,
}

impl SshfsManager {
    pub fn new() -> Result<SshfsManager, AuricError> {
        let xdg_runtime_dir = match std::env::var("XDG_RUNTIME_DIR") {
            Ok(val) => val,
            Err(e) => {
                return Err(AuricError::Invocation(format!(
                    "fatal error getting ${{XDG_RUNTIME_DIR}}: ``{}''",
                    e
                )))
            }
        };
        let mut mountpoint = PathBuf::new();
        mountpoint.push(xdg_runtime_dir);
        mountpoint.push("rsync.net-mountpoint");

        Ok(SshfsManager {
            mountpoint: mountpoint,
        })
    }

    fn ensure_mountpoint_is_dir(&self) -> Result<(), AuricError> {
        if self.mountpoint.is_dir() {
            return Ok(());
        }
        std::fs::create_dir(self.mountpoint.as_path())
            .map_err(|e| AuricError::Io(format!("bad mountpoint: ``{}''", e)))
    }

    // Does _not_ ensure that backing device exists.
    pub fn loop_backing_device_path(&self) -> PathBuf {
        let mut result: PathBuf = self.mountpoint.clone();
        result.push(LOOP_BACKING_DEVICE_BASENAME);
        result
    }

    pub fn loop_backing_device_present(&self) -> bool {
        self.loop_backing_device_path().is_file()
    }

    pub fn mount(&self) -> Result<(), AuricError> {
        self.ensure_mountpoint_is_dir()?;
        let result = Exec::cmd("sshfs")
            .arg("-o")
            .arg("allow_other")
            .arg(RSYNC_DOT_NET_REMOTE_DIR)
            .arg(&self.mountpoint)
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "sshfs failed: ``{}''",
                result.stderr_str()
            )));
        }
        Ok(())
    }

    pub fn unmount(&self) -> Result<(), AuricError> {
        let result = Exec::cmd("fusermount")
            .arg("-u")
            .arg(&self.mountpoint)
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "fusermount -u failed: ``{}''",
                result.stderr_str()
            )));
        }
        Ok(())
    }
}

impl LoopManager {
    pub fn new(backing: &PathBuf) -> LoopManager {
        let target = format!(
            r"^(/dev/loop\d)(\s+\d+){{4}}\s+({})\s+",
            backing.to_str().unwrap()
        );
        LoopManager {
            target: Regex::new(&target).unwrap(),
            backing: backing.clone(),
        }
    }

    pub fn find(&self) -> Result<PathBuf, AuricError> {
        let result = Exec::cmd("sudo")
            .arg("losetup")
            .arg("-l")
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "failed to list loop devices: ``{}''",
                result.stderr_str()
            )));
        }

        for line in result.stdout_str().lines() {
            if let Some(captures) = self.target.captures(line) {
                return Ok(PathBuf::from(captures.get(1).unwrap().as_str()));
            }
        }
        Err(AuricError::NotFound)
    }

    pub fn attach(&self) -> Result<(), AuricError> {
        let result = Exec::cmd("udisksctl")
            .arg("loop-setup")
            .arg("-f")
            .arg(&self.backing)
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "failed to attach loop device: ``{}''",
                result.stderr_str()
            )));
        }
        Ok(())
    }

    // Note that the loop device will linger if the volume remains
    // unlocked. Prefer not to call this before locking.
    pub fn detach(&self) -> Result<(), AuricError> {
        let attached_loop = match self.find() {
            Ok(path) => path,
            Err(e) => {
                if let AuricError::NotFound = e {
                    return Ok(());
                }
                return Err(e);
            }
        };
        let result = Exec::cmd("udisksctl")
            .arg("loop-delete")
            .arg("-b")
            .arg(&attached_loop)
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "failed to detach loop device: ``{}''",
                result.stderr_str()
            )));
        }
        Ok(())
    }
}

impl LuksManager {
    pub fn new() -> LuksManager {
        let mut device = PathBuf::from("/dev/disk/by-label");
        device.push(LOOP_DEVICE_PARTITION_LABEL);
        LuksManager { device: device }
    }

    // `locked_device` is necessary as an external argument because no
    // device mapping exists in a pre-unlock world, so we need to target
    // the loop device directly.
    pub fn unlock(&self, locked_device: &PathBuf) -> Result<(), AuricError> {
        let result = Exec::cmd("udisksctl")
            .arg("unlock")
            .arg("-b")
            .arg(locked_device)
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "failed to unlock {}: ``{}''",
                locked_device.to_str().unwrap(),
                result.stderr_str()
            )));
        }
        Ok(())
    }

    // No extra argument is needed here (c.f. `self::unlock()`) because
    // we can go straight after the well-known device available in
    // /dev/disk/by-label.
    pub fn lock(&self) -> Result<(), AuricError> {
        let result = Exec::cmd("udisksctl")
            .arg("lock")
            .arg("-b")
            .arg(&self.device)
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "failed to lock {}: ``{}''",
                self.device.to_str().unwrap(),
                result.stderr_str()
            )));
        }
        Ok(())
    }

    pub fn mount(&self) -> Result<(), AuricError> {
        let result = Exec::cmd("udisksctl")
            .arg("mount")
            .arg("-b")
            .arg(&self.device)
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "failed to mount {}: ``{}''",
                self.device.to_str().unwrap(),
                result.stderr_str()
            )));
        }
        Ok(())
    }

    pub fn unmount(&self) -> Result<(), AuricError> {
        let result = Exec::cmd("udisksctl")
            .arg("unmount")
            .arg("-b")
            .arg(&self.device)
            .stdout(Redirection::Pipe)
            .stderr(Redirection::Pipe)
            .capture()?;
        if !result.success() {
            return Err(AuricError::Subprocess(format!(
                "failed to unmount {}: ``{}''",
                self.device.to_str().unwrap(),
                result.stderr_str()
            )));
        }
        Ok(())
    }
}

fn main_impl() -> Result<(), AuricError> {
    println!("Hello there!");
    Ok(())
}

fn main() {
    std::process::exit(match main_impl() {
        Ok(_) => 0,
        Err(e) => {
            eprintln!("{:?}", e);
            1
        }
    });
}
<|endoftext|>