<commit_before>// ignore-windows: File handling is not implemented yet
// compile-flags: -Zmiri-disable-isolation

use std::fs::{File, create_dir, read_dir, remove_dir, remove_dir_all, remove_file, rename};
use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom};
use std::path::{PathBuf, Path};

fn main() {
    test_file();
    test_file_clone();
    test_seek();
    test_metadata();
    test_symlink();
    test_errors();
    test_rename();
    test_directory();
}

/// Prepare: compute filename and make sure the file does not exist.
fn prepare(filename: &str) -> PathBuf {
    let tmp = std::env::temp_dir();
    let path = tmp.join(filename);
    // Clean the paths for robustness.
    remove_file(&path).ok();
    path
}

/// Prepare directory: compute directory name and make sure it does not exist.
fn prepare_dir(dirname: &str) -> PathBuf {
    let tmp = std::env::temp_dir();
    let path = tmp.join(&dirname);
    // Clean the directory for robustness.
    remove_dir_all(&path).ok();
    path
}

/// Prepare like above, and also write some initial content to the file.
fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf {
    let path = prepare(filename);
    let mut file = File::create(&path).unwrap();
    file.write(content).unwrap();
    path
}

fn test_file() {
    let bytes = b"Hello, World!\n";
    let path = prepare("miri_test_fs_file.txt");

    // Test creating, writing and closing a file (closing is tested when `file` is dropped).
    let mut file = File::create(&path).unwrap();
    // Writing 0 bytes should not change the file contents.
    file.write(&mut []).unwrap();
    assert_eq!(file.metadata().unwrap().len(), 0);

    file.write(bytes).unwrap();
    assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64);
    // Test opening, reading and closing a file.
    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    // Reading 0 bytes should not move the file pointer.
    file.read(&mut []).unwrap();
    // Reading until EOF should get the whole text.
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_clone() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_file_clone.txt", bytes);

    // Cloning a file should be successful.
    let file = File::open(&path).unwrap();
    let mut cloned = file.try_clone().unwrap();
    // Reading from a cloned file should get the same text.
    let mut contents = Vec::new();
    cloned.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_seek() {
    let bytes = b"Hello, entire World!\n";
    let path = prepare_with_content("miri_test_fs_seek.txt", bytes);

    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that seeking to the beginning and reading until EOF gets the text again.
    file.seek(SeekFrom::Start(0)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test seeking relative to the end of the file.
    file.seek(SeekFrom::End(-1)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[bytes.len() - 1..], contents.as_slice());
    // Test seeking relative to the current position.
    file.seek(SeekFrom::Start(5)).unwrap();
    file.seek(SeekFrom::Current(-3)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[2..], contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> {
    // Test that the file metadata is correct.
    let metadata = path.metadata()?;
    // `path` should point to a file.
    assert!(metadata.is_file());
    // The size of the file must be equal to the number of written bytes.
    assert_eq!(bytes.len() as u64, metadata.len());
    Ok(())
}

fn test_metadata() {
    let bytes = b"Hello, meta-World!\n";
    let path = prepare_with_content("miri_test_fs_metadata.txt", bytes);

    // Test that metadata of an absolute path is correct.
    check_metadata(bytes, &path).unwrap();
    // Test that metadata of a relative path is correct.
    std::env::set_current_dir(path.parent().unwrap()).unwrap();
    check_metadata(bytes, Path::new(path.file_name().unwrap())).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_symlink() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_link_target.txt", bytes);
    let symlink_path = prepare("miri_test_fs_symlink.txt");

    // Creating a symbolic link should succeed.
    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
    // Test that the symbolic link has the same contents as the file.
    let mut symlink_file = File::open(&symlink_path).unwrap();
    let mut contents = Vec::new();
    symlink_file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that metadata of a symbolic link is correct.
    check_metadata(bytes, &symlink_path).unwrap();
    // Test that the metadata of a symbolic link is correct when not following it.
    assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
    // Removing symbolic link should succeed.
    remove_file(&symlink_path).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_errors() {
    let bytes = b"Hello, World!\n";
    let path = prepare("miri_test_fs_errors.txt");

    // The following tests also check that the `__errno_location()` shim is working properly.
    // Opening a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind());
    // Removing a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind());
    // Reading the metadata of a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(bytes, &path).unwrap_err().kind());
}

fn test_rename() {
    // Renaming a file should succeed.
    let path1 = prepare("miri_test_fs_rename_source.txt");
    let path2 = prepare("miri_test_fs_rename_destination.txt");

    let file = File::create(&path1).unwrap();
    drop(file);

    // Renaming should succeed
    rename(&path1, &path2).unwrap();
    // Check that the old file path isn't present
    assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind());
    // Check that the file has moved successfully
    assert!(path2.metadata().unwrap().is_file());

    // Renaming a nonexistent file should fail
    assert_eq!(ErrorKind::NotFound, rename(&path1, &path2).unwrap_err().kind());

    remove_file(&path2).unwrap();
}

fn test_directory() {
    let dir_path = prepare_dir("miri_test_fs_dir");
    // Creating a directory should succeed.
    create_dir(&dir_path).unwrap();
    // Test that the metadata of a directory is correct.
    assert!(dir_path.metadata().unwrap().is_dir());

    // Create some files inside the directory
    let path_1 = dir_path.join("test_file_1");
    drop(File::create(&path_1).unwrap());
    let path_2 = dir_path.join("test_file_2");
    drop(File::create(&path_2).unwrap());
    // Test that the files are present inside the directory
    let mut dir_iter = read_dir(&dir_path).unwrap();
    let first_dir_entry = dir_iter.next().unwrap().unwrap();
    let second_dir_entry = dir_iter.next().unwrap().unwrap();
    assert!(
        first_dir_entry.file_name() == "test_file_1" ||
        first_dir_entry.file_name() == "test_file_2",
        "File name was {:?} instead of test_file_1 or test_file_2",
        first_dir_entry.file_name(),
    );
    assert!(
        second_dir_entry.file_name() == "test_file_1" ||
        second_dir_entry.file_name() == "test_file_2",
        "File name was {:?} instead of test_file_1 or test_file_2",
        second_dir_entry.file_name(),
    );
    assert!(dir_iter.next().is_none());
    drop(dir_iter);
    // Clean up the files in the directory
    remove_file(&path_1).unwrap();
    remove_file(&path_2).unwrap();

    // Deleting the directory should succeed.
    remove_dir(&dir_path).unwrap();
    // Reading the metadata of a non-existent file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(&[], &dir_path).unwrap_err().kind());
}
<commit_msg>Rewrite fs tests<commit_after>// ignore-windows: File handling is not implemented yet
// compile-flags: -Zmiri-disable-isolation

use std::fs::{File, create_dir, read_dir, remove_dir, remove_dir_all, remove_file, rename};
use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom};
use std::path::{PathBuf, Path};

fn main() {
    test_file();
    test_file_clone();
    test_seek();
    test_metadata();
    test_symlink();
    test_errors();
    test_rename();
    test_directory();
}

/// Prepare: compute filename and make sure the file does not exist.
fn prepare(filename: &str) -> PathBuf {
    let tmp = std::env::temp_dir();
    let path = tmp.join(filename);
    // Clean the paths for robustness.
    remove_file(&path).ok();
    path
}

/// Prepare directory: compute directory name and make sure it does not exist.
fn prepare_dir(dirname: &str) -> PathBuf {
    let tmp = std::env::temp_dir();
    let path = tmp.join(&dirname);
    // Clean the directory for robustness.
    remove_dir_all(&path).ok();
    path
}

/// Prepare like above, and also write some initial content to the file.
fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf {
    let path = prepare(filename);
    let mut file = File::create(&path).unwrap();
    file.write(content).unwrap();
    path
}

fn test_file() {
    let bytes = b"Hello, World!\n";
    let path = prepare("miri_test_fs_file.txt");

    // Test creating, writing and closing a file (closing is tested when `file` is dropped).
    let mut file = File::create(&path).unwrap();
    // Writing 0 bytes should not change the file contents.
    file.write(&mut []).unwrap();
    assert_eq!(file.metadata().unwrap().len(), 0);

    file.write(bytes).unwrap();
    assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64);
    // Test opening, reading and closing a file.
    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    // Reading 0 bytes should not move the file pointer.
    file.read(&mut []).unwrap();
    // Reading until EOF should get the whole text.
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_clone() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_file_clone.txt", bytes);

    // Cloning a file should be successful.
    let file = File::open(&path).unwrap();
    let mut cloned = file.try_clone().unwrap();
    // Reading from a cloned file should get the same text.
    let mut contents = Vec::new();
    cloned.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_seek() {
    let bytes = b"Hello, entire World!\n";
    let path = prepare_with_content("miri_test_fs_seek.txt", bytes);

    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that seeking to the beginning and reading until EOF gets the text again.
    file.seek(SeekFrom::Start(0)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test seeking relative to the end of the file.
    file.seek(SeekFrom::End(-1)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[bytes.len() - 1..], contents.as_slice());
    // Test seeking relative to the current position.
    file.seek(SeekFrom::Start(5)).unwrap();
    file.seek(SeekFrom::Current(-3)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[2..], contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> {
    // Test that the file metadata is correct.
    let metadata = path.metadata()?;
    // `path` should point to a file.
    assert!(metadata.is_file());
    // The size of the file must be equal to the number of written bytes.
    assert_eq!(bytes.len() as u64, metadata.len());
    Ok(())
}

fn test_metadata() {
    let bytes = b"Hello, meta-World!\n";
    let path = prepare_with_content("miri_test_fs_metadata.txt", bytes);

    // Test that metadata of an absolute path is correct.
    check_metadata(bytes, &path).unwrap();
    // Test that metadata of a relative path is correct.
    std::env::set_current_dir(path.parent().unwrap()).unwrap();
    check_metadata(bytes, Path::new(path.file_name().unwrap())).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_symlink() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_link_target.txt", bytes);
    let symlink_path = prepare("miri_test_fs_symlink.txt");

    // Creating a symbolic link should succeed.
    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
    // Test that the symbolic link has the same contents as the file.
    let mut symlink_file = File::open(&symlink_path).unwrap();
    let mut contents = Vec::new();
    symlink_file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that metadata of a symbolic link is correct.
    check_metadata(bytes, &symlink_path).unwrap();
    // Test that the metadata of a symbolic link is correct when not following it.
    assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
    // Removing symbolic link should succeed.
    remove_file(&symlink_path).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_errors() {
    let bytes = b"Hello, World!\n";
    let path = prepare("miri_test_fs_errors.txt");

    // The following tests also check that the `__errno_location()` shim is working properly.
    // Opening a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind());
    // Removing a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind());
    // Reading the metadata of a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(bytes, &path).unwrap_err().kind());
}

fn test_rename() {
    // Renaming a file should succeed.
    let path1 = prepare("miri_test_fs_rename_source.txt");
    let path2 = prepare("miri_test_fs_rename_destination.txt");

    let file = File::create(&path1).unwrap();
    drop(file);

    // Renaming should succeed
    rename(&path1, &path2).unwrap();
    // Check that the old file path isn't present
    assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind());
    // Check that the file has moved successfully
    assert!(path2.metadata().unwrap().is_file());

    // Renaming a nonexistent file should fail
    assert_eq!(ErrorKind::NotFound, rename(&path1, &path2).unwrap_err().kind());

    remove_file(&path2).unwrap();
}

fn test_directory() {
    let dir_path = prepare_dir("miri_test_fs_dir");
    // Creating a directory should succeed.
    create_dir(&dir_path).unwrap();
    // Test that the metadata of a directory is correct.
    assert!(dir_path.metadata().unwrap().is_dir());

    // Create some files inside the directory
    let path_1 = dir_path.join("test_file_1");
    drop(File::create(&path_1).unwrap());
    let path_2 = dir_path.join("test_file_2");
    drop(File::create(&path_2).unwrap());
    // Test that the files are present inside the directory
    let dir_iter = read_dir(&dir_path).unwrap();
    let mut file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::<Vec<_>>();
    file_names.sort_unstable();
    assert_eq!(file_names, vec!["test_file_1", "test_file_2"]);
    // Clean up the files in the directory
    remove_file(&path_1).unwrap();
    remove_file(&path_2).unwrap();

    // Deleting the directory should succeed.
    remove_dir(&dir_path).unwrap();
    // Reading the metadata of a non-existent file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(&[], &dir_path).unwrap_err().kind());
}
<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashSet};
use reporter::{Diagnostic, Note, Severity};

#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, Clone)]
enum MarkerStyle {
    // ~~~~~ or ____~
    Secondary,
    // ^^^^^ or ____^
    Primary,
}

impl MarkerStyle {
    fn from_note_index(index: usize) -> MarkerStyle {
        if index == 0 {
            MarkerStyle::Primary
        } else {
            MarkerStyle::Secondary
        }
    }

    fn to_marker_part(self, is_arrow: bool) -> MarkerPart {
        match self {
            MarkerStyle::Primary => {
                if is_arrow {
                    MarkerPart::ArrowPrimary
                } else {
                    MarkerPart::PrimaryMarker
                }
            }
            MarkerStyle::Secondary => {
                if is_arrow {
                    MarkerPart::ArrowSecondary
                } else {
                    MarkerPart::SecondaryMarker
                }
            }
        }
    }
}

#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, Clone)]
enum MarkerPart {
    None,
    ArrowBottom,
    SecondaryMarker,
    PrimaryMarker,
    ArrowSecondary,
    ArrowPrimary,
    SingleColumn
}

impl MarkerPart {
    fn or(self, other: MarkerPart) -> MarkerPart {
        ::std::cmp::max(self, other)
    }

    fn to_char(self) -> char {
        match self {
            MarkerPart::None => ' ',
            MarkerPart::ArrowBottom => '_',
            MarkerPart::SecondaryMarker |
            MarkerPart::ArrowSecondary => '~',
            MarkerPart::PrimaryMarker |
            MarkerPart::ArrowPrimary => '^',
            MarkerPart::SingleColumn => '|',
        }
    }
}

#[derive(Debug, Clone)]
enum LineMarker<'a> {
    FromStart {
        connect_col: u32,
        arrow_col: u32,
        message: Option<&'a str>,
        style: MarkerStyle,
    },
    FromTo {
        start_col: u32,
        end_col: u32,
        message: Option<&'a str>,
        style: MarkerStyle,
    },
}

impl<'a> LineMarker<'a> {
    fn message(&self) -> Option<&str> {
        match *self {
            LineMarker::FromStart { message, .. } |
            LineMarker::FromTo { message, .. } => message,
        }
    }

    fn end_col(&self) -> u32 {
        match *self {
            LineMarker::FromStart { arrow_col, .. } => arrow_col + 1,
            LineMarker::FromTo { end_col, .. } => end_col,
        }
    }

    fn is_arrow(&self) -> bool {
        match *self {
            LineMarker::FromStart { .. } => true,
            LineMarker::FromTo { .. } => false,
        }
    }
}

struct Printer<'a> {
    lines: Vec<&'a str>,
    // use BTreeMap here so that we can iterate annotated lines in order
    line_markers: BTreeMap<u32, Vec<LineMarker<'a>>>,
    next_connect_col: u32,
    full_connection_cols: HashSet<u32>,
    number_space: usize,
}

impl<'a> Printer<'a> {
    fn new(source: &'a str) -> Self {
        Printer {
            lines: source.lines().map(str::trim_right).collect(),
            line_markers: BTreeMap::new(),
            next_connect_col: 0,
            full_connection_cols: HashSet::new(),
            number_space: 0,
        }
    }

    fn pretty_print(&mut self, diagnostic: &'a Diagnostic) {
        match diagnostic.severity {
            Severity::Error => {
                println!("error: {}", diagnostic.message);
            }
            Severity::Warning => {
                println!("warning: {}", diagnostic.message);
            }
        }
        if diagnostic.notes.len() > 0 {
            self.print_notes(&diagnostic.notes);
        }
    }

    fn print_notes(&mut self, notes: &'a [Note]) {
        assert!(self.line_markers.is_empty());
        assert_eq!(self.next_connect_col, 0);
        assert!(self.full_connection_cols.is_empty());
        for (index, note) in notes.iter().enumerate() {
            self.add_note_markers(note, MarkerStyle::from_note_index(index));
        }
        for markers in self.line_markers.values_mut() {
            markers.sort_by_key(LineMarker::end_col);
        }
        assert!(!self.line_markers.is_empty());
        let last_line = *self.line_markers.keys().next_back().unwrap();
        self.number_space = number_length(last_line) as usize;
        self.print_annotations();
        self.line_markers.clear();
        assert!(self.full_connection_cols.is_empty());
        self.next_connect_col = 0;
    }

    fn add_note_markers(&mut self, note: &'a Note, style: MarkerStyle) {
        if note.span.start.line == note.span.end.line {
            self.add_line_marker(note.span.start.line, LineMarker::FromTo {
                start_col: note.span.start.column,
                end_col: note.span.end.column,
                message: note.message.as_ref().map(AsRef::as_ref),
                style,
            });
        } else {
            let connect_col = self.next_connect_col;
            self.next_connect_col += 2;
            self.add_line_marker(note.span.start.line, LineMarker::FromStart {
                connect_col,
                arrow_col: note.span.start.column,
                message: None,
                style,
            });
            self.add_line_marker(note.span.end.line, LineMarker::FromStart {
                connect_col,
                arrow_col: note.span.end.column - 1,
                message: note.message.as_ref().map(AsRef::as_ref),
                style,
            });
        }
    }

    fn add_line_marker(&mut self, line: u32, marker: LineMarker<'a>) {
        self.line_markers
            .entry(line)
            .or_insert_with(Vec::new)
            .push(marker);
    }

    fn print_annotations(&mut self) {
        let line_markers = ::std::mem::replace(&mut self.line_markers, BTreeMap::new());
        let mut last_printed = None;
        for (line, markers) in line_markers {
            if let Some(prev) = last_printed {
                if self.full_connection_cols.len() > 0 {
                    if line - prev > 3 {
                        self.print_line(prev + 1);
                        self.print_gap_line();
                        self.print_line(line - 1);
                    } else {
                        for line in (prev + 1)..line {
                            self.print_line(line);
                        }
                    }
                } else if line - prev > 1 {
                    self.print_gap_line();
                }
            }
            last_printed = Some(line);
            self.print_line_and_markers(line, markers);
        }
    }

    fn print_line_and_markers(&mut self, line: u32, mut markers: Vec<LineMarker>) {
        assert!(markers.len() > 0, "line has no markers");
        self.print_line(line);
        self.print_immediate_markers(&markers);
        // last span has its message printed inline
        println!(" {}", markers
            .iter()
            .next_back()
            .unwrap()
            .message()
            .unwrap_or(""));
        markers.pop();

        // non-arrow markers without messages don't extend below first line
        markers.retain(|m| m.message().is_some() || m.is_arrow());

        // possibly print additional line so that instead of
        //      let x = 1;
        //          ~~~  ~ first note
        //            second note
        // we would get
        //      let x = 1;
        //          ~~~  ~ first note
        //            |
        //            second note
        match markers.iter().next_back().cloned() {
            Some(LineMarker::FromTo { end_col, .. }) => {
                self.print_markers(&markers, end_col);
                println!();
            }
            Some(LineMarker::FromStart { arrow_col, message, .. })
                if message.is_some() =>
            {
                self.print_markers(&markers, arrow_col + 1);
                println!();
            }
            _ => {}
        }
        for i in (1..(markers.len() + 1)).rev() {
            let markers = &markers[0..i];
            match &markers[i - 1] {
                &LineMarker::FromTo { end_col, message, .. } => {
                    self.print_markers(markers, end_col - 1);
                    println!("{}", message.unwrap_or(""));
                }
                &LineMarker::FromStart { arrow_col, message, .. } => {
                    self.print_markers(markers, arrow_col + 2);
                    println!("{}", message.unwrap_or(""));
                }
            }
        }
    }

    fn print_line(&mut self, line: u32) {
        self.print_line_header(Some(line), None);
        for ch in self.lines.get((line - 1) as usize).unwrap_or(&"").chars() {
            match ch {
                // print these chars as one space, otherwise
                // they will break note alignment with code
                '\t' | '\r' => print!(" "),
                ch => print!("{}", ch),
            }
        }
        println!();
    }

    fn print_line_header(&mut self, line: Option<u32>, arrow_from: Option<u32>) {
        if let Some(line) = line {
            print!("{: >width$} |  ", line, width = self.number_space);
        } else {
            print!("{: >width$} |  ", "", width = self.number_space);
        }
        for col in 0..self.next_connect_col {
            if self.full_connection_cols.contains(&col) {
                print!("|");
            } else {
                match arrow_from {
                    Some(c) if c < col => print!("_"),
                    _ => print!(" "),
                }
            }
            if arrow_from == Some(col) {
                if self.full_connection_cols.contains(&col) {
                    self.full_connection_cols.remove(&col);
                } else {
                    self.full_connection_cols.insert(col);
                }
            }
        }
    }

    fn print_gap_line(&mut self) {
        print!("{: <width$}", "...", width = self.number_space + 4);
        for col in 0..self.next_connect_col {
            if self.full_connection_cols.contains(&col) {
                print!("|");
            } else {
                print!(" ");
            }
        }
        println!();
    }

    fn print_immediate_markers(&mut self, markers: &[LineMarker]) {
        let (connect, arrow_end) = match markers.iter().next_back().unwrap() {
            &LineMarker::FromStart { connect_col, arrow_col, .. } => {
                (Some(connect_col), arrow_col - 1)
            }
            _ => {
                (None, 0)
            }
        };
        self.print_line_header(None, connect);
        let last_col = markers.iter().next_back().unwrap().end_col();
        for col in 1..last_col {
            let mut part = MarkerPart::None;
            if col <= arrow_end {
                part = MarkerPart::ArrowBottom;
            }
            for (index, marker) in markers.iter().rev().enumerate() {
                match *marker {
                    LineMarker::FromStart { arrow_col, style, .. } => {
                        if arrow_col == col {
                            part = part.or(style.to_marker_part(true));
                        }
                    }
                    LineMarker::FromTo { start_col, end_col, style, message } => {
                        if start_col <= col && col < end_col {
                            part = part.or(style.to_marker_part(false));
                        }
                        if start_col == col
                            && end_col == start_col + 1 // marker is one col wide
                            && index > 0 // and not the last one in line
                            && message.is_some() // and has a message
                            && style != MarkerStyle::Primary // and it is not primary
                        {
                            part = part.or(MarkerPart::SingleColumn);
                        }
                    }
                }
            }
            print!("{}", part.to_char());
        }
    }

    fn print_markers(&mut self, markers: &[LineMarker], last_col: u32) {
        let (connect, arrow_end) = match markers.iter().next_back().unwrap() {
            &LineMarker::FromStart { connect_col, arrow_col, .. } => {
                (Some(connect_col), arrow_col - 1)
            }
            _ => {
                (None, 0)
            }
        };
        self.print_line_header(None, connect);
        for col in 1..last_col {
            let mut part = MarkerPart::None;
            if col <= arrow_end {
                part = MarkerPart::ArrowBottom;
            }
            for marker in markers.iter().rev() {
                match *marker {
                    LineMarker::FromStart { arrow_col, .. } => {
                        if arrow_col == col {
                            part = MarkerPart::SingleColumn;
                        }
                    }
                    LineMarker::FromTo { end_col, message, .. } => {
                        if end_col == col + 1 && message.is_some() {
                            part = MarkerPart::SingleColumn;
                        }
                    }
                }
            }
            print!("{}", part.to_char());
        }
    }
}

fn number_length(mut num: u32) -> u32 {
    let mut len = 1;
    while num >= 10 {
        len += 1;
        num /= 10;
    }
    len
}

pub fn print_diagnostic(source: &str, diagnostic: &Diagnostic) {
    Printer::new(source).pretty_print(diagnostic)
}

pub fn print_diagnostics(source: &str, diagnostics: &[Diagnostic]) {
    let mut printer = Printer::new(source);
    for diagnostic in diagnostics {
        printer.pretty_print(diagnostic);
        println!("");
    }
}
<commit_msg>fix crash in diagnostic printing<commit_after>use std::collections::{BTreeMap, HashSet};
use reporter::{Diagnostic, Note, Severity};

#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, Clone)]
enum MarkerStyle {
    // ~~~~~ or ____~
    Secondary,
    // ^^^^^ or ____^
    Primary,
}

impl MarkerStyle {
    fn from_note_index(index: usize) -> MarkerStyle {
        if index == 0 {
            MarkerStyle::Primary
        } else {
            MarkerStyle::Secondary
        }
    }

    fn to_marker_part(self, is_arrow: bool) -> MarkerPart {
        match self {
            MarkerStyle::Primary => {
                if is_arrow {
                    MarkerPart::ArrowPrimary
                } else {
                    MarkerPart::PrimaryMarker
                }
            }
            MarkerStyle::Secondary => {
                if is_arrow {
                    MarkerPart::ArrowSecondary
                } else {
                    MarkerPart::SecondaryMarker
                }
            }
        }
    }
}

#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, Clone)]
enum MarkerPart {
    None,
    ArrowBottom,
    SecondaryMarker,
    PrimaryMarker,
    ArrowSecondary,
    ArrowPrimary,
    SingleColumn
}

impl MarkerPart {
    fn or(self, other: MarkerPart) -> MarkerPart {
        ::std::cmp::max(self, other)
    }

    fn to_char(self) -> char {
        match self {
            MarkerPart::None => ' ',
            MarkerPart::ArrowBottom => '_',
            MarkerPart::SecondaryMarker |
            MarkerPart::ArrowSecondary => '~',
            MarkerPart::PrimaryMarker |
            MarkerPart::ArrowPrimary => '^',
            MarkerPart::SingleColumn => '|',
        }
    }
}

#[derive(Debug, Clone)]
enum LineMarker<'a> {
    FromStart {
        connect_col: u32,
        arrow_col: u32,
        message: Option<&'a str>,
        style: MarkerStyle,
    },
    FromTo {
        start_col: u32,
        end_col: u32,
        message: Option<&'a str>,
        style: MarkerStyle,
    },
}

impl<'a> LineMarker<'a> {
    fn message(&self) -> Option<&str> {
        match *self {
            LineMarker::FromStart { message, .. } |
            LineMarker::FromTo { message, .. } => message,
        }
    }

    fn end_col(&self) -> u32 {
        match *self {
            LineMarker::FromStart { arrow_col, .. } => arrow_col + 1,
            LineMarker::FromTo { end_col, .. } => end_col,
        }
    }

    fn is_arrow(&self) -> bool {
        match *self {
            LineMarker::FromStart { .. } => true,
            LineMarker::FromTo { .. } => false,
        }
    }
}

struct Printer<'a> {
    lines: Vec<&'a str>,
    // use BTreeMap here so that we can iterate annotated lines in order
    line_markers: BTreeMap<u32, Vec<LineMarker<'a>>>,
    next_connect_col: u32,
    full_connection_cols: HashSet<u32>,
    number_space: usize,
}

impl<'a> Printer<'a> {
    fn new(source: &'a str) -> Self {
        Printer {
            lines: source.lines().map(str::trim_right).collect(),
            line_markers: BTreeMap::new(),
            next_connect_col: 0,
            full_connection_cols: HashSet::new(),
            number_space: 0,
        }
    }

    fn pretty_print(&mut self, diagnostic: &'a Diagnostic) {
        match diagnostic.severity {
            Severity::Error => {
                println!("error: {}", diagnostic.message);
            }
            Severity::Warning => {
                println!("warning: {}", diagnostic.message);
            }
        }
        if diagnostic.notes.len() > 0 {
            self.print_notes(&diagnostic.notes);
        }
    }

    fn print_notes(&mut self, notes: &'a [Note]) {
        assert!(self.line_markers.is_empty());
        assert_eq!(self.next_connect_col, 0);
        assert!(self.full_connection_cols.is_empty());
        for (index, note) in notes.iter().enumerate() {
            self.add_note_markers(note, MarkerStyle::from_note_index(index));
        }
        for markers in self.line_markers.values_mut() {
            markers.sort_by_key(LineMarker::end_col);
        }
        assert!(!self.line_markers.is_empty());
        let last_line = *self.line_markers.keys().next_back().unwrap();
        self.number_space = number_length(last_line) as usize;
        self.print_annotations();
        self.line_markers.clear();
        assert!(self.full_connection_cols.is_empty());
        self.next_connect_col = 0;
    }

    fn add_note_markers(&mut self, note: &'a Note, style: MarkerStyle) {
        if note.span.start.line == note.span.end.line {
            self.add_line_marker(note.span.start.line, LineMarker::FromTo {
                start_col: note.span.start.column,
                end_col: note.span.end.column,
                message: note.message.as_ref().map(AsRef::as_ref),
                style,
            });
        } else {
            let connect_col = self.next_connect_col;
            self.next_connect_col += 2;
            self.add_line_marker(note.span.start.line, LineMarker::FromStart {
                connect_col,
                arrow_col: note.span.start.column,
                message: None,
                style,
            });
            self.add_line_marker(note.span.end.line, LineMarker::FromStart {
                connect_col,
                arrow_col: note.span.end.column - 1,
                message: note.message.as_ref().map(AsRef::as_ref),
                style,
            });
        }
    }

    fn add_line_marker(&mut self, line: u32, marker: LineMarker<'a>) {
        self.line_markers
            .entry(line)
            .or_insert_with(Vec::new)
            .push(marker);
    }

    fn print_annotations(&mut self) {
        let line_markers = ::std::mem::replace(&mut self.line_markers, BTreeMap::new());
        let mut last_printed = None;
        for (line, markers) in line_markers {
            if let Some(prev) = last_printed {
                if self.full_connection_cols.len() > 0 {
                    if line - prev > 3 {
                        self.print_line(prev + 1);
                        self.print_gap_line();
                        self.print_line(line - 1);
                    } else {
                        for line in (prev + 1)..line {
                            self.print_line(line);
                        }
                    }
                } else if line - prev > 1 {
                    self.print_gap_line();
                }
            }
            last_printed = Some(line);
            self.print_line_and_markers(line, markers);
        }
    }

    fn print_line_and_markers(&mut self, line: u32, mut markers: Vec<LineMarker>) {
        assert!(markers.len() > 0, "line has no markers");
        self.print_line(line);
        self.print_immediate_markers(&markers);
        // last span has its message printed inline
        println!(" {}", markers
            .iter()
            .next_back()
            .unwrap()
            .message()
            .unwrap_or(""));
        markers.pop();

        // non-arrow markers without messages don't extend below first line
        markers.retain(|m| m.message().is_some() || m.is_arrow());

        // possibly print additional line so that instead of
        //      let x = 1;
        //          ~~~  ~ first note
        //            second note
        // we would get
        //      let x = 1;
        //          ~~~  ~ first note
        //            |
        //            second note
        match markers.iter().next_back().cloned() {
            Some(LineMarker::FromTo { end_col, .. }) => {
                self.print_markers(&markers, end_col);
                println!();
            }
            Some(LineMarker::FromStart { arrow_col, message, .. })
                if message.is_some() =>
            {
                self.print_markers(&markers, arrow_col + 1);
                println!();
            }
            _ => {}
        }
        for i in (1..(markers.len() + 1)).rev() {
            let markers = &markers[0..i];
            match &markers[i - 1] {
                &LineMarker::FromTo { end_col, message, .. } => {
                    self.print_markers(markers, end_col - 1);
                    println!("{}", message.unwrap_or(""));
                }
                &LineMarker::FromStart { arrow_col, message, .. } => {
                    self.print_markers(markers, arrow_col + 2);
                    println!("{}", message.unwrap_or(""));
                }
            }
        }
    }

    fn print_line(&mut self, line: u32) {
        self.print_line_header(Some(line), None);
        for ch in self.lines.get((line - 1) as usize).unwrap_or(&"").chars() {
            match ch {
                // print these chars as one space, otherwise
                // they will break note alignment with code
                '\t' | '\r' => print!(" "),
                ch => print!("{}", ch),
            }
        }
        println!();
    }

    fn print_line_header(&mut self, line: Option<u32>, arrow_from: Option<u32>) {
        if let Some(line) = line {
            print!("{: >width$} |  ", line, width = self.number_space);
        } else {
            print!("{: >width$} |  ", "", width = self.number_space);
        }
        for col in 0..self.next_connect_col {
            if self.full_connection_cols.contains(&col) {
                print!("|");
            } else {
                match arrow_from {
                    Some(c) if c < col => print!("_"),
                    _ => print!(" "),
                }
            }
            if arrow_from == Some(col) {
                if self.full_connection_cols.contains(&col) {
                    self.full_connection_cols.remove(&col);
                } else {
                    self.full_connection_cols.insert(col);
                }
            }
        }
    }

    fn print_gap_line(&mut self) {
        print!("{: <width$}", "...", width = self.number_space + 4);
        for col in 0..self.next_connect_col {
            if self.full_connection_cols.contains(&col) {
                print!("|");
            } else {
                print!(" ");
            }
        }
        println!();
    }

    fn print_immediate_markers(&mut self, markers: &[LineMarker]) {
        let (connect, arrow_end) = match markers.iter().next_back().unwrap() {
            &LineMarker::FromStart { connect_col, arrow_col, .. } => {
                (Some(connect_col), arrow_col.saturating_sub(1))
            }
            _ => {
                (None, 0)
            }
        };
        self.print_line_header(None, connect);
        let last_col = markers.iter().next_back().unwrap().end_col();
        for col in 1..last_col {
            let mut part = MarkerPart::None;
            if col <= arrow_end {
                part = MarkerPart::ArrowBottom;
            }
            for (index, marker) in markers.iter().rev().enumerate() {
                match *marker {
                    LineMarker::FromStart { arrow_col, style, .. } => {
                        if arrow_col == col {
                            part = part.or(style.to_marker_part(true));
                        }
                    }
                    LineMarker::FromTo { start_col, end_col, style, message } => {
                        if start_col <= col && col < end_col {
                            part = part.or(style.to_marker_part(false));
                        }
                        if start_col == col
                            && end_col == start_col + 1 // marker is one col wide
                            && index > 0 // and not the last one in line
                            && message.is_some() // and has a message
                            && style != MarkerStyle::Primary // and it is not primary
                        {
                            part = part.or(MarkerPart::SingleColumn);
                        }
                    }
                }
            }
            print!("{}", part.to_char());
        }
    }

    fn print_markers(&mut self, markers: &[LineMarker], last_col: u32) {
        let (connect, arrow_end) = match markers.iter().next_back().unwrap() {
            &LineMarker::FromStart { connect_col, arrow_col, .. } => {
                (Some(connect_col), arrow_col - 1)
            }
            _ => {
                (None, 0)
            }
        };
        self.print_line_header(None, connect);
        for col in 1..last_col {
            let mut part = MarkerPart::None;
            if col <= arrow_end {
                part = MarkerPart::ArrowBottom;
            }
            for marker in markers.iter().rev() {
                match *marker {
                    LineMarker::FromStart { arrow_col, .. } => {
                        if arrow_col == col {
                            part = MarkerPart::SingleColumn;
                        }
                    }
                    LineMarker::FromTo { end_col, message, .. } => {
                        if end_col == col + 1 && message.is_some() {
                            part = MarkerPart::SingleColumn;
                        }
                    }
                }
            }
            print!("{}", part.to_char());
        }
    }
}

fn number_length(mut num: u32) -> u32 {
    let mut len = 1;
    while num >= 10 {
        len += 1;
        num /= 10;
    }
    len
}

pub fn print_diagnostic(source: &str, diagnostic: &Diagnostic) {
    Printer::new(source).pretty_print(diagnostic)
}

pub fn print_diagnostics(source: &str, diagnostics: &[Diagnostic]) {
    let mut printer = Printer::new(source);
    for diagnostic in diagnostics {
        printer.pretty_print(diagnostic);
        println!("");
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

use git2::{Repository, Signature};
use toml::Value;

use libimagerror::into::IntoError;
use libimagerror::trace::trace_error;
use libimagstore::hook::error::CustomData;
use libimagstore::hook::error::HookErrorKind as HEK;
use libimagstore::hook::result::HookResult;

use vcs::git::result::Result;
use vcs::git::error::{MapErrInto, GitHookErrorKind as GHEK};
use vcs::git::config::{author_name, author_mail, committer_name, committer_mail};

struct Person<'a> {
    pub name: &'a str,
    pub mail: &'a str,
}

impl<'a> Person<'a> {
    fn new(name: &'a str, mail: &'a str) -> Person<'a> {
        Person { name: name, mail: mail }
    }
}

pub struct Runtime<'a> {
    repository: Option<Repository>,
    author: Option<Person<'a>>,
    committer: Option<Person<'a>>,

    config: Option<Value>,
}

impl<'a> Runtime<'a> {

    pub fn new(storepath: &PathBuf) -> Runtime<'a> {
        Runtime {
            repository: match Repository::open(storepath) {
                Ok(r) => Some(r),
                Err(e) => {
                    trace_error(&e);
                    None
                },
            },

            author: None,
            committer: None,
            config: None,
        }
    }

    pub fn set_config(&mut self, cfg: &Value) -> Result<()> {
        let config = cfg.clone();
        let res = author_name(&config)
            .and_then(|n| author_mail(&config).map(|m| Person::new(n, m)))
            .and_then(|author| {
                committer_name(&config)
                    .and_then(|n| committer_mail(&config).map(|m| (author, Person::new(n, m))))
            })
            .map(|(author, committer)| {
                self.author = Some(author);
                self.committer = Some(committer);
            });
        self.config = Some(config);
        res
    }

    pub fn has_repository(&self) -> bool {
        self.repository.is_some()
    }

    pub fn has_config(&self) -> bool {
        self.config.is_some()
    }

    pub fn config_value_or_err(&self) -> HookResult<&Value> {
        self.config
            .as_ref()
            .ok_or(GHEK::NoConfigError.into_error())
            .map_err_into(GHEK::ConfigError)
            .map_err(Box::new)
            .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
            .map_err(|mut e| e.with_custom_data(CustomData::default().aborting(false)))
    }

    pub fn new_committer_sig(&self) -> Option<Result<Signature>> {
        self.committer
            .as_ref()
            .map(|c| {
                Signature::now(c.name, c.mail)
                    .map_err(|e| GHEK::MkSignature.into_error_with_cause(Box::new(e)))
            })
    }

    pub fn new_committer_sig(&self) -> Option<Result<Signature>> {
        self.committer
            .as_ref()
            .map(|c| {
                Signature::now(c.name, c.mail)
                    .map_err(|e| GHEK::MkSignature.into_error_with_cause(Box::new(e)))
            })
    }

    pub fn repository(&self) -> Result<&Repository> {
        self.repository.as_ref().ok_or(GHEK::MkRepo.into_error())
    }

    pub fn ensure_cfg_branch_is_checked_out(&self) -> HookResult<()> {
        use vcs::git::config::ensure_branch;

        let head = try!(self
                        .repository()
                        .and_then(|r| {
                            r.head().map_err_into(GHEK::HeadFetchError)
                        })
                        .map_err(Box::new)
                        .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e)));

        // TODO: Fail if not on branch? hmmh... I'm not sure
        if head.is_branch() {
            return Err(GHEK::NotOnBranch.into_error())
                .map_err(Box::new)
                .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e));
        }

        // Check out appropriate branch ... or fail
        match ensure_branch(self.config.as_ref()) {
            Ok(Some(s)) => {
                match head.name().map(|name| name == s) {
                    Some(b) => {
                        if b {
                            debug!("Branch already checked out.");
                            Ok(())
                        } else {
                            debug!("Branch not checked out.");
                            unimplemented!()
                        }
                    },

                    None => Err(GHEK::RepositoryBranchNameFetchingError.into_error())
                        .map_err_into(GHEK::RepositoryBranchError)
                        .map_err_into(GHEK::RepositoryError),
                }
            },
            Ok(None) => {
                debug!("No branch to checkout");
                Ok(())
            },

            Err(e) => Err(e).map_err_into(GHEK::RepositoryError),
        }
        .map_err(Box::new)
        .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
    }

}

<commit_msg>Revert "Add Runtime::new_committer_sig()"<commit_after>use std::path::PathBuf;

use git2::{Repository, Signature};
use toml::Value;

use libimagerror::into::IntoError;
use libimagerror::trace::trace_error;
use libimagstore::hook::error::CustomData;
use libimagstore::hook::error::HookErrorKind as HEK;
use libimagstore::hook::result::HookResult;

use vcs::git::result::Result;
use vcs::git::error::{MapErrInto, GitHookErrorKind as GHEK};
use vcs::git::config::{author_name, author_mail, committer_name, committer_mail};

struct Person<'a> {
    pub name: &'a str,
    pub mail: &'a str,
}

impl<'a> Person<'a> {
    fn new(name: &'a str, mail: &'a str) -> Person<'a> {
        Person { name: name, mail: mail }
    }
}

pub struct Runtime<'a> {
    repository: Option<Repository>,
    author: Option<Person<'a>>,
    committer: Option<Person<'a>>,

    config: Option<Value>,
}

impl<'a> Runtime<'a> {

    pub fn new(storepath: &PathBuf) -> Runtime<'a> {
        Runtime {
            repository: match Repository::open(storepath) {
                Ok(r) => Some(r),
                Err(e) => {
                    trace_error(&e);
                    None
                },
            },

            author: None,
            committer: None,
            config: None,
        }
    }

    pub fn set_config(&mut self, cfg: &Value) -> Result<()> {
        let config = cfg.clone();
        let res = author_name(&config)
            .and_then(|n| author_mail(&config).map(|m| Person::new(n, m)))
            .and_then(|author| {
                committer_name(&config)
                    .and_then(|n| committer_mail(&config).map(|m| (author, Person::new(n, m))))
            })
            .map(|(author, committer)| {
                self.author = Some(author);
                self.committer = Some(committer);
            });
        self.config = Some(config);
        res
    }

    pub fn has_repository(&self) -> bool {
        self.repository.is_some()
    }

    pub fn has_config(&self) -> bool {
        self.config.is_some()
    }

    pub fn config_value_or_err(&self) -> HookResult<&Value> {
        self.config
            .as_ref()
            .ok_or(GHEK::NoConfigError.into_error())
            .map_err_into(GHEK::ConfigError)
            .map_err(Box::new)
            .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
            .map_err(|mut e| e.with_custom_data(CustomData::default().aborting(false)))
    }

    pub fn repository(&self) -> Result<&Repository> {
        self.repository.as_ref().ok_or(GHEK::MkRepo.into_error())
    }

    pub fn ensure_cfg_branch_is_checked_out(&self) -> HookResult<()> {
        use vcs::git::config::ensure_branch;

        let head = try!(self
                        .repository()
                        .and_then(|r| {
                            r.head().map_err_into(GHEK::HeadFetchError)
                        })
                        .map_err(Box::new)
                        .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e)));

        // TODO: Fail if not on branch? hmmh... I'm not sure
        if head.is_branch() {
            return Err(GHEK::NotOnBranch.into_error())
                .map_err(Box::new)
                .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e));
        }

        // Check out appropriate branch ... or fail
        match ensure_branch(self.config.as_ref()) {
            Ok(Some(s)) => {
                match head.name().map(|name| name == s) {
                    Some(b) => {
                        if b {
                            debug!("Branch already checked out.");
                            Ok(())
                        } else {
                            debug!("Branch not checked out.");
                            unimplemented!()
                        }
                    },

                    None => Err(GHEK::RepositoryBranchNameFetchingError.into_error())
                        .map_err_into(GHEK::RepositoryBranchError)
                        .map_err_into(GHEK::RepositoryError),
                }
            },
            Ok(None) => {
                debug!("No branch to checkout");
                Ok(())
            },

            Err(e) => Err(e).map_err_into(GHEK::RepositoryError),
        }
        .map_err(Box::new)
        .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
    }

}

<|endoftext|>


<commit_before>use crate::graphics::*;

use mint;

/// A struct containing all the necessary info for drawing a [`Drawable`](trait.Drawable.html).
///
/// This struct implements the `Default` trait, so to set only some parameter
/// you can just do:
///
/// ```rust
/// # use ggez::*;
/// # use ggez::graphics::*;
/// # fn t<P>(ctx: &mut Context, drawable: &P) where P: Drawable {
/// let my_dest = mint::Point2::new(13.0, 37.0);
/// graphics::draw(ctx, drawable, DrawParam::default().dest(my_dest) );
/// # }
/// ```
///
/// As a shortcut, it also implements `From` for a variety of tuple types.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DrawParam {
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image `(0,0 to 1,1)` if omitted.
    pub src: Rect,
    /// The position to draw the graphic expressed as a `Point2`.
    pub dest: mint::Point2<f32>,
    /// The orientation of the graphic in radians.
    pub rotation: f32,
    /// The x/y scale factors expressed as a `Vector2`.
    pub scale: mint::Vector2<f32>,
    /// An offset from the center for transform operations like scale/rotation,
    /// with `0,0` meaning the origin and `1,1` meaning the opposite corner from the origin.
    /// By default these operations are done from the top-left corner, so to rotate something
    /// from the center specify `Point2::new(0.5, 0.5)` here.
    pub offset: mint::Point2<f32>,
    /// A color to draw the target with.
    /// Default: white.
    pub color: Color,
}

impl Default for DrawParam {
    fn default() -> Self {
        DrawParam {
            src: Rect::one(),
            dest: mint::Point2 { x: 0.0, y: 0.0 },
            rotation: 0.0,
            scale: mint::Vector2 { x: 1.0, y: 1.0 },
            offset: mint::Point2 { x: 0.0, y: 0.0 },
            color: WHITE,
        }
    }
}

impl DrawParam {
    /// Create a new DrawParam with default values.
    pub fn new() -> Self {
        Self::default()
    }

    /// Set the source rect
    pub fn src(mut self, src: Rect) -> Self {
        self.src = src;
        self
    }

    /// Set the dest point
    pub fn dest<P>(mut self, dest: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = dest.into();
        self.dest = p;
        self
    }

    /// Set the drawable color.  This will be blended with whatever
    /// color the drawn object already is.
    pub fn color(mut self, color: Color) -> Self {
        self.color = color;
        self
    }

    /// Set the rotation of the drawable.
    pub fn rotation(mut self, rotation: f32) -> Self {
        self.rotation = rotation;
        self
    }

    /// Set the scaling factors of the drawable.
    pub fn scale<V>(mut self, scale: V) -> Self
    where
        V: Into<mint::Vector2<f32>>,
    {
        let p: mint::Vector2<f32> = scale.into();
        self.scale = p;
        self
    }

    /// Set the transformation offset of the drawable.
    pub fn offset<P>(mut self, offset: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = offset.into();
        self.offset = p;
        self
    }

    /// A [`DrawParam`](struct.DrawParam.html) that has been crunched down to a single matrix.
    fn to_na_matrix(&self) -> Matrix4 {
        // Calculate a matrix equivalent to doing this:
        //  type Vec3 = na::Vector3<f32>;
        //  let translate = Matrix4::new_translation(&Vec3::new(self.dest.x, self.dest.y, 0.0));
        //  let offset = Matrix4::new_translation(&Vec3::new(self.offset.x, self.offset.y, 0.0));
        //  let offset_inverse =
        //      Matrix4::new_translation(&Vec3::new(-self.offset.x, -self.offset.y, 0.0));
        //  let axis_angle = Vec3::z() * self.rotation;
        //  let rotation = Matrix4::new_rotation(axis_angle);
        //  let scale = Matrix4::new_nonuniform_scaling(&Vec3::new(self.scale.x, self.scale.y, 1.0));
        //  translate * offset * rotation * scale * offset_inverse
        let cosr = self.rotation.cos();
        let sinr = self.rotation.sin();
        let m00 = cosr * self.scale.x;
        let m01 = -sinr * self.scale.y;
        let m10 = sinr * self.scale.x;
        let m11 = cosr * self.scale.y;
        let m03 = self.offset.x * (1.0 - m00) - self.offset.y * m01 + self.dest.x;
        let m13 = self.offset.y * (1.0 - m11) - self.offset.x * m10 + self.dest.y;
        Matrix4::from_cols_array(&[
            m00, m01, 0.0, m03, m10, m11, 0.0, m13, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
        ])
    }

    /// A [`DrawParam`](struct.DrawParam.html) that has been crunched down to a single
    ///matrix.  Because of this it only contains the transform part (rotation/scale/etc),
    /// with no src/dest/color info.
    pub fn to_matrix(&self) -> mint::ColumnMatrix4<f32> {
        self.to_na_matrix().into()
    }
}

/// Create a `DrawParam` from a location.
/// Note that this takes a single-element tuple.
/// It's a little weird but keeps the trait implementations
/// from clashing.
impl<P> From<(P,)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from(location: (P,)) -> Self {
        DrawParam::new().dest(location.0)
    }
}

/// Create a `DrawParam` from a location and color
impl<P> From<(P, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, color): (P, Color)) -> Self {
        DrawParam::new().dest(location).color(color)
    }
}

/// Create a `DrawParam` from a location, rotation and color
impl<P> From<(P, f32, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, rotation, color): (P, f32, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .color(color)
    }
}

/// Create a `DrawParam` from a location, rotation, offset and color
impl<P> From<(P, f32, P, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, rotation, offset, color): (P, f32, P, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .color(color)
    }
}

/// Create a `DrawParam` from a location, rotation, offset, scale and color
impl<P, V> From<(P, f32, P, V, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
    V: Into<mint::Vector2<f32>>,
{
    fn from((location, rotation, offset, scale, color): (P, f32, P, V, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .scale(scale)
            .color(color)
    }
}

/// A [`DrawParam`](struct.DrawParam.html) that has been crunched down to a single matrix.
/// This is a lot less useful for doing transformations than I'd hoped; basically, we sometimes
/// have to modify parameters of a `DrawParam` based *on* the parameters of a `DrawParam`, for
/// instance when scaling images so that they are in units of pixels.  This makes it really
/// hard to extract scale and rotation and such, so meh.
///
/// It's still useful for a couple internal things though, so it's kept around.
#[derive(Debug, Copy, Clone, PartialEq)]
pub(crate) struct DrawTransform {
    /// The transform matrix for the DrawParams
    pub matrix: Matrix4,
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image (1.0) if omitted.
    pub src: Rect,
    /// A color to draw the target with.
    /// Default: white.
    pub color: Color,
}

impl Default for DrawTransform {
    fn default() -> Self {
        DrawTransform {
            matrix: Matrix4::identity(),
            src: Rect::one(),
            color: WHITE,
        }
    }
}

impl From<DrawParam> for DrawTransform {
    fn from(param: DrawParam) -> Self {
        // TODO: Double-check this all lines up
        let transform = param.to_na_matrix();
        DrawTransform {
            src: param.src,
            color: param.color,
            matrix: transform,
        }
    }
}

impl DrawTransform {
    pub(crate) fn to_instance_properties(&self, srgb: bool) -> InstanceProperties {
        // TODO: Verify 'row arrays' is correct here.
        let mat: [[f32; 4]; 4] = self.matrix.to_cols_array_2d();
        let color: [f32; 4] = if srgb {
            let linear_color: types::LinearColor = self.color.into();
            linear_color.into()
        } else {
            self.color.into()
        };
        InstanceProperties {
            src: self.src.into(),
            col1: mat[0],
            col2: mat[1],
            col3: mat[2],
            col4: mat[3],
            color,
        }
    }
}
<commit_msg>Fix a math bug.<commit_after>use crate::graphics::*;

use mint;

/// A struct containing all the necessary info for drawing a [`Drawable`](trait.Drawable.html).
///
/// This struct implements the `Default` trait, so to set only some parameter
/// you can just do:
///
/// ```rust
/// # use ggez::*;
/// # use ggez::graphics::*;
/// # fn t<P>(ctx: &mut Context, drawable: &P) where P: Drawable {
/// let my_dest = mint::Point2::new(13.0, 37.0);
/// graphics::draw(ctx, drawable, DrawParam::default().dest(my_dest) );
/// # }
/// ```
///
/// As a shortcut, it also implements `From` for a variety of tuple types.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DrawParam {
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image `(0,0 to 1,1)` if omitted.
    pub src: Rect,
    /// The position to draw the graphic expressed as a `Point2`.
    pub dest: mint::Point2<f32>,
    /// The orientation of the graphic in radians.
    pub rotation: f32,
    /// The x/y scale factors expressed as a `Vector2`.
    pub scale: mint::Vector2<f32>,
    /// An offset from the center for transform operations like scale/rotation,
    /// with `0,0` meaning the origin and `1,1` meaning the opposite corner from the origin.
    /// By default these operations are done from the top-left corner, so to rotate something
    /// from the center specify `Point2::new(0.5, 0.5)` here.
    pub offset: mint::Point2<f32>,
    /// A color to draw the target with.
    /// Default: white.
    pub color: Color,
}

impl Default for DrawParam {
    fn default() -> Self {
        DrawParam {
            src: Rect::one(),
            dest: mint::Point2 { x: 0.0, y: 0.0 },
            rotation: 0.0,
            scale: mint::Vector2 { x: 1.0, y: 1.0 },
            offset: mint::Point2 { x: 0.0, y: 0.0 },
            color: WHITE,
        }
    }
}

impl DrawParam {
    /// Create a new DrawParam with default values.
    pub fn new() -> Self {
        Self::default()
    }

    /// Set the source rect
    pub fn src(mut self, src: Rect) -> Self {
        self.src = src;
        self
    }

    /// Set the dest point
    pub fn dest<P>(mut self, dest: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = dest.into();
        self.dest = p;
        self
    }

    /// Set the drawable color.  This will be blended with whatever
    /// color the drawn object already is.
    pub fn color(mut self, color: Color) -> Self {
        self.color = color;
        self
    }

    /// Set the rotation of the drawable.
    pub fn rotation(mut self, rotation: f32) -> Self {
        self.rotation = rotation;
        self
    }

    /// Set the scaling factors of the drawable.
    pub fn scale<V>(mut self, scale: V) -> Self
    where
        V: Into<mint::Vector2<f32>>,
    {
        let p: mint::Vector2<f32> = scale.into();
        self.scale = p;
        self
    }

    /// Set the transformation offset of the drawable.
    pub fn offset<P>(mut self, offset: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = offset.into();
        self.offset = p;
        self
    }

    /// A [`DrawParam`](struct.DrawParam.html) that has been crunched down to a single matrix.
    fn to_na_matrix(&self) -> Matrix4 {
        // Calculate a matrix equivalent to doing this:
        //  type Vec3 = na::Vector3<f32>;
        //  let translate = Matrix4::new_translation(&Vec3::new(self.dest.x, self.dest.y, 0.0));
        //  let offset = Matrix4::new_translation(&Vec3::new(self.offset.x, self.offset.y, 0.0));
        //  let offset_inverse =
        //      Matrix4::new_translation(&Vec3::new(-self.offset.x, -self.offset.y, 0.0));
        //  let axis_angle = Vec3::z() * self.rotation;
        //  let rotation = Matrix4::new_rotation(axis_angle);
        //  let scale = Matrix4::new_nonuniform_scaling(&Vec3::new(self.scale.x, self.scale.y, 1.0));
        //  translate * offset * rotation * scale * offset_inverse
        let cosr = self.rotation.cos();
        let sinr = self.rotation.sin();
        let m00 = cosr * self.scale.x;
        let m01 = -sinr * self.scale.y;
        let m10 = sinr * self.scale.x;
        let m11 = cosr * self.scale.y;
        let m03 = self.offset.x * (1.0 - m00) - self.offset.y * m01 + self.dest.x;
        let m13 = self.offset.y * (1.0 - m11) - self.offset.x * m10 + self.dest.y;
        // Welp, this transpose fixes some bug that makes nothing draw,
        // that was introduced in commit 2c6b3cc03f34fb240f4246f5a68c75bd85b60eae.
        // The best part is, I don't know if this code is wrong, or whether there's
        // some reversed matrix multiply or such somewhere else that this cancel
        // out.  Probably the former though.
        Matrix4::from_cols_array(&[
            m00, m01, 0.0, m03, // oh rustfmt you so fine
            m10, m11, 0.0, m13, // you so fine you blow my mind
            0.0, 0.0, 1.0, 0.0, // but leave my matrix formatting alone
            0.0, 0.0, 0.0, 1.0, // plz
        ])
        .transpose()
    }

    /// A [`DrawParam`](struct.DrawParam.html) that has been crunched down to a single
    ///matrix.  Because of this it only contains the transform part (rotation/scale/etc),
    /// with no src/dest/color info.
    pub fn to_matrix(&self) -> mint::ColumnMatrix4<f32> {
        self.to_na_matrix().into()
    }
}

/// Create a `DrawParam` from a location.
/// Note that this takes a single-element tuple.
/// It's a little weird but keeps the trait implementations
/// from clashing.
impl<P> From<(P,)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from(location: (P,)) -> Self {
        DrawParam::new().dest(location.0)
    }
}

/// Create a `DrawParam` from a location and color
impl<P> From<(P, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, color): (P, Color)) -> Self {
        DrawParam::new().dest(location).color(color)
    }
}

/// Create a `DrawParam` from a location, rotation and color
impl<P> From<(P, f32, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, rotation, color): (P, f32, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .color(color)
    }
}

/// Create a `DrawParam` from a location, rotation, offset and color
impl<P> From<(P, f32, P, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, rotation, offset, color): (P, f32, P, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .color(color)
    }
}

/// Create a `DrawParam` from a location, rotation, offset, scale and color
impl<P, V> From<(P, f32, P, V, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
    V: Into<mint::Vector2<f32>>,
{
    fn from((location, rotation, offset, scale, color): (P, f32, P, V, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .scale(scale)
            .color(color)
    }
}

/// A [`DrawParam`](struct.DrawParam.html) that has been crunched down to a single matrix.
/// This is a lot less useful for doing transformations than I'd hoped; basically, we sometimes
/// have to modify parameters of a `DrawParam` based *on* the parameters of a `DrawParam`, for
/// instance when scaling images so that they are in units of pixels.  This makes it really
/// hard to extract scale and rotation and such, so meh.
///
/// It's still useful for a couple internal things though, so it's kept around.
#[derive(Debug, Copy, Clone, PartialEq)]
pub(crate) struct DrawTransform {
    /// The transform matrix for the DrawParams
    pub matrix: Matrix4,
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image (1.0) if omitted.
    pub src: Rect,
    /// A color to draw the target with.
    /// Default: white.
    pub color: Color,
}

impl Default for DrawTransform {
    fn default() -> Self {
        DrawTransform {
            matrix: Matrix4::identity(),
            src: Rect::one(),
            color: WHITE,
        }
    }
}

impl From<DrawParam> for DrawTransform {
    fn from(param: DrawParam) -> Self {
        // TODO: Double-check this all lines up
        let transform = param.to_na_matrix();
        DrawTransform {
            src: param.src,
            color: param.color,
            matrix: transform,
        }
    }
}

impl DrawTransform {
    pub(crate) fn to_instance_properties(&self, srgb: bool) -> InstanceProperties {
        // TODO: Verify 'row arrays' is correct here.
        let mat: [[f32; 4]; 4] = self.matrix.to_cols_array_2d();
        let color: [f32; 4] = if srgb {
            let linear_color: types::LinearColor = self.color.into();
            linear_color.into()
        } else {
            self.color.into()
        };
        InstanceProperties {
            src: self.src.into(),
            col1: mat[0],
            col2: mat[1],
            col3: mat[2],
            col4: mat[3],
            color,
        }
    }
}
<|endoftext|>


<commit_before>use helpers::{HelperDef};
use registry::{Registry};
use context::{Context};
use render::{RenderContext, RenderError, Helper};

#[derive(Clone, Copy)]
pub struct RawHelper;

impl HelperDef for RawHelper {
    fn call(&self, _: &Context, h: &Helper, _: &Registry, rc: &mut RenderContext) -> Result<(), RenderError> {
        let tpl = h.template();
        if tpl.is_some() {
            try!(rc.writer.write(tpl.unwrap().to_string().into_bytes().as_ref()));
        }
        let ivs = h.inverse();
        if ivs.is_some() {
            try!(rc.writer.write("{{else}}".to_owned().into_bytes().as_ref()));
            try!(rc.writer.write(ivs.unwrap().to_string().into_bytes().as_ref()));
        }

        Ok(())
    }
}

pub static RAW_HELPER: RawHelper = RawHelper;

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};

    #[test]
    fn test_raw_helper () {
        let t = Template::compile("a{{#raw}}{{content}}{{else}}hello{{/raw}}".to_string()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t);

        let r = handlebars.render("t0", &());
        assert_eq!(r.ok().unwrap(), "a{{content}}{{else}}hello");
    }
}
<commit_msg>(feat) update the build-in raw helper [#65]<commit_after>use helpers::{HelperDef};
use registry::{Registry};
use context::{Context};
use render::{Renderable, RenderContext, RenderError, Helper};

#[derive(Clone, Copy)]
pub struct RawHelper;

impl HelperDef for RawHelper {
    fn call(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError> {
        let tpl = h.template();
        if let Some(t) = tpl {
            t.render(c, r, rc)
        } else {
            Ok(())
        }
    }
}

pub static RAW_HELPER: RawHelper = RawHelper;

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};

    #[test]
    fn test_raw_helper () {
        let t = Template::compile("a{{{{raw}}}}{{content}}{{else}}hello{{{{/raw}}}}".to_string()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t);

        let r = handlebars.render("t0", &());
        assert_eq!(r.ok().unwrap(), "a{{content}}{{else}}hello");
    }
}
<|endoftext|>


<commit_before>use sovrin::api::ErrorCode;
use sovrin::api::wallet::{
    sovrin_register_wallet_type,
    sovrin_create_wallet,
    sovrin_open_wallet,
    sovrin_wallet_set_seq_no_for_value,
    sovrin_delete_wallet,
    sovrin_close_wallet
};

use utils::callback::CallbackUtils;
use utils::inmem_wallet::InmemWallet;
use utils::timeout::TimeoutUtils;
use utils::sequence::SequenceUtils;

use std::collections::HashSet;
use std::ffi::CString;
use std::ptr::null;
use std::sync::mpsc::channel;
use std::sync::Mutex;

pub struct WalletUtils {}

impl WalletUtils {
    pub fn register_wallet_type(xtype: &str) -> Result<(), ErrorCode> {
        lazy_static! {
            static ref REGISERED_WALLETS: Mutex<HashSet<String>> = Default::default();
        }

        let mut wallets = REGISERED_WALLETS.lock().unwrap();

        if wallets.contains(xtype) {
            // as registering of plugged wallet with
            return Ok(())
        }

        let (sender, receiver) = channel();

        let cb = Box::new(move |err| {
            sender.send(err).unwrap();
        });

        let (command_handle, cb) = CallbackUtils::closure_to_register_wallet_type_cb(cb);

        let xxtype = CString::new(xtype).unwrap();

        let err = sovrin_register_wallet_type(
            command_handle,
            xxtype.as_ptr(),
            Some(InmemWallet::create),
            Some(InmemWallet::open),
            Some(InmemWallet::set),
            Some(InmemWallet::get),
            Some(InmemWallet::get_not_expied),
            Some(InmemWallet::list),
            Some(InmemWallet::close),
            Some(InmemWallet::delete),
            Some(InmemWallet::free),
            cb
        );

        if err != ErrorCode::Success {
            return Err(err);
        }

        let err = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        wallets.insert(xtype.to_string());
        Ok(())
    }

    pub fn create_wallet(pool_name: &str, wallet_name: &str, xtype: Option<&str>, config: Option<&str>) -> Result<(), ErrorCode> {
        let (sender, receiver) = channel();

        let cb = Box::new(move |err| {
            sender.send(err).unwrap();
        });

        let (command_handle, cb) = CallbackUtils::closure_to_create_wallet_cb(cb);

        let pool_name = CString::new(pool_name).unwrap();
        let wallet_name = CString::new(wallet_name).unwrap();
        let xtype_str = xtype.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("").unwrap());
        let config_str = config.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("").unwrap());

        let err =
            sovrin_create_wallet(command_handle,
                                 pool_name.as_ptr(),
                                 wallet_name.as_ptr(),
                                 if xtype.is_some() { xtype_str.as_ptr() } else { null() },
                                 if config.is_some() { config_str.as_ptr() } else { null() },
                                 null(),
                                 cb);

        if err != ErrorCode::Success {
            return Err(err);
        }

        let err = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        Ok(())
    }

    pub fn open_wallet(wallet_name: &str, config: Option<&str>) -> Result<i32, ErrorCode> {
        let (sender, receiver) = channel();

        let cb = Box::new(move |err, handle| {
            sender.send((err, handle)).unwrap();
        });

        let (command_handle, cb) = CallbackUtils::closure_to_open_wallet_cb(cb);

        let wallet_name = CString::new(wallet_name).unwrap();
        let config_str = config.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("").unwrap());

        let err =
            sovrin_open_wallet(command_handle,
                               wallet_name.as_ptr(),
                               if config.is_some() { config_str.as_ptr() } else { null() },
                               null(),
                               cb);

        if err != ErrorCode::Success {
            return Err(err);
        }

        let (err, wallet_handle) = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        Ok(wallet_handle)
    }

    pub fn create_and_open_wallet(pool_name: &str, xtype: Option<&str>) -> Result<i32, ErrorCode> {
        let (sender, receiver) = channel();
        let (open_sender, open_receiver) = channel();

        let cb = Box::new(move |err| {
            sender.send(err).unwrap();
        });
        let open_cb = Box::new(move |err, handle| {
            open_sender.send((err, handle)).unwrap();
        });

        let (command_handle, cb) = CallbackUtils::closure_to_create_wallet_cb(cb);
        let (open_command_handle, open_cb) = CallbackUtils::closure_to_open_wallet_cb(open_cb);

        let pool_name = CString::new(pool_name).unwrap();
        let wallet_name = CString::new(format!("default-wallet-name-{}", SequenceUtils::get_next_id())).unwrap();
        let xtype = match xtype {
            Some(xtype) => CString::new(xtype).unwrap(),
            None => CString::new("defaukt").unwrap()
        };

        let err =
            sovrin_create_wallet(command_handle,
                                 pool_name.as_ptr(),
                                 wallet_name.as_ptr(),
                                 xtype.as_ptr(),
                                 null(),
                                 null(),
                                 cb);

        if err != ErrorCode::Success {
            return Err(err);
        }

        let err = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        let err =
            sovrin_open_wallet(open_command_handle,
                               wallet_name.as_ptr(),
                               null(),
                               null(),
                               open_cb);

        if err != ErrorCode::Success {
            return Err(err);
        }

        let (err, wallet_handle) = open_receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        Ok(wallet_handle)
    }

    pub fn wallet_set_seq_no_for_value(wallet_handle: i32, value: &str, seq_no: i32) -> Result<(), ErrorCode> {
        let (sender, receiver) = channel();

        let cb = Box::new(move |err| {
            sender.send(err).unwrap();
        });

        let (command_handle, cb) = CallbackUtils::closure_to_wallet_set_seq_no_for_value_cb(cb);

        let value = CString::new(value).unwrap();

        let err =
            sovrin_wallet_set_seq_no_for_value(command_handle,
                                               wallet_handle,
                                               value.as_ptr(),
                                               seq_no,
                                               cb);

        if err != ErrorCode::Success {
            return Err(err);
        }

        let err = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        Ok(())
    }

    pub fn delete_wallet(wallet_name: &str) -> Result<(), ErrorCode> {
        let (sender, receiver) = channel();

        let cb = Box::new(move |err| {
            sender.send(err).unwrap();
        });

        let (command_handle, cb) = CallbackUtils::closure_to_delete_wallet_cb(cb);

        let wallet_name = CString::new(wallet_name).unwrap();

        let err =
            sovrin_delete_wallet(command_handle,
                                 wallet_name.as_ptr(),
                                 null(),
                                 cb);

        if err != ErrorCode::Success {
            return Err(err);
        }

        let err = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        Ok(())
    }

    pub fn close_wallet(wallet_handle: i32) -> Result<(), ErrorCode> {
        let (sender, receiver) = channel();

        let cb = Box::new(move |err| {
            sender.send(err).unwrap();
        });

        let (command_handle, cb) = CallbackUtils::closure_to_delete_wallet_cb(cb);

        let err =
            sovrin_close_wallet(command_handle,
                                wallet_handle,
                                cb);

        if err != ErrorCode::Success {
            return Err(err);
        }

        let err = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        Ok(())
    }
}<commit_msg>* Fixed misprint<commit_after>use sovrin::api::ErrorCode;
use sovrin::api::wallet::{
    sovrin_register_wallet_type,
    sovrin_create_wallet,
    sovrin_open_wallet,
    sovrin_wallet_set_seq_no_for_value,
    sovrin_delete_wallet,
    sovrin_close_wallet
};

use utils::callback::CallbackUtils;
use utils::inmem_wallet::InmemWallet;
use utils::timeout::TimeoutUtils;
use utils::sequence::SequenceUtils;

use std::collections::HashSet;
use std::ffi::CString;
use std::ptr::null;
use std::sync::mpsc::channel;
use std::sync::Mutex;

pub struct WalletUtils {}

impl WalletUtils {
    pub fn register_wallet_type(xtype: &str) -> Result<(), ErrorCode> {
        lazy_static! {
            static ref REGISERED_WALLETS: Mutex<HashSet<String>> = Default::default();
        }

        let mut wallets = REGISERED_WALLETS.lock().unwrap();

        if wallets.contains(xtype) {
            // as registering of plugged wallet with
            return Ok(())
        }

        let (sender, receiver) = channel();

        let cb = Box::new(move |err| {
            sender.send(err).unwrap();
        });

        let (command_handle, cb) = CallbackUtils::closure_to_register_wallet_type_cb(cb);

        let xxtype = CString::new(xtype).unwrap();

        let err = sovrin_register_wallet_type(
            command_handle,
            xxtype.as_ptr(),
            Some(InmemWallet::create),
            Some(InmemWallet::open),
            Some(InmemWallet::set),
            Some(InmemWallet::get),
            Some(InmemWallet::get_not_expied),
            Some(InmemWallet::list),
            Some(InmemWallet::close),
            Some(InmemWallet::delete),
            Some(InmemWallet::free),
            cb
        );

        if err != ErrorCode::Success {
            return Err(err);
        }

        let err = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        wallets.insert(xtype.to_string());
        Ok(())
    }

    pub fn create_wallet(pool_name: &str, wallet_name: &str, xtype: Option<&str>, config: Option<&str>) -> Result<(), ErrorCode> {
        let (sender, receiver) = channel();

        let cb = Box::new(move |err| {
            sender.send(err).unwrap();
        });

        let (command_handle, cb) = CallbackUtils::closure_to_create_wallet_cb(cb);

        let pool_name = CString::new(pool_name).unwrap();
        let wallet_name = CString::new(wallet_name).unwrap();
        let xtype_str = xtype.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("").unwrap());
        let config_str = config.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("").unwrap());

        let err =
            sovrin_create_wallet(command_handle,
                                 pool_name.as_ptr(),
                                 wallet_name.as_ptr(),
                                 if xtype.is_some() { xtype_str.as_ptr() } else { null() },
                                 if config.is_some() { config_str.as_ptr() } else { null() },
                                 null(),
                                 cb);

        if err != ErrorCode::Success {
            return Err(err);
        }

        let err = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        Ok(())
    }

    pub fn open_wallet(wallet_name: &str, config: Option<&str>) -> Result<i32, ErrorCode> {
        let (sender, receiver) = channel();

        let cb = Box::new(move |err, handle| {
            sender.send((err, handle)).unwrap();
        });

        let (command_handle, cb) = CallbackUtils::closure_to_open_wallet_cb(cb);

        let wallet_name = CString::new(wallet_name).unwrap();
        let config_str = config.map(|s| CString::new(s).unwrap()).unwrap_or(CString::new("").unwrap());

        let err =
            sovrin_open_wallet(command_handle,
                               wallet_name.as_ptr(),
                               if config.is_some() { config_str.as_ptr() } else { null() },
                               null(),
                               cb);

        if err != ErrorCode::Success {
            return Err(err);
        }

        let (err, wallet_handle) = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        Ok(wallet_handle)
    }

    pub fn create_and_open_wallet(pool_name: &str, xtype: Option<&str>) -> Result<i32, ErrorCode> {
        let (sender, receiver) = channel();
        let (open_sender, open_receiver) = channel();

        let cb = Box::new(move |err| {
            sender.send(err).unwrap();
        });
        let open_cb = Box::new(move |err, handle| {
            open_sender.send((err, handle)).unwrap();
        });

        let (command_handle, cb) = CallbackUtils::closure_to_create_wallet_cb(cb);
        let (open_command_handle, open_cb) = CallbackUtils::closure_to_open_wallet_cb(open_cb);

        let pool_name = CString::new(pool_name).unwrap();
        let wallet_name = CString::new(format!("default-wallet-name-{}", SequenceUtils::get_next_id())).unwrap();
        let xtype = match xtype {
            Some(xtype) => CString::new(xtype).unwrap(),
            None => CString::new("default").unwrap()
        };

        let err =
            sovrin_create_wallet(command_handle,
                                 pool_name.as_ptr(),
                                 wallet_name.as_ptr(),
                                 xtype.as_ptr(),
                                 null(),
                                 null(),
                                 cb);

        if err != ErrorCode::Success {
            return Err(err);
        }

        let err = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        let err =
            sovrin_open_wallet(open_command_handle,
                               wallet_name.as_ptr(),
                               null(),
                               null(),
                               open_cb);

        if err != ErrorCode::Success {
            return Err(err);
        }

        let (err, wallet_handle) = open_receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        Ok(wallet_handle)
    }

    pub fn wallet_set_seq_no_for_value(wallet_handle: i32, value: &str, seq_no: i32) -> Result<(), ErrorCode> {
        let (sender, receiver) = channel();

        let cb = Box::new(move |err| {
            sender.send(err).unwrap();
        });

        let (command_handle, cb) = CallbackUtils::closure_to_wallet_set_seq_no_for_value_cb(cb);

        let value = CString::new(value).unwrap();

        let err =
            sovrin_wallet_set_seq_no_for_value(command_handle,
                                               wallet_handle,
                                               value.as_ptr(),
                                               seq_no,
                                               cb);

        if err != ErrorCode::Success {
            return Err(err);
        }

        let err = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        Ok(())
    }

    pub fn delete_wallet(wallet_name: &str) -> Result<(), ErrorCode> {
        let (sender, receiver) = channel();

        let cb = Box::new(move |err| {
            sender.send(err).unwrap();
        });

        let (command_handle, cb) = CallbackUtils::closure_to_delete_wallet_cb(cb);

        let wallet_name = CString::new(wallet_name).unwrap();

        let err =
            sovrin_delete_wallet(command_handle,
                                 wallet_name.as_ptr(),
                                 null(),
                                 cb);

        if err != ErrorCode::Success {
            return Err(err);
        }

        let err = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        Ok(())
    }

    pub fn close_wallet(wallet_handle: i32) -> Result<(), ErrorCode> {
        let (sender, receiver) = channel();

        let cb = Box::new(move |err| {
            sender.send(err).unwrap();
        });

        let (command_handle, cb) = CallbackUtils::closure_to_delete_wallet_cb(cb);

        let err =
            sovrin_close_wallet(command_handle,
                                wallet_handle,
                                cb);

        if err != ErrorCode::Success {
            return Err(err);
        }

        let err = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

        if err != ErrorCode::Success {
            return Err(err);
        }

        Ok(())
    }
}<|endoftext|>


<commit_before>use std::sync::{Arc, RwLock};
use std::option::Option;

use uuid::Uuid;

type OptInt32 = Option<i32>;
type OptInt64 = Option<i64>;
type OptString = Option<String>;

pub enum CellType {
    Int32 (OptInt32),
    Int64 (OptInt64),
    Text  (OptString)
}

trait Metainf {
    fn name(&self) -> String;
}

impl Metainf for CellType {
    fn name(&self) -> String {
        return match *self {
            CellType::Int32(_) => "INT32".to_string(),
            CellType::Int64(_) => "INT64".to_string(),
            CellType::Text(_) => "TEXT".to_string()
        }
    }
}

pub struct CellFormat {
    pub name: String,
    pub type_: CellType
}

pub struct RecFormat {
    pub cols: Vec<CellFormat>
}

trait Metaformat<T> {
    fn construct(format_: CellFormat) -> T;
}

//impl Metaformat<Cell> for Cell {
//    fn construct(format_: CellFormat) -> Cell {
//        return match format_.type_ {
//            CellType::Int32(_) => Cell { value: CellType::Int32(None) },
//            CellType::Int64(_) => Cell { value: CellType::Int64(None) },
//            CellType::Text(_) => Cell { value: CellType::Text(None) }
//        }
//    }
//}

trait Container<T> {
    fn size(&self) -> usize;
    fn push(&mut self, item: T);
    //fn remove
}

pub struct Rec {
    pub guid: Uuid,
    pub cells: Vec<CellType>,
    pub format: Arc<RwLock<RecFormat>>
}

pub fn construct_rec(format: Arc<RwLock<RecFormat>>) -> Rec {
    let cells = format.read().unwrap().cols.iter().map(|x| x.type_.clone()).collect::<Vec<CellType>>();
    return Rec{guid: Uuid::new_v4(),
        cells: cells,
        format: format}
}

//impl Container<Cell> for Rec {

//    fn size(&self) -> usize {
//        return self.cells.len();
//    }

//    fn push(&mut self, item: Cell) {
//        self.cells.push(item);
//    }
//}

pub struct Table {
    pub name: String,
    pub rows: Vec<Rec>,
    pub format: Arc<RwLock<RecFormat>>
}

impl Container<Rec> for Table {
    fn size(&self) -> usize {
        return self.rows.len();
    }

    fn push(&mut self, item: Rec) {
        self.rows.push(item);
    }
}
<commit_msg>Try to implement clone<commit_after>use std::sync::{Arc, RwLock};
use std::option::Option;
use std::clone::Clone;

use uuid::Uuid;

type OptInt32 = Option<i32>;
type OptInt64 = Option<i64>;
type OptString = Option<String>;

//#[derive(Copy)]
pub enum CellType {
    Int32 (OptInt32),
    Int64 (OptInt64),
    Text  (OptString)
}

impl Clone for CellType {
    fn clone(&self) -> CellType {
        *self;
    }
}

trait Metainf {
    fn name(&self) -> String;
}

impl Metainf for CellType {
    fn name(&self) -> String {
        return match *self {
            CellType::Int32(_) => "INT32".to_string(),
            CellType::Int64(_) => "INT64".to_string(),
            CellType::Text(_) => "TEXT".to_string()
        }
    }
}

pub struct CellFormat {
    pub name: String,
    pub type_: CellType
}

pub struct RecFormat {
    pub cols: Vec<CellFormat>
}

trait Metaformat<T> {
    fn construct(format_: CellFormat) -> T;
}

//impl Metaformat<Cell> for Cell {
//    fn construct(format_: CellFormat) -> Cell {
//        return match format_.type_ {
//            CellType::Int32(_) => Cell { value: CellType::Int32(None) },
//            CellType::Int64(_) => Cell { value: CellType::Int64(None) },
//            CellType::Text(_) => Cell { value: CellType::Text(None) }
//        }
//    }
//}

trait Container<T> {
    fn size(&self) -> usize;
    fn push(&mut self, item: T);
    //fn remove
}

pub struct Rec {
    pub guid: Uuid,
    pub cells: Vec<CellType>,
    pub format: Arc<RwLock<RecFormat>>
}

pub fn construct_rec(format: Arc<RwLock<RecFormat>>) -> Rec {
    let cells = format.read().unwrap().cols.iter().map(|x| x.type_.clone()).collect::<Vec<CellType>>();
    return Rec{guid: Uuid::new_v4(),
        cells: cells,
        format: format}
}

//impl Container<Cell> for Rec {

//    fn size(&self) -> usize {
//        return self.cells.len();
//    }

//    fn push(&mut self, item: Cell) {
//        self.cells.push(item);
//    }
//}

pub struct Table {
    pub name: String,
    pub rows: Vec<Rec>,
    pub format: Arc<RwLock<RecFormat>>
}

impl Container<Rec> for Table {
    fn size(&self) -> usize {
        return self.rows.len();
    }

    fn push(&mut self, item: Rec) {
        self.rows.push(item);
    }
}
<|endoftext|>