<commit_before>#![allow(dead_code)]
/// The XML structure for a cobatura report is roughly as follows:
///
/// <coverage lines-valid="5" lines-covered="0" line-rate="0.0" branches-valid="0"
/// branches-covered="0" branch-rate="0.0" version="1.9" timestamp="...">
///   <sources>
///     <source>PATH</source>
///     ...
///   </sources>
///
///   <packages>
///     <package name=".."  line-rate="0.0" branch-rate="0.0" complexity="0.0">
///       <classes>
///         <class name="Main" filename="main.rs" line-rate="0.0" branch-rate="0.0" complexity="0.0">
///           <methods>
///             <method name="main" signature="()" line-rate="0.0" branch-rate="0.0">
///               <lines>
///                 <line number="1" hits="5" branch="false"/>
///                 <line number="3" hits="2" branch="true">
///                   <conditions>
///                     <condition number="0" type="jump" coverage="50%"/>
///                     ...
///                   </conditions>
///                 </line>
///               </lines>
///             </method>
///             ...
///           </methods>
///
///           <lines>
///             <line number="10" hits="4" branch="false"/>
///           </lines>
///         </class>
///         ...
///       </classes>
///     </package>
///     ...
///   </packages>
/// </coverage>

use std::error;
use std::fmt;
use std::fs::File;
use std::io::{Cursor, Write};
use std::time::{SystemTime, UNIX_EPOCH};
use std::path::{Path, PathBuf};

use quick_xml::{Writer, events::{BytesDecl, BytesEnd, BytesStart, Event}};

use chrono::offset::Utc;

use crate::config::{Config};
use crate::traces::{CoverageStat, Trace, TraceMap};

pub fn report(traces: &TraceMap, config: &Config) -> Result<(), Error> {
    let result = Report::render(config, traces)?;
    result.export(config)
}

#[derive(Debug)]
pub enum Error {
    Unknown,
    ExportError(quick_xml::Error),
}

impl error::Error for Error {

    #[inline]
    fn description(&self) -> &str {
        match self {
            Error::ExportError(_) => "Error exporting xml file",
            Error::Unknown => "Unknown Error",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for Error {

    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::ExportError(ref e) => write!(f, "Export Error {}", e),
            Error::Unknown => write!(f, "Unknown Error"),
        }
    }
}

#[derive(Debug)]
pub struct Report {
    timestamp: i64,
    lines_covered: usize,
    lines_valid: usize,
    line_rate: f64,
    branches_covered:usize,
    branches_valid: usize,
    branch_rate: f64,
    sources: Vec<PathBuf>,
    packages: Vec<Package>,
}

impl Report {

    pub fn render(config: &Config, traces: &TraceMap) -> Result<Self, Error> {
        let timestamp   = Utc::now().timestamp();
        let sources     = render_sources(config);
        let packages    = render_packages(config, traces);
        let mut line_rate   = 0.0;
        let mut branch_rate = 0.0;

        if packages.len() > 0 {
            line_rate   = packages.iter()
                .map(|x| x.line_rate).sum::<f64>() / packages.len() as f64;
            branch_rate = packages.iter()
                .map(|x| x.branch_rate).sum::<f64>() / packages.len() as f64;
        }

        Ok(Report {
            timestamp:      timestamp,
            lines_covered: traces.total_covered(),
            lines_valid: traces.total_coverable(),
            line_rate:      line_rate,
            branches_covered: 0,
            branches_valid: 0,
            branch_rate:    branch_rate,
            sources:        sources,
            packages:       packages,
        })
    }

    pub fn export(&self, _config: &Config) -> Result<(), Error> {
        let mut file = File::create("cobertura.xml")
            .map_err(|e| Error::ExportError(quick_xml::Error::Io(e)))?;

        let mut writer = Writer::new(Cursor::new(vec![]));
        writer.write_event(Event::Decl(BytesDecl::new(b"1.0", None, None)))
            .map_err(|e| Error::ExportError(e))?;

        let cov_tag = b"coverage";
        let mut cov = BytesStart::borrowed(cov_tag, cov_tag.len());
        cov.push_attribute(("lines-covered", self.lines_covered.to_string().as_ref()));
        cov.push_attribute(("lines-valid", self.lines_valid.to_string().as_ref()));
        cov.push_attribute(("line-rate", self.line_rate.to_string().as_ref()));
        cov.push_attribute(("branches-covered", self.branches_covered.to_string().as_ref()));
        cov.push_attribute(("branches-valid", self.branches_valid.to_string().as_ref()));
        cov.push_attribute(("branch-rate", self.branch_rate.to_string().as_ref()));
        cov.push_attribute(("complexity", "0"));
        cov.push_attribute(("version", "1.9"));

        let secs = match SystemTime::now().duration_since(UNIX_EPOCH) {
            Ok(s) => s.as_secs().to_string(),
            Err(_) => String::from("0"),
        };
        cov.push_attribute(("timestamp", secs.as_ref()));

        writer.write_event(Event::Start(cov))
            .map_err(|e| Error::ExportError(e))?;

        self.export_header(&mut writer)
            .map_err(|e| Error::ExportError(e))?;

        self.export_packages(&mut writer)
            .map_err(|e| Error::ExportError(e))?;

        writer.write_event(Event::End(BytesEnd::borrowed(cov_tag)))
            .map_err(|e| Error::ExportError(e))?;

        let result = writer.into_inner().into_inner();
        file.write_all(&result)
            .map_err(|e| Error::ExportError(quick_xml::Error::Io(e)))
    }

    fn export_header<T: Write>(&self, writer: &mut Writer<T>) -> Result<(), quick_xml::Error> {
        let sources_tag = b"sources";
        let source_tag = b"source";
        writer.write_event(Event::Start(BytesStart::borrowed(sources_tag, sources_tag.len())))?;
        for source in self.sources.iter() {
            if let Some(ref path) = source.to_str() {
                writer.write_event(Event::Start(BytesStart::borrowed(source_tag, source_tag.len())))?;
                writer.write(path.as_bytes())?;
                writer.write_event(Event::End(BytesEnd::borrowed(source_tag)))?;
            }
        }
        writer.write_event(Event::End(BytesEnd::borrowed(sources_tag)))
            .map(|_| ())
    }

    fn export_packages<T: Write>(&self, writer: &mut Writer<T>) -> Result<(), quick_xml::Error> {
        let packages_tag = b"packages";
        let pack_tag = b"package";

        writer.write_event(Event::Start(BytesStart::borrowed(packages_tag, packages_tag.len())))?;
        // Export the package
        for package in &self.packages {
            let mut pack = BytesStart::borrowed(pack_tag, pack_tag.len());
            pack.push_attribute(("line-rate", package.line_rate.to_string().as_ref()));
            pack.push_attribute(("branch-rate", package.branch_rate.to_string().as_ref()));
            pack.push_attribute(("complexity", package.complexity.to_string().as_ref()));

            writer.write_event(Event::Start(pack))?;
            self.export_classes(&package.classes, writer)?;
            writer.write_event(Event::End(BytesEnd::borrowed(pack_tag)))?;
        }

        writer.write_event(Event::End(BytesEnd::borrowed(packages_tag)))
            .map(|_| ())
    }

    fn export_classes<T: Write>(&self, classes: &[Class], writer: &mut Writer<T>) -> Result<(), quick_xml::Error> {
        let classes_tag = b"classes";
        let class_tag = b"class";
        let methods_tag = b"methods";

        writer.write_event(Event::Start(BytesStart::borrowed(classes_tag, classes_tag.len())))?;
        for class in classes {
            let c = BytesStart::borrowed(class_tag, class_tag.len());

            writer.write_event(Event::Start(c))?;
            writer.write_event(Event::Empty(BytesStart::borrowed(methods_tag, methods_tag.len())))?;
            self.export_lines(&class.lines, writer)?;
            writer.write_event(Event::End(BytesEnd::borrowed(class_tag)))?;
        }
        writer.write_event(Event::End(BytesEnd::borrowed(classes_tag)))
            .map(|_| ())
    }

    fn export_lines<T: Write>(&self, lines: &[Line], writer: &mut Writer<T>) -> Result<(), quick_xml::Error> {
        let lines_tag = b"lines";
        let line_tag = b"line";

        writer.write_event(Event::Start(BytesStart::borrowed(lines_tag, lines_tag.len())))?;
        for line in lines {
            let mut l = BytesStart::borrowed(line_tag, line_tag.len());
            match line {
                Line::Plain{ref number, ref hits} => {
                    l.push_attribute(("number", number.to_string().as_ref()));
                    l.push_attribute(("hits", hits.to_string().as_ref()));
                },
                Line::Branch{..} => {},
            }
            writer.write_event(Event::Empty(l))?;
        }
        writer.write_event(Event::End(BytesEnd::borrowed(lines_tag)))
            .map(|_| ())
    }
}

fn render_sources(config: &Config) -> Vec<PathBuf> {
    let render_source = |&x| Path::to_path_buf(x);

    config.manifest.parent().iter().map(render_source).collect()
}

#[derive(Debug)]
struct Package {
    name:           String,
    line_rate:      f64,
    branch_rate:    f64,
    complexity:     f64,
    classes:        Vec<Class>,
}

fn render_packages(config: &Config, traces: &TraceMap) -> Vec<Package> {
    let mut dirs: Vec<&Path> = traces.files().into_iter()
        .filter_map(|x| x.parent())
        .collect();

    dirs.dedup();

    dirs.into_iter()
        .map(|x| render_package(config, traces, x))
        .collect()
}

fn render_package(config: &Config, traces: &TraceMap, pkg: &Path) -> Package {
    let root = config.manifest.parent().unwrap_or(&config.manifest);
    let name = pkg.strip_prefix(root)
        .map(|x| Path::to_str(x))
        .unwrap_or_default()
        .unwrap_or_default();

    let line_cover = traces.covered_in_path(pkg) as f64;
    let line_rate = line_cover / (traces.coverable_in_path(pkg) as f64);

    Package {
        name:           name.to_string(),
        line_rate:      line_rate,
        branch_rate:    0.0,
        complexity:     0.0,
        classes:        render_classes(config, traces, pkg)
    }
}

#[derive(Debug)]
struct Class {
    name:           String,
    file_name:      String,
    line_rate:      f64,
    branch_rate:    f64,
    complexity:     f64,
    lines:          Vec<Line>,
    methods:        Vec<Method>,
}

fn render_classes(config: &Config, traces: &TraceMap, pkg: &Path) -> Vec<Class> {
    traces.files().iter()
        .filter(|x| x.parent() == Some(pkg))
        .map(|x| render_class(config, traces, x))
        .collect()
}

// TODO: Cobertura distinguishes between lines outside methods, and methods
// (which also contain lines). As there is currently no way to get traces from
// a particular function only, all traces are put into lines, and the vector
// of methods is empty.
//
// Until this is fixed, the render_method function will panic if called, as it
// cannot be properly implemented.
//
fn render_class(config: &Config, traces: &TraceMap, file: &Path) -> Class {
    let root = config.manifest.parent().unwrap_or(&config.manifest);
    let name = file.file_stem()
        .map(|x| x.to_str().unwrap())
        .unwrap_or_default()
        .to_string();

    let file_name = file.strip_prefix(root)
        .unwrap_or(file)
        .to_str()
        .unwrap()
        .to_string();

    let covered = traces.covered_in_path(file) as f64;
    let line_rate = covered / traces.coverable_in_path(file) as f64;
    let lines = traces.get_child_traces(file).iter()
        .map(|x| render_line(x))
        .collect();

    Class {
        name:           name,
        file_name:      file_name,
        line_rate:      line_rate,
        branch_rate:    0.0,
        complexity:     0.0,
        lines:          lines,
        methods:        vec![]
    }
}

#[derive(Debug)]
struct Method {
    name:           String,
    signature:      String,
    line_rate:      f64,
    branch_rate:    f64,
    lines:          Vec<Line>,
}

fn render_methods() -> Vec<Method> {
    unimplemented!()
}

fn render_method() -> Method {
    unimplemented!()
}

#[derive(Debug)]
enum Line {
    Plain {
        number:     usize,
        hits:       usize,
    },

    Branch {
        number:     usize,
        hits:       usize,
        conditions: Vec<Condition>,
    }
}

fn render_line(trace: &Trace) -> Line {
    match &trace.stats {
        CoverageStat::Line(hits) => Line::Plain {
            number: trace.line as usize,
            hits:   *hits as usize
        },

        // TODO: Branches in cobertura are given a fresh number as a label,
        // which would require having some form of context when rendering.
        //
        _ => panic!("Not currently supported")
    }
}

#[derive(Debug)]
struct Condition {
    number:         usize,
    cond_type:      ConditionType,
    coverage:       f64,
}

// Condition types
#[derive(Debug)]
enum ConditionType {
    Jump,
}

<commit_msg>Added line rate and branch rate for classes<commit_after>#![allow(dead_code)]
/// The XML structure for a cobatura report is roughly as follows:
///
/// <coverage lines-valid="5" lines-covered="0" line-rate="0.0" branches-valid="0"
/// branches-covered="0" branch-rate="0.0" version="1.9" timestamp="...">
///   <sources>
///     <source>PATH</source>
///     ...
///   </sources>
///
///   <packages>
///     <package name=".."  line-rate="0.0" branch-rate="0.0" complexity="0.0">
///       <classes>
///         <class name="Main" filename="main.rs" line-rate="0.0" branch-rate="0.0" complexity="0.0">
///           <methods>
///             <method name="main" signature="()" line-rate="0.0" branch-rate="0.0">
///               <lines>
///                 <line number="1" hits="5" branch="false"/>
///                 <line number="3" hits="2" branch="true">
///                   <conditions>
///                     <condition number="0" type="jump" coverage="50%"/>
///                     ...
///                   </conditions>
///                 </line>
///               </lines>
///             </method>
///             ...
///           </methods>
///
///           <lines>
///             <line number="10" hits="4" branch="false"/>
///           </lines>
///         </class>
///         ...
///       </classes>
///     </package>
///     ...
///   </packages>
/// </coverage>

use std::error;
use std::fmt;
use std::fs::File;
use std::io::{Cursor, Write};
use std::time::{SystemTime, UNIX_EPOCH};
use std::path::{Path, PathBuf};

use quick_xml::{Writer, events::{BytesDecl, BytesEnd, BytesStart, Event}};

use chrono::offset::Utc;

use crate::config::{Config};
use crate::traces::{CoverageStat, Trace, TraceMap};

pub fn report(traces: &TraceMap, config: &Config) -> Result<(), Error> {
    let result = Report::render(config, traces)?;
    result.export(config)
}

#[derive(Debug)]
pub enum Error {
    Unknown,
    ExportError(quick_xml::Error),
}

impl error::Error for Error {

    #[inline]
    fn description(&self) -> &str {
        match self {
            Error::ExportError(_) => "Error exporting xml file",
            Error::Unknown => "Unknown Error",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for Error {

    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::ExportError(ref e) => write!(f, "Export Error {}", e),
            Error::Unknown => write!(f, "Unknown Error"),
        }
    }
}

#[derive(Debug)]
pub struct Report {
    timestamp: i64,
    lines_covered: usize,
    lines_valid: usize,
    line_rate: f64,
    branches_covered:usize,
    branches_valid: usize,
    branch_rate: f64,
    sources: Vec<PathBuf>,
    packages: Vec<Package>,
}

impl Report {

    pub fn render(config: &Config, traces: &TraceMap) -> Result<Self, Error> {
        let timestamp   = Utc::now().timestamp();
        let sources     = render_sources(config);
        let packages    = render_packages(config, traces);
        let mut line_rate   = 0.0;
        let mut branch_rate = 0.0;

        if packages.len() > 0 {
            line_rate   = packages.iter()
                .map(|x| x.line_rate).sum::<f64>() / packages.len() as f64;
            branch_rate = packages.iter()
                .map(|x| x.branch_rate).sum::<f64>() / packages.len() as f64;
        }

        Ok(Report {
            timestamp:      timestamp,
            lines_covered: traces.total_covered(),
            lines_valid: traces.total_coverable(),
            line_rate:      line_rate,
            branches_covered: 0,
            branches_valid: 0,
            branch_rate:    branch_rate,
            sources:        sources,
            packages:       packages,
        })
    }

    pub fn export(&self, _config: &Config) -> Result<(), Error> {
        let mut file = File::create("cobertura.xml")
            .map_err(|e| Error::ExportError(quick_xml::Error::Io(e)))?;

        let mut writer = Writer::new(Cursor::new(vec![]));
        writer.write_event(Event::Decl(BytesDecl::new(b"1.0", None, None)))
            .map_err(|e| Error::ExportError(e))?;

        let cov_tag = b"coverage";
        let mut cov = BytesStart::borrowed(cov_tag, cov_tag.len());
        cov.push_attribute(("lines-covered", self.lines_covered.to_string().as_ref()));
        cov.push_attribute(("lines-valid", self.lines_valid.to_string().as_ref()));
        cov.push_attribute(("line-rate", self.line_rate.to_string().as_ref()));
        cov.push_attribute(("branches-covered", self.branches_covered.to_string().as_ref()));
        cov.push_attribute(("branches-valid", self.branches_valid.to_string().as_ref()));
        cov.push_attribute(("branch-rate", self.branch_rate.to_string().as_ref()));
        cov.push_attribute(("complexity", "0"));
        cov.push_attribute(("version", "1.9"));

        let secs = match SystemTime::now().duration_since(UNIX_EPOCH) {
            Ok(s) => s.as_secs().to_string(),
            Err(_) => String::from("0"),
        };
        cov.push_attribute(("timestamp", secs.as_ref()));

        writer.write_event(Event::Start(cov))
            .map_err(|e| Error::ExportError(e))?;

        self.export_header(&mut writer)
            .map_err(|e| Error::ExportError(e))?;

        self.export_packages(&mut writer)
            .map_err(|e| Error::ExportError(e))?;

        writer.write_event(Event::End(BytesEnd::borrowed(cov_tag)))
            .map_err(|e| Error::ExportError(e))?;

        let result = writer.into_inner().into_inner();
        file.write_all(&result)
            .map_err(|e| Error::ExportError(quick_xml::Error::Io(e)))
    }

    fn export_header<T: Write>(&self, writer: &mut Writer<T>) -> Result<(), quick_xml::Error> {
        let sources_tag = b"sources";
        let source_tag = b"source";
        writer.write_event(Event::Start(BytesStart::borrowed(sources_tag, sources_tag.len())))?;
        for source in self.sources.iter() {
            if let Some(ref path) = source.to_str() {
                writer.write_event(Event::Start(BytesStart::borrowed(source_tag, source_tag.len())))?;
                writer.write(path.as_bytes())?;
                writer.write_event(Event::End(BytesEnd::borrowed(source_tag)))?;
            }
        }
        writer.write_event(Event::End(BytesEnd::borrowed(sources_tag)))
            .map(|_| ())
    }

    fn export_packages<T: Write>(&self, writer: &mut Writer<T>) -> Result<(), quick_xml::Error> {
        let packages_tag = b"packages";
        let pack_tag = b"package";

        writer.write_event(Event::Start(BytesStart::borrowed(packages_tag, packages_tag.len())))?;
        // Export the package
        for package in &self.packages {
            let mut pack = BytesStart::borrowed(pack_tag, pack_tag.len());
            pack.push_attribute(("line-rate", package.line_rate.to_string().as_ref()));
            pack.push_attribute(("branch-rate", package.branch_rate.to_string().as_ref()));
            pack.push_attribute(("complexity", package.complexity.to_string().as_ref()));

            writer.write_event(Event::Start(pack))?;
            self.export_classes(&package.classes, writer)?;
            writer.write_event(Event::End(BytesEnd::borrowed(pack_tag)))?;
        }

        writer.write_event(Event::End(BytesEnd::borrowed(packages_tag)))
            .map(|_| ())
    }

    fn export_classes<T: Write>(&self, classes: &[Class], writer: &mut Writer<T>) -> Result<(), quick_xml::Error> {
        let classes_tag = b"classes";
        let class_tag = b"class";
        let methods_tag = b"methods";

        writer.write_event(Event::Start(BytesStart::borrowed(classes_tag, classes_tag.len())))?;
        for class in classes {
            let mut c = BytesStart::borrowed(class_tag, class_tag.len());
            c.push_attribute(("name", class.name.as_ref()));
            c.push_attribute(("filename", class.file_name.as_ref()));
            c.push_attribute(("line-rate", class.line_rate.to_string().as_ref()));
            c.push_attribute(("branch-rate", class.branch_rate.to_string().as_ref()));
            c.push_attribute(("complexity", class.complexity.to_string().as_ref()));

            writer.write_event(Event::Start(c))?;
            writer.write_event(Event::Empty(BytesStart::borrowed(methods_tag, methods_tag.len())))?;
            self.export_lines(&class.lines, writer)?;
            writer.write_event(Event::End(BytesEnd::borrowed(class_tag)))?;
        }
        writer.write_event(Event::End(BytesEnd::borrowed(classes_tag)))
            .map(|_| ())
    }

    fn export_lines<T: Write>(&self, lines: &[Line], writer: &mut Writer<T>) -> Result<(), quick_xml::Error> {
        let lines_tag = b"lines";
        let line_tag = b"line";

        writer.write_event(Event::Start(BytesStart::borrowed(lines_tag, lines_tag.len())))?;
        for line in lines {
            let mut l = BytesStart::borrowed(line_tag, line_tag.len());
            match line {
                Line::Plain{ref number, ref hits} => {
                    l.push_attribute(("number", number.to_string().as_ref()));
                    l.push_attribute(("hits", hits.to_string().as_ref()));
                },
                Line::Branch{..} => {},
            }
            writer.write_event(Event::Empty(l))?;
        }
        writer.write_event(Event::End(BytesEnd::borrowed(lines_tag)))
            .map(|_| ())
    }
}

fn render_sources(config: &Config) -> Vec<PathBuf> {
    let render_source = |&x| Path::to_path_buf(x);

    config.manifest.parent().iter().map(render_source).collect()
}

#[derive(Debug)]
struct Package {
    name:           String,
    line_rate:      f64,
    branch_rate:    f64,
    complexity:     f64,
    classes:        Vec<Class>,
}

fn render_packages(config: &Config, traces: &TraceMap) -> Vec<Package> {
    let mut dirs: Vec<&Path> = traces.files().into_iter()
        .filter_map(|x| x.parent())
        .collect();

    dirs.dedup();

    dirs.into_iter()
        .map(|x| render_package(config, traces, x))
        .collect()
}

fn render_package(config: &Config, traces: &TraceMap, pkg: &Path) -> Package {
    let root = config.manifest.parent().unwrap_or(&config.manifest);
    let name = pkg.strip_prefix(root)
        .map(|x| Path::to_str(x))
        .unwrap_or_default()
        .unwrap_or_default();

    let line_cover = traces.covered_in_path(pkg) as f64;
    let line_rate = line_cover / (traces.coverable_in_path(pkg) as f64);

    Package {
        name:           name.to_string(),
        line_rate:      line_rate,
        branch_rate:    0.0,
        complexity:     0.0,
        classes:        render_classes(config, traces, pkg)
    }
}

#[derive(Debug)]
struct Class {
    name:           String,
    file_name:      String,
    line_rate:      f64,
    branch_rate:    f64,
    complexity:     f64,
    lines:          Vec<Line>,
    methods:        Vec<Method>,
}

fn render_classes(config: &Config, traces: &TraceMap, pkg: &Path) -> Vec<Class> {
    traces.files().iter()
        .filter(|x| x.parent() == Some(pkg))
        .map(|x| render_class(config, traces, x))
        .collect()
}

// TODO: Cobertura distinguishes between lines outside methods, and methods
// (which also contain lines). As there is currently no way to get traces from
// a particular function only, all traces are put into lines, and the vector
// of methods is empty.
//
// Until this is fixed, the render_method function will panic if called, as it
// cannot be properly implemented.
//
fn render_class(config: &Config, traces: &TraceMap, file: &Path) -> Class {
    let root = config.manifest.parent().unwrap_or(&config.manifest);
    let name = file.file_stem()
        .map(|x| x.to_str().unwrap())
        .unwrap_or_default()
        .to_string();

    let file_name = file.strip_prefix(root)
        .unwrap_or(file)
        .to_str()
        .unwrap()
        .to_string();

    let covered = traces.covered_in_path(file) as f64;
    let line_rate = covered / traces.coverable_in_path(file) as f64;
    let lines = traces.get_child_traces(file).iter()
        .map(|x| render_line(x))
        .collect();

    Class {
        name:           name,
        file_name:      file_name,
        line_rate:      line_rate,
        branch_rate:    0.0,
        complexity:     0.0,
        lines:          lines,
        methods:        vec![]
    }
}

#[derive(Debug)]
struct Method {
    name:           String,
    signature:      String,
    line_rate:      f64,
    branch_rate:    f64,
    lines:          Vec<Line>,
}

fn render_methods() -> Vec<Method> {
    unimplemented!()
}

fn render_method() -> Method {
    unimplemented!()
}

#[derive(Debug)]
enum Line {
    Plain {
        number:     usize,
        hits:       usize,
    },

    Branch {
        number:     usize,
        hits:       usize,
        conditions: Vec<Condition>,
    }
}

fn render_line(trace: &Trace) -> Line {
    match &trace.stats {
        CoverageStat::Line(hits) => Line::Plain {
            number: trace.line as usize,
            hits:   *hits as usize
        },

        // TODO: Branches in cobertura are given a fresh number as a label,
        // which would require having some form of context when rendering.
        //
        _ => panic!("Not currently supported")
    }
}

#[derive(Debug)]
struct Condition {
    number:         usize,
    cond_type:      ConditionType,
    coverage:       f64,
}

// Condition types
#[derive(Debug)]
enum ConditionType {
    Jump,
}

<|endoftext|>


<commit_before>use std::fs::File;

use rand;
use regex::Regex;

use bot::{Bot, Node, RoomEvent};
use services::utils::reservoir_sample;

pub struct TryFile {
    safe_re: Regex,
}

impl TryFile {
    pub fn new() -> Self {
        Self {
            safe_re: Regex::new(r"[a-zA-Z]").unwrap(),
        }
    }
}

impl<'a> Node<'a> for TryFile {
    fn handle(&mut self, bot: &Bot, event: RoomEvent) {
        let body = event.raw_event.content["body"].as_str().unwrap();

        if self.safe_re.is_match(body) {
            let rng = rand::thread_rng();

            let fname = format!("var/{}.txt", body);
            match File::open(fname) {
                Ok(d) => {
                    let line = reservoir_sample(d, rng);
                    bot.reply(&event, &line);
                },
                Err(e) => {
                    println!("Tried to open: \"{}\" failed: {:?}", body, e);
                }
            };
        }
    }
}
<commit_msg>Make tryfile quieter<commit_after>use std::fs::File;

use rand;
use regex::Regex;

use bot::{Bot, Node, RoomEvent};
use services::utils::reservoir_sample;

pub struct TryFile {
    safe_re: Regex,
}

impl TryFile {
    pub fn new() -> Self {
        Self {
            safe_re: Regex::new(r"[a-zA-Z]").unwrap(),
        }
    }
}

impl<'a> Node<'a> for TryFile {
    fn handle(&mut self, bot: &Bot, event: RoomEvent) {
        let body = event.raw_event.content["body"].as_str().unwrap();

        if self.safe_re.is_match(body) {
            let rng = rand::thread_rng();

            let fname = format!("var/{}.txt", body);
            match File::open(fname) {
                Ok(d) => {
                    let line = reservoir_sample(d, rng);
                    bot.reply(&event, &line);
                },
                Err(e) => (),
                //{ println!("Tried to open: \"{}\" failed: {:?}", body, e); }
            };
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::hash_map::HashMap;
use std::mem::size_of;

use dora_parser::lexer::position::Position;

use crate::baseline::fct::{JitBaselineFct, JitDescriptor, JitFct, JitFctId};
use crate::baseline::map::CodeDescriptor;
use crate::cpu::{Mem, FREG_PARAMS, REG_FP, REG_PARAMS, REG_SP, REG_THREAD, REG_TMP1};
use crate::exception::DoraToNativeInfo;
use crate::gc::Address;
use crate::masm::MacroAssembler;
use crate::mem;
use crate::threads::{ThreadLocalData, THREAD};
use crate::ty::{BuiltinType, MachineMode};
use crate::vm::FctId;
use crate::vm::VM;

pub struct NativeThunks {
    map: HashMap<Address, JitFctId>,
}

impl NativeThunks {
    pub fn new() -> NativeThunks {
        NativeThunks {
            map: HashMap::new(),
        }
    }

    pub fn find_fct(&self, ptr: Address) -> Option<JitFctId> {
        self.map.get(&ptr).map(|&jit_fct_id| jit_fct_id)
    }

    pub fn insert_fct(&mut self, ptr: Address, fct: JitFctId) {
        self.map.entry(ptr).or_insert(fct);
    }
}

#[derive(Clone)]
pub enum InternalFctDescriptor {
    NativeThunk(FctId),
    AllocThunk,
    VerifyThunk,
    TrapThunk,
}

pub struct InternalFct<'a> {
    pub ptr: Address,
    pub args: &'a [BuiltinType],
    pub return_type: BuiltinType,
    pub throws: bool,
    pub desc: InternalFctDescriptor,
}

pub fn generate<'a, 'ast: 'a>(vm: &'a VM<'ast>, fct: InternalFct, dbg: bool) -> JitFctId {
    let fct_desc = fct.desc.clone();

    let ngen = NativeGen {
        vm,
        masm: MacroAssembler::new(),
        fct,
        dbg,
    };

    let jit_fct = ngen.generate();
    let jit_start = jit_fct.ptr_start();
    let jit_end = jit_fct.ptr_end();
    let jit_fct_id: JitFctId = vm.jit_fcts.push(JitFct::Base(jit_fct)).into();

    let code_desc = match fct_desc {
        InternalFctDescriptor::NativeThunk(_) => CodeDescriptor::NativeThunk(jit_fct_id),
        InternalFctDescriptor::TrapThunk => CodeDescriptor::TrapThunk,
        InternalFctDescriptor::VerifyThunk => CodeDescriptor::VerifyThunk,
        InternalFctDescriptor::AllocThunk => CodeDescriptor::AllocThunk,
    };

    vm.insert_code_map(jit_start, jit_end, code_desc);

    jit_fct_id
}

struct NativeGen<'a, 'ast: 'a> {
    vm: &'a VM<'ast>,
    masm: MacroAssembler,

    fct: InternalFct<'a>,
    dbg: bool,
}

impl<'a, 'ast> NativeGen<'a, 'ast>
where
    'ast: 'a,
{
    pub fn generate(mut self) -> JitBaselineFct {
        let save_return = self.fct.return_type != BuiltinType::Unit;
        let args = self.fct.args.len();

        let dtn_size = size_of::<DoraToNativeInfo>() as i32;

        let offset_dtn = 0;
        let offset_return = dtn_size;
        let offset_args = offset_return + if save_return { mem::ptr_width() } else { 0 };
        let framesize = mem::align_i32(offset_args + args as i32 * mem::ptr_width(), 16);

        // `start_native_call` assumes that offset_dtn is on top of current stack frame.

        if self.dbg {
            self.masm.debug();
        }

        self.masm.prolog_size(framesize);

        save_params(&mut self.masm, self.fct.args, offset_args);

        self.masm.load_mem(
            MachineMode::Ptr,
            REG_TMP1.into(),
            Mem::Base(REG_THREAD, ThreadLocalData::dtn_offset()),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::last_offset()),
            REG_TMP1.into(),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::fp_offset()),
            REG_FP.into(),
        );

        self.masm.copy_pc(REG_TMP1);

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::pc_offset()),
            REG_TMP1.into(),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_THREAD, ThreadLocalData::dtn_offset()),
            REG_SP.into(),
        );

        restore_params(&mut self.masm, self.fct.args, offset_args);

        self.masm.raw_call(self.fct.ptr.to_ptr());

        self.masm.load_mem(
            MachineMode::Ptr,
            REG_TMP1.into(),
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::last_offset()),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_THREAD, ThreadLocalData::dtn_offset()),
            REG_TMP1.into(),
        );

        self.masm.load_mem(
            MachineMode::Ptr,
            REG_TMP1.into(),
            Mem::Base(REG_THREAD, ThreadLocalData::exception_object_offset()),
        );

        let lbl_exception = self.masm.test_if_not_nil(REG_TMP1);

        self.masm.safepoint(self.vm.polling_page.addr());
        self.masm.epilog();

        self.masm.bind_label(lbl_exception);
        self.masm.throw(REG_TMP1, Position::new(1, 1));
        self.masm.nop();

        let desc = match self.fct.desc {
            InternalFctDescriptor::NativeThunk(fid) => JitDescriptor::NativeThunk(fid),
            InternalFctDescriptor::AllocThunk => JitDescriptor::AllocThunk,
            InternalFctDescriptor::VerifyThunk => JitDescriptor::VerifyThunk,
            InternalFctDescriptor::TrapThunk => JitDescriptor::TrapThunk,
        };

        self.masm.jit(self.vm, framesize, desc, self.fct.throws)
    }
}

fn save_params(masm: &mut MacroAssembler, args: &[BuiltinType], offset_args: i32) {
    let mut reg_idx = 0;
    let mut freg_idx = 0;
    let mut idx = 0;

    for &ty in args {
        let mode = ty.mode();
        let is_float = mode.is_float();
        let offset = offset_args + idx as i32 * 8;

        if is_float && freg_idx < FREG_PARAMS.len() {
            let freg = FREG_PARAMS[freg_idx].into();
            masm.store_mem(mode, Mem::Base(REG_SP, offset), freg);
            freg_idx += 1;
        } else if !is_float && reg_idx < REG_PARAMS.len() {
            let reg = REG_PARAMS[reg_idx].into();
            masm.store_mem(mode, Mem::Base(REG_SP, offset), reg);
            reg_idx += 1;
        } else {
            panic!("parameter saved on stack");
        }

        idx += 1;
    }
}

fn restore_params(masm: &mut MacroAssembler, args: &[BuiltinType], offset_args: i32) {
    let mut reg_idx = 0;
    let mut freg_idx = 0;
    let mut idx = 0;

    for &ty in args {
        let mode = ty.mode();
        let is_float = mode.is_float();
        let offset = offset_args + idx as i32 * 8;

        if is_float && freg_idx < FREG_PARAMS.len() {
            let freg = FREG_PARAMS[freg_idx].into();
            masm.load_mem(mode, freg, Mem::Base(REG_SP, offset));
            freg_idx += 1;
        } else if !is_float && reg_idx < REG_PARAMS.len() {
            let reg = REG_PARAMS[reg_idx].into();
            masm.load_mem(mode, reg, Mem::Base(REG_SP, offset));
            reg_idx += 1;
        } else {
            panic!("parameter saved on stack");
        }

        idx += 1;
    }
}

pub fn start_native_call() {
    THREAD.with(|thread| {
        thread.borrow().handles.push_border();
    });
}

pub fn finish_native_call() {
    THREAD.with(|thread| {
        thread.borrow().handles.pop_border();
    });
}
<commit_msg>Revert "dora_native: remove start/finish_native_call calls"<commit_after>use std::collections::hash_map::HashMap;
use std::mem::size_of;

use dora_parser::lexer::position::Position;

use crate::baseline::fct::{JitBaselineFct, JitDescriptor, JitFct, JitFctId};
use crate::baseline::map::CodeDescriptor;
use crate::cpu::{Mem, FREG_PARAMS, REG_FP, REG_PARAMS, REG_RESULT, REG_SP, REG_THREAD, REG_TMP1};
use crate::exception::DoraToNativeInfo;
use crate::gc::Address;
use crate::masm::MacroAssembler;
use crate::mem;
use crate::threads::{ThreadLocalData, THREAD};
use crate::ty::{BuiltinType, MachineMode};
use crate::vm::FctId;
use crate::vm::VM;

pub struct NativeThunks {
    map: HashMap<Address, JitFctId>,
}

impl NativeThunks {
    pub fn new() -> NativeThunks {
        NativeThunks {
            map: HashMap::new(),
        }
    }

    pub fn find_fct(&self, ptr: Address) -> Option<JitFctId> {
        self.map.get(&ptr).map(|&jit_fct_id| jit_fct_id)
    }

    pub fn insert_fct(&mut self, ptr: Address, fct: JitFctId) {
        self.map.entry(ptr).or_insert(fct);
    }
}

#[derive(Clone)]
pub enum InternalFctDescriptor {
    NativeThunk(FctId),
    AllocThunk,
    VerifyThunk,
    TrapThunk,
}

pub struct InternalFct<'a> {
    pub ptr: Address,
    pub args: &'a [BuiltinType],
    pub return_type: BuiltinType,
    pub throws: bool,
    pub desc: InternalFctDescriptor,
}

pub fn generate<'a, 'ast: 'a>(vm: &'a VM<'ast>, fct: InternalFct, dbg: bool) -> JitFctId {
    let fct_desc = fct.desc.clone();

    let ngen = NativeGen {
        vm,
        masm: MacroAssembler::new(),
        fct,
        dbg,
    };

    let jit_fct = ngen.generate();
    let jit_start = jit_fct.ptr_start();
    let jit_end = jit_fct.ptr_end();
    let jit_fct_id: JitFctId = vm.jit_fcts.push(JitFct::Base(jit_fct)).into();

    let code_desc = match fct_desc {
        InternalFctDescriptor::NativeThunk(_) => CodeDescriptor::NativeThunk(jit_fct_id),
        InternalFctDescriptor::TrapThunk => CodeDescriptor::TrapThunk,
        InternalFctDescriptor::VerifyThunk => CodeDescriptor::VerifyThunk,
        InternalFctDescriptor::AllocThunk => CodeDescriptor::AllocThunk,
    };

    vm.insert_code_map(jit_start, jit_end, code_desc);

    jit_fct_id
}

struct NativeGen<'a, 'ast: 'a> {
    vm: &'a VM<'ast>,
    masm: MacroAssembler,

    fct: InternalFct<'a>,
    dbg: bool,
}

impl<'a, 'ast> NativeGen<'a, 'ast>
where
    'ast: 'a,
{
    pub fn generate(mut self) -> JitBaselineFct {
        let save_return = self.fct.return_type != BuiltinType::Unit;
        let args = self.fct.args.len();

        let dtn_size = size_of::<DoraToNativeInfo>() as i32;

        let offset_dtn = 0;
        let offset_return = dtn_size;
        let offset_args = offset_return + if save_return { mem::ptr_width() } else { 0 };
        let framesize = mem::align_i32(offset_args + args as i32 * mem::ptr_width(), 16);

        // `start_native_call` assumes that offset_dtn is on top of current stack frame.

        if self.dbg {
            self.masm.debug();
        }

        self.masm.prolog_size(framesize);

        save_params(&mut self.masm, self.fct.args, offset_args);

        self.masm.load_mem(
            MachineMode::Ptr,
            REG_TMP1.into(),
            Mem::Base(REG_THREAD, ThreadLocalData::dtn_offset()),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::last_offset()),
            REG_TMP1.into(),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::fp_offset()),
            REG_FP.into(),
        );

        self.masm.copy_pc(REG_TMP1);

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::pc_offset()),
            REG_TMP1.into(),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_THREAD, ThreadLocalData::dtn_offset()),
            REG_SP.into(),
        );

        self.masm.raw_call(start_native_call as *const u8);

        restore_params(&mut self.masm, self.fct.args, offset_args);

        self.masm.raw_call(self.fct.ptr.to_ptr());

        if save_return {
            self.masm.store_mem(
                MachineMode::Ptr,
                Mem::Base(REG_SP, offset_return),
                REG_RESULT.into(),
            );
        }

        self.masm.load_mem(
            MachineMode::Ptr,
            REG_TMP1.into(),
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::last_offset()),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_THREAD, ThreadLocalData::dtn_offset()),
            REG_TMP1.into(),
        );

        self.masm.raw_call(finish_native_call as *const u8);

        self.masm.load_mem(
            MachineMode::Ptr,
            REG_RESULT.into(),
            Mem::Base(REG_THREAD, ThreadLocalData::exception_object_offset()),
        );

        let lbl_exception = self.masm.test_if_not_nil(REG_RESULT);

        if save_return {
            self.masm.load_mem(
                MachineMode::Ptr,
                REG_RESULT.into(),
                Mem::Base(REG_SP, offset_return),
            );
        }

        self.masm.safepoint(self.vm.polling_page.addr());
        self.masm.epilog();

        self.masm.bind_label(lbl_exception);
        self.masm.throw(REG_RESULT, Position::new(1, 1));
        self.masm.nop();

        let desc = match self.fct.desc {
            InternalFctDescriptor::NativeThunk(fid) => JitDescriptor::NativeThunk(fid),
            InternalFctDescriptor::AllocThunk => JitDescriptor::AllocThunk,
            InternalFctDescriptor::VerifyThunk => JitDescriptor::VerifyThunk,
            InternalFctDescriptor::TrapThunk => JitDescriptor::TrapThunk,
        };

        self.masm.jit(self.vm, framesize, desc, self.fct.throws)
    }
}

fn save_params(masm: &mut MacroAssembler, args: &[BuiltinType], offset_args: i32) {
    let mut reg_idx = 0;
    let mut freg_idx = 0;
    let mut idx = 0;

    for &ty in args {
        let mode = ty.mode();
        let is_float = mode.is_float();
        let offset = offset_args + idx as i32 * 8;

        if is_float && freg_idx < FREG_PARAMS.len() {
            let freg = FREG_PARAMS[freg_idx].into();
            masm.store_mem(mode, Mem::Base(REG_SP, offset), freg);
            freg_idx += 1;
        } else if !is_float && reg_idx < REG_PARAMS.len() {
            let reg = REG_PARAMS[reg_idx].into();
            masm.store_mem(mode, Mem::Base(REG_SP, offset), reg);
            reg_idx += 1;
        } else {
            panic!("parameter saved on stack");
        }

        idx += 1;
    }
}

fn restore_params(masm: &mut MacroAssembler, args: &[BuiltinType], offset_args: i32) {
    let mut reg_idx = 0;
    let mut freg_idx = 0;
    let mut idx = 0;

    for &ty in args {
        let mode = ty.mode();
        let is_float = mode.is_float();
        let offset = offset_args + idx as i32 * 8;

        if is_float && freg_idx < FREG_PARAMS.len() {
            let freg = FREG_PARAMS[freg_idx].into();
            masm.load_mem(mode, freg, Mem::Base(REG_SP, offset));
            freg_idx += 1;
        } else if !is_float && reg_idx < REG_PARAMS.len() {
            let reg = REG_PARAMS[reg_idx].into();
            masm.load_mem(mode, reg, Mem::Base(REG_SP, offset));
            reg_idx += 1;
        } else {
            panic!("parameter saved on stack");
        }

        idx += 1;
    }
}

pub fn start_native_call() {
    THREAD.with(|thread| {
        thread.borrow().handles.push_border();
    });
}

pub fn finish_native_call() {
    THREAD.with(|thread| {
        thread.borrow().handles.pop_border();
    });
}
<|endoftext|>


<commit_before>use std::ptr;

struct TssContext { handle: u32 }
struct TssTpm<'context> { context: &'context TssContext, handle: u32 }

type TssHContext = u32;
type TssHTPM = u32;
type TssResult = u32;
type TssUnicode = u16;

const TSS_SUCCESS: TssResult = 0;

#[link(name = "tspi")]
extern {
    fn Tspi_Context_Create(phContext: *mut TssHContext) -> TssResult;
    fn Tspi_Context_Connect(phContext: TssHContext, wszDestination: *const TssUnicode) -> TssResult;
    fn Tspi_Context_GetTpmObject(phContext: TssHContext, phTPM: *mut TssHTPM) -> TssResult;
    fn Tspi_Context_FreeMemory(phContext: TssHContext, rgbMemory: *mut u8) -> TssResult;
    fn Tspi_Context_Close(phContext: TssHContext) -> TssResult;
    fn Tspi_TPM_PcrRead(hTPM: TssHTPM, ulPcrIndex: u32, pulPcrValueLength: *mut u32, prgbPcrValue: *mut *mut u8) -> TssResult;
}

impl TssContext {
    fn new() -> Result<TssContext, TssResult> {
        unsafe {
            let mut handle = 0;
            let result = Tspi_Context_Create(&mut handle);
            if result != TSS_SUCCESS {
                Err(result)
            } else {
                Ok(TssContext { handle: handle })
            }
        }
    }

    // TODO: support destination
    fn connect(&self) -> Result<(), TssResult> {
        unsafe {
            let result = Tspi_Context_Connect(self.handle, ptr::null());
            if result != TSS_SUCCESS {
                Err(result)
            } else {
                Ok(())
            }
        }
    }

    fn get_tpm_object(&self) -> Result<TssTpm, TssResult> {
        unsafe {
            let mut handle = 0;
            let result = Tspi_Context_GetTpmObject(self.handle, &mut handle);
            if result != TSS_SUCCESS {
                Err(result)
            } else {
                Ok(TssTpm { context: self, handle: handle })
            }
        }
    }
}

impl Drop for TssContext {
    fn drop(&mut self) {
        unsafe {
            Tspi_Context_Close(self.handle);
        }
    }
}

impl<'context> TssTpm<'context> {
    fn pcr_read(&self, pcr_index: u32) -> Result<Vec<u8>, TssResult> {
        unsafe {
            let mut ulPcrValueLength = -1;
            let mut pRgbPcrValue = 0 as *mut u8;
            let result = Tspi_TPM_PcrRead(self.handle, pcr_index, &mut ulPcrValueLength, &mut pRgbPcrValue);
            if result != TSS_SUCCESS {
                Err(result)
            } else {
                let mut vec = Vec::new();
                for i in 0..ulPcrValueLength {
                    vec.push(*pRgbPcrValue.offset(i as isize));
                }
                Tspi_Context_FreeMemory(self.context.handle, pRgbPcrValue);
                Ok(vec)
            }
        }
    }
}

fn main() {
    // TODO: Any cleaner way to write this?
    let contextresult = TssContext::new();
    if let Ok(context) = contextresult {
        if let Ok(_) = context.connect() {
            if let Ok(tpm) = context.get_tpm_object() {
                println!("I'M IN UR TPM READING UR PCRZ (From Rust!)");
                println!("TPM handle: {:?}", tpm.handle);
                for i in 0..24 {
                    if let Ok(vec) = tpm.pcr_read(i) {
                        print!("PCR {:02}", i);
                        for j in 0..19 {
                            print!(" {:02X}", vec[j]);
                        }
                        print!("\n");
                    }
                }
            } else {
                println!("Failed to get TPM handle :(")
            }
        } else {
            println!("Failed to connect :(");
        }
    } else {
        println!("Failed :(");
    }

    /*
    match blah {
        Ok(context) => println!("Context created! {:?}", context.handle),
        Err(e) => println!("Context failed with err {:?}", e),
    }
    println!("Hello world!");
    */
}
<commit_msg>Call FreeMemory on NULL in the postlude too<commit_after>use std::ptr;

struct TssContext { handle: u32 }
struct TssTpm<'context> { context: &'context TssContext, handle: u32 }

type TssHContext = u32;
type TssHTPM = u32;
type TssResult = u32;
type TssUnicode = u16;

const TSS_SUCCESS: TssResult = 0;

#[link(name = "tspi")]
extern {
    fn Tspi_Context_Create(phContext: *mut TssHContext) -> TssResult;
    fn Tspi_Context_Connect(phContext: TssHContext, wszDestination: *const TssUnicode) -> TssResult;
    fn Tspi_Context_GetTpmObject(phContext: TssHContext, phTPM: *mut TssHTPM) -> TssResult;
    fn Tspi_Context_FreeMemory(phContext: TssHContext, rgbMemory: *mut u8) -> TssResult;
    fn Tspi_Context_Close(phContext: TssHContext) -> TssResult;
    fn Tspi_TPM_PcrRead(hTPM: TssHTPM, ulPcrIndex: u32, pulPcrValueLength: *mut u32, prgbPcrValue: *mut *mut u8) -> TssResult;
}

impl TssContext {
    fn new() -> Result<TssContext, TssResult> {
        unsafe {
            let mut handle = 0;
            let result = Tspi_Context_Create(&mut handle);
            if result != TSS_SUCCESS {
                Err(result)
            } else {
                Ok(TssContext { handle: handle })
            }
        }
    }

    // TODO: support destination
    fn connect(&self) -> Result<(), TssResult> {
        unsafe {
            let result = Tspi_Context_Connect(self.handle, ptr::null());
            if result != TSS_SUCCESS {
                Err(result)
            } else {
                Ok(())
            }
        }
    }

    fn get_tpm_object(&self) -> Result<TssTpm, TssResult> {
        unsafe {
            let mut handle = 0;
            let result = Tspi_Context_GetTpmObject(self.handle, &mut handle);
            if result != TSS_SUCCESS {
                Err(result)
            } else {
                Ok(TssTpm { context: self, handle: handle })
            }
        }
    }
}

impl Drop for TssContext {
    fn drop(&mut self) {
        unsafe {
            Tspi_Context_FreeMemory(self.handle, 0 as *mut u8);
            Tspi_Context_Close(self.handle);
        }
    }
}

impl<'context> TssTpm<'context> {
    fn pcr_read(&self, pcr_index: u32) -> Result<Vec<u8>, TssResult> {
        unsafe {
            let mut ulPcrValueLength = -1;
            let mut pRgbPcrValue = 0 as *mut u8;
            let result = Tspi_TPM_PcrRead(self.handle, pcr_index, &mut ulPcrValueLength, &mut pRgbPcrValue);
            if result != TSS_SUCCESS {
                Err(result)
            } else {
                let mut vec = Vec::new();
                for i in 0..ulPcrValueLength {
                    vec.push(*pRgbPcrValue.offset(i as isize));
                }
                Tspi_Context_FreeMemory(self.context.handle, pRgbPcrValue);
                Ok(vec)
            }
        }
    }
}

fn main() {
    // TODO: Any cleaner way to write this?
    let contextresult = TssContext::new();
    if let Ok(context) = contextresult {
        if let Ok(_) = context.connect() {
            if let Ok(tpm) = context.get_tpm_object() {
                println!("I'M IN UR TPM READING UR PCRZ (From Rust!)");
                println!("TPM handle: {:?}", tpm.handle);
                for i in 0..24 {
                    if let Ok(vec) = tpm.pcr_read(i) {
                        print!("PCR {:02}", i);
                        for j in 0..19 {
                            print!(" {:02x}", vec[j]);
                        }
                        print!("\n");
                    }
                }
            } else {
                println!("Failed to get TPM handle :(")
            }
        } else {
            println!("Failed to connect :(");
        }
    } else {
        println!("Failed :(");
    }

    /*
    match blah {
        Ok(context) => println!("Context created! {:?}", context.handle),
        Err(e) => println!("Context failed with err {:?}", e),
    }
    println!("Hello world!");
    */
}
<|endoftext|>


<commit_before>extern crate sorting;

use std::fmt::Debug;

/// Verify order of input vector as sorted by indices.
///
/// # Details
///
/// This function takes as arguments a vector of data and a vector representing the indices of the
/// first vector making it sorted.
///
/// The elements of the sorted vector are compared to the next ones to make sure they are less
/// or equal.
///
/// # Panics
///
/// The sorting of the data vector is enforced using `assert!()`.
///
/// # Examples
///
/// ```
/// let data: Vec<i32> = vec![4, 2, 3, 1];
/// let sorted_indices: Vec<usize> = vec![3, 1, 2, 0];
/// verify_sorting(&data, &sorted_indices);
/// ```
///
fn verify_sorting<T: Debug + PartialOrd>(array: &Vec<T>, sorted_indices: &Vec<usize>) {
    let n = array.len();
    assert_eq!(n , sorted_indices.len());

    if !array.is_empty() {
        for i in 0..n-1 {
            println!("array[sorted_indices[i={:?}]]={:?}   array[sorted_indices[i+1={:?}]]={:?}",
                i, array[sorted_indices[i]], i+1, array[sorted_indices[i+1]]);
            assert!(array[sorted_indices[i]] <= array[sorted_indices[i+1]]);
        }
    }
}

/// Validate against empty vector.
#[test]
fn simple_insertion_empty() {
    let to_sort: Vec<i32> = vec![];

    let sorted_indices = sorting::simplesorts::insertion::sort(&to_sort);

    verify_sorting(&to_sort, &sorted_indices);

    assert_eq!(sorted_indices, vec![]);
}

/// Validate a vector of double precision values.
#[test]
fn simple_insertion_multiple_sizes_f64() {
    let to_sort: Vec<f64> = vec![6.0,   5.0,  3.0,  1.0,  2.4, 4.0, 10.0, 7.0,
                                 3.42, 32.2, 44.2, 56.3, 67.9, 3.2, 44.2, 2.0];

    let sorted_indices = sorting::simplesorts::insertion::sort(&to_sort);

    verify_sorting(&to_sort, &sorted_indices);
}
<commit_msg>Manually sort the array; compare indices.<commit_after>extern crate sorting;

use std::fmt::Debug;

/// Verify order of input vector as sorted by indices.
///
/// # Details
///
/// This function takes as arguments a vector of data and a vector representing the indices of the
/// first vector making it sorted.
///
/// The elements of the sorted vector are compared to the next ones to make sure they are less
/// or equal.
///
/// # Panics
///
/// The sorting of the data vector is enforced using `assert!()`.
///
/// # Examples
///
/// ```
/// let data: Vec<i32> = vec![4, 2, 3, 1];
/// let sorted_indices: Vec<usize> = vec![3, 1, 2, 0];
/// verify_sorting(&data, &sorted_indices);
/// ```
///
fn verify_sorting<T: Debug + PartialOrd>(array: &Vec<T>, sorted_indices: &Vec<usize>) {
    let n = array.len();
    assert_eq!(n , sorted_indices.len());

    if !array.is_empty() {
        for i in 0..n-1 {
            println!("array[sorted_indices[i={:?}]]={:?}   array[sorted_indices[i+1={:?}]]={:?}",
                i, array[sorted_indices[i]], i+1, array[sorted_indices[i+1]]);
            assert!(array[sorted_indices[i]] <= array[sorted_indices[i+1]]);
        }
    }
}

/// Validate against empty vector.
#[test]
fn simple_insertion_empty() {
    let to_sort: Vec<i32> = vec![];

    let sorted_indices = sorting::simplesorts::insertion::sort(&to_sort);

    verify_sorting(&to_sort, &sorted_indices);

    assert_eq!(sorted_indices, vec![]);
}

/// Validate a vector of double precision values.
#[test]
fn simple_insertion_multiple_sizes_f64() {
    let to_sort: Vec<f64> = vec![6.0,   5.0,  3.0,  1.0,  2.4, 4.0, 10.0, 7.0,
                                 3.42, 32.2, 44.2, 56.3, 67.9, 3.2, 44.2, 2.0];

    let sorted_indices = sorting::simplesorts::insertion::sort(&to_sort);

    verify_sorting(&to_sort, &sorted_indices);

    assert_eq!(sorted_indices, vec![3, 15, 4, 2, 13, 8, 5, 1, 0, 7, 6, 9, 10, 14, 11, 12]);
}
<|endoftext|>


<commit_before>mod particles;
use self::particles::{Particle, ParticleVec, ParticleSlice, ParticleSliceMut};

#[test]
fn const_ref() {
    let particle = Particle::new(String::from("Cl"), 0.0);

    let reference = particle.as_ref();
    let ptr = reference.as_ptr();

    unsafe {
        assert_eq!(ptr.as_ref().unwrap().name, "Cl");
        assert_eq!(*ptr.as_ref().unwrap().mass, 0.0);
    }
}

#[test]
fn mut_ref() {
    let mut particle = Particle::new(String::from("Cl"), 0.0);
    let mut reference = particle.as_mut();

    let ptr = reference.as_mut_ptr();

    unsafe {
        *ptr.as_mut().unwrap().name = String::from("Fe");
        *ptr.as_mut().unwrap().mass = 42.0;
    }

    let ptr = reference.as_ptr();

    unsafe {
        assert_eq!(ptr.as_ref().unwrap().name, "Fe");
        assert_eq!(*ptr.as_ref().unwrap().mass, 42.0);
    }
}

#[test]
fn slice() {
    let mut particles = ParticleVec::new();

    particles.push(Particle::new(String::from("Na"), 1.0));
    particles.push(Particle::new(String::from("Zn"), 2.0));
    particles.push(Particle::new(String::from("Fe"), 3.0));

    let slice = particles.as_slice();
    let ptr = slice.as_ptr();

    unsafe {
        assert_eq!(ptr.as_ref().unwrap().name, "Na");
        assert_eq!(*ptr.as_ref().unwrap().mass, 1.0);
    }

    unsafe {
        let slice = ParticleSlice::from_raw_parts(ptr, 2);
        assert_eq!(slice.len(), 2);
        assert_eq!(slice.index(0).name, "Na");
        assert_eq!(slice.index(1).name, "Zn");

        assert_eq!(*slice.index(0).mass, 1.0);
        assert_eq!(*slice.index(1).mass, 2.0);
    }
}

#[test]
fn slice_mut() {
    let mut particles = ParticleVec::new();

    particles.push(Particle::new(String::from("Na"), 1.0));
    particles.push(Particle::new(String::from("Zn"), 2.0));
    particles.push(Particle::new(String::from("Fe"), 3.0));

    let mut slice = particles.as_mut_slice();
    let ptr = slice.as_mut_ptr();

    unsafe {
        *ptr.as_mut().unwrap().name = String::from("Fe");
        *ptr.as_mut().unwrap().mass = 42.0;
    }

    assert_eq!(slice.index(0).name, "Fe");
    assert_eq!(*slice.index(0).mass, 42.0);

    unsafe {
        let slice = ParticleSliceMut::from_raw_parts_mut(ptr, 2);

        for mass in slice.mass {
            *mass = -1.0;
        }
    }

    assert_eq!(*slice.index(0).mass, -1.0);
    assert_eq!(*slice.index(1).mass, -1.0);
    assert_eq!(*slice.index(2).mass, 3.0);
}

#[test]
fn vec() {
    let mut particles = ParticleVec::new();

    particles.push(Particle::new(String::from("Na"), 1.0));
    particles.push(Particle::new(String::from("Zn"), 2.0));
    particles.push(Particle::new(String::from("Fe"), 3.0));

    let len = particles.len();
    let capacity = particles.capacity();
    let ptr = particles.as_mut_ptr();

    std::mem::forget(particles);

    unsafe {
        *ptr.as_mut().unwrap().name = String::from("Fe");
        *ptr.as_mut().unwrap().mass = 42.0;
    }

    let particles = unsafe {
        ParticleVec::from_raw_parts(ptr, len, capacity)
    };

    assert_eq!(particles.len(), len);
    assert_eq!(particles.capacity(), capacity);

    assert_eq!(particles.index(0).name, "Fe");
    assert_eq!(*particles.index(0).mass, 42.0);

    assert_eq!(particles.index(1).name, "Zn");
    assert_eq!(*particles.index(1).mass, 2.0);

    assert_eq!(particles.index(2).name, "Fe");
    assert_eq!(*particles.index(2).mass, 3.0);
}
<commit_msg>Revert use of soa slices' index in tests<commit_after>mod particles;
use self::particles::{Particle, ParticleVec, ParticleSlice, ParticleSliceMut};

#[test]
fn const_ref() {
    let particle = Particle::new(String::from("Cl"), 0.0);

    let reference = particle.as_ref();
    let ptr = reference.as_ptr();

    unsafe {
        assert_eq!(ptr.as_ref().unwrap().name, "Cl");
        assert_eq!(*ptr.as_ref().unwrap().mass, 0.0);
    }
}

#[test]
fn mut_ref() {
    let mut particle = Particle::new(String::from("Cl"), 0.0);
    let mut reference = particle.as_mut();

    let ptr = reference.as_mut_ptr();

    unsafe {
        *ptr.as_mut().unwrap().name = String::from("Fe");
        *ptr.as_mut().unwrap().mass = 42.0;
    }

    let ptr = reference.as_ptr();

    unsafe {
        assert_eq!(ptr.as_ref().unwrap().name, "Fe");
        assert_eq!(*ptr.as_ref().unwrap().mass, 42.0);
    }
}

#[test]
fn slice() {
    let mut particles = ParticleVec::new();

    particles.push(Particle::new(String::from("Na"), 1.0));
    particles.push(Particle::new(String::from("Zn"), 2.0));
    particles.push(Particle::new(String::from("Fe"), 3.0));

    let slice = particles.as_slice();
    let ptr = slice.as_ptr();

    unsafe {
        assert_eq!(ptr.as_ref().unwrap().name, "Na");
        assert_eq!(*ptr.as_ref().unwrap().mass, 1.0);
    }

    unsafe {
        let slice = ParticleSlice::from_raw_parts(ptr, 2);
        assert_eq!(slice.len(), 2);
        assert_eq!(slice.name[0], "Na");
        assert_eq!(slice.name[1], "Zn");

        assert_eq!(slice.mass[0], 1.0);
        assert_eq!(slice.mass[1], 2.0);
    }
}

#[test]
fn slice_mut() {
    let mut particles = ParticleVec::new();

    particles.push(Particle::new(String::from("Na"), 1.0));
    particles.push(Particle::new(String::from("Zn"), 2.0));
    particles.push(Particle::new(String::from("Fe"), 3.0));

    let mut slice = particles.as_mut_slice();
    let ptr = slice.as_mut_ptr();

    unsafe {
        *ptr.as_mut().unwrap().name = String::from("Fe");
        *ptr.as_mut().unwrap().mass = 42.0;
    }

    assert_eq!(slice.name[0], "Fe");
    assert_eq!(slice.mass[0], 42.0);

    unsafe {
        let slice = ParticleSliceMut::from_raw_parts_mut(ptr, 2);

        for mass in slice.mass {
            *mass = -1.0;
        }
    }

    assert_eq!(slice.mass[0], -1.0);
    assert_eq!(slice.mass[1], -1.0);
    assert_eq!(slice.mass[2], 3.0);
}

#[test]
fn vec() {
    let mut particles = ParticleVec::new();

    particles.push(Particle::new(String::from("Na"), 1.0));
    particles.push(Particle::new(String::from("Zn"), 2.0));
    particles.push(Particle::new(String::from("Fe"), 3.0));

    let len = particles.len();
    let capacity = particles.capacity();
    let ptr = particles.as_mut_ptr();

    std::mem::forget(particles);

    unsafe {
        *ptr.as_mut().unwrap().name = String::from("Fe");
        *ptr.as_mut().unwrap().mass = 42.0;
    }

    let particles = unsafe {
        ParticleVec::from_raw_parts(ptr, len, capacity)
    };

    assert_eq!(particles.len(), len);
    assert_eq!(particles.capacity(), capacity);

    assert_eq!(particles.name[0], "Fe");
    assert_eq!(particles.mass[0], 42.0);

    assert_eq!(particles.name[1], "Zn");
    assert_eq!(particles.mass[1], 2.0);

    assert_eq!(particles.name[2], "Fe");
    assert_eq!(particles.mass[2], 3.0);
}
<|endoftext|>


<commit_before>use crate::exceptions::IOError;
use std::fs;
use std::path::PathBuf;
use std::process::{Command, ExitStatus};

// `Metric` defines a dbt command that we want to measure on both the
// baseline and dev branches.
#[derive(Debug, Clone)]
struct Metric<'a> {
    name: &'a str,
    prepare: &'a str,
    cmd: &'a str,
}

impl Metric<'_> {
    // Returns the proper filename for the hyperfine output for this metric.
    fn outfile(&self, project: &str, branch: &str) -> String {
        [branch, "_", self.name, "_", project, ".json"].join("")
    }
}

// Calls hyperfine via system command, and returns all the exit codes for each hyperfine run.
pub fn measure<'a>(
    projects_directory: &PathBuf,
    dbt_branch: &str,
) -> Result<Vec<ExitStatus>, IOError> {
    /*
        Strategy of this function body:
        1. Read all directory names in `projects_directory`
        2. Pair `n` projects with `m` metrics for a total of n*m pairs
        3. Run hyperfine on each project-metric pair
    */

    // To add a new metric to the test suite, simply define it in this list:
    // TODO: This could be read from a config file in a future version.
    let metrics: Vec<Metric> = vec![Metric {
        name: "parse",
        prepare: "rm -rf target/",
        cmd: "dbt parse --no-version-check",
    }];

    fs::read_dir(projects_directory)
        .or_else(|e| Err(IOError::ReadErr(projects_directory.to_path_buf(), Some(e))))?
        .map(|entry| {
            let path = entry
                .or_else(|e| Err(IOError::ReadErr(projects_directory.to_path_buf(), Some(e))))?
                .path();

            let project_name: String = path
                .file_name()
                .ok_or_else(|| IOError::MissingFilenameErr(path.clone().to_path_buf()))
                .and_then(|x| {
                    x.to_str()
                        .ok_or_else(|| IOError::FilenameNotUnicodeErr(path.clone().to_path_buf()))
                })?
                .to_owned();

            // each project-metric pair we will run
            let pairs = metrics
                .iter()
                .map(|metric| (path.clone(), project_name.clone(), metric))
                .collect::<Vec<(PathBuf, String, &Metric<'a>)>>();

            Ok(pairs)
        })
        .collect::<Result<Vec<Vec<(PathBuf, String, &Metric<'a>)>>, IOError>>()?
        .concat()
        .iter()
        // run hyperfine on each pairing
        .map(|(path, project_name, metric)| {
            Command::new("hyperfine")
                .current_dir(path)
                // warms filesystem caches by running the command first without counting it.
                // alternatively we could clear them before each run
                .arg("--warmup")
                .arg("1")
                .arg("--prepare")
                .arg(metric.prepare)
                .arg([metric.cmd, " --profiles-dir ", "../../project_config/"].join(""))
                .arg("--export-json")
                .arg(["../../results/", &metric.outfile(project_name, dbt_branch)].join(""))
                // this prevents hyperfine from capturing dbt's output.
                // Noisy, but good for debugging when tests fail.
                .arg("--show-output")
                .status() // use spawn() here instead for more information
                .or_else(|e| Err(IOError::CommandErr(Some(e))))
        })
        .collect()
}
<commit_msg>minimum performance runs to 20<commit_after>use crate::exceptions::IOError;
use std::fs;
use std::path::PathBuf;
use std::process::{Command, ExitStatus};

// `Metric` defines a dbt command that we want to measure on both the
// baseline and dev branches.
#[derive(Debug, Clone)]
struct Metric<'a> {
    name: &'a str,
    prepare: &'a str,
    cmd: &'a str,
}

impl Metric<'_> {
    // Returns the proper filename for the hyperfine output for this metric.
    fn outfile(&self, project: &str, branch: &str) -> String {
        [branch, "_", self.name, "_", project, ".json"].join("")
    }
}

// Calls hyperfine via system command, and returns all the exit codes for each hyperfine run.
pub fn measure<'a>(
    projects_directory: &PathBuf,
    dbt_branch: &str,
) -> Result<Vec<ExitStatus>, IOError> {
    /*
        Strategy of this function body:
        1. Read all directory names in `projects_directory`
        2. Pair `n` projects with `m` metrics for a total of n*m pairs
        3. Run hyperfine on each project-metric pair
    */

    // To add a new metric to the test suite, simply define it in this list:
    // TODO: This could be read from a config file in a future version.
    let metrics: Vec<Metric> = vec![Metric {
        name: "parse",
        prepare: "rm -rf target/",
        cmd: "dbt parse --no-version-check",
    }];

    fs::read_dir(projects_directory)
        .or_else(|e| Err(IOError::ReadErr(projects_directory.to_path_buf(), Some(e))))?
        .map(|entry| {
            let path = entry
                .or_else(|e| Err(IOError::ReadErr(projects_directory.to_path_buf(), Some(e))))?
                .path();

            let project_name: String = path
                .file_name()
                .ok_or_else(|| IOError::MissingFilenameErr(path.clone().to_path_buf()))
                .and_then(|x| {
                    x.to_str()
                        .ok_or_else(|| IOError::FilenameNotUnicodeErr(path.clone().to_path_buf()))
                })?
                .to_owned();

            // each project-metric pair we will run
            let pairs = metrics
                .iter()
                .map(|metric| (path.clone(), project_name.clone(), metric))
                .collect::<Vec<(PathBuf, String, &Metric<'a>)>>();

            Ok(pairs)
        })
        .collect::<Result<Vec<Vec<(PathBuf, String, &Metric<'a>)>>, IOError>>()?
        .concat()
        .iter()
        // run hyperfine on each pairing
        .map(|(path, project_name, metric)| {
            Command::new("hyperfine")
                .current_dir(path)
                // warms filesystem caches by running the command first without counting it.
                // alternatively we could clear them before each run
                .arg("--warmup")
                .arg("1")
                // --min-runs defaults to 10
                .arg("--min-runs")
                .arg("20")
                .arg("--prepare")
                .arg(metric.prepare)
                .arg([metric.cmd, " --profiles-dir ", "../../project_config/"].join(""))
                .arg("--export-json")
                .arg(["../../results/", &metric.outfile(project_name, dbt_branch)].join(""))
                // this prevents hyperfine from capturing dbt's output.
                // Noisy, but good for debugging when tests fail.
                .arg("--show-output")
                .status() // use spawn() here instead for more information
                .or_else(|e| Err(IOError::CommandErr(Some(e))))
        })
        .collect()
}
<|endoftext|>


<commit_before>
#![feature(start)]
#![allow(dead_code)]
#![allow(unreachable_code)]
#![allow(unused_variables)]
#![allow(non_snake_case)]
#![allow(unstable)]

extern crate num;
//extern crate native;
extern crate libc;

extern crate glfw;
extern crate gl;
extern crate nanovg;

use glfw::Context;
use std::cell::Cell; // for glfw error count
use nanovg::Ctx;

/// evaluate the expression, then check for GL error.
macro_rules! glcheck {
    ($e: expr) => (
        {
            $e;
            assert_eq!(unsafe {gl::GetError()}, 0);
        }
    )
}

mod perf;
mod demo;

/*#[start]
fn start(argc: int, argv: *const *const u8) -> int {
    native::start(argc, argv, main)
}*/

/// give GLFW a way to report errors, and count them.
fn error_callback(_: glfw::Error, description: String, error_count: &Cell<usize>) {
    println!("GLFW error {}: {}", error_count.get(), description);
    error_count.set(error_count.get() + 1);
}

fn init_gl() {
    glcheck!(unsafe {gl::FrontFace(gl::CCW)});
    glcheck!(unsafe {gl::Enable(gl::DEPTH_TEST)});
    glcheck!(unsafe {gl::Enable(gl::SCISSOR_TEST)});
    glcheck!(unsafe {gl::DepthFunc(gl::LEQUAL)});
    glcheck!(unsafe {gl::FrontFace(gl::CCW)});
    glcheck!(unsafe {gl::Enable(gl::CULL_FACE)});
    glcheck!(unsafe {gl::CullFace(gl::BACK)});
}

static mut blowup: bool = false;
static mut screenshot: bool = false;
static mut premult: bool = false;

fn main()
{
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    // TODO: Get this working? No idea what's wrong with it, but the example of usage in glfw-rs is out of date
	/*// set up GLFW error callback, with an error-counter
	glfw.set_error_callback(Some(
	    glfw::Callback {
	        f: error_callback,
	        data: Cell::new(0),
	    }
	));*/

	glfw.window_hint(glfw::WindowHint::ContextVersion(3, 2));
 	glfw.window_hint(glfw::WindowHint::OpenglForwardCompat(true));
 	glfw.window_hint(glfw::WindowHint::OpenglProfile(glfw::OpenGlProfileHint::Core));
 	glfw.window_hint(glfw::WindowHint::OpenglDebugContext(true));

    let (mut window, events) = glfw.create_window(1100, 800, "NanoVG GL3 Rust demo", glfw::WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

	// window.set_key_callback(key);
    window.set_key_polling(true);

    window.make_current();

    // use glfw to load GL function pointers
    glcheck!(gl::load_with(|name| window.get_proc_address(name)));
    init_gl();

   	let vg: nanovg::Ctx = nanovg::Ctx::create_gl3(nanovg::ANTIALIAS | nanovg::STENCIL_STROKES);
   	//assert!(!vg.ptr.is_null());

    let data = demo::DemoData::load(&vg, "../../res");

//    return test_linebreaks(vg);

	glfw.set_swap_interval(0);

	glfw.set_time(0.0);
	let mut prevt = glfw.get_time();

	let mut fps = perf::PerfGraph::init(perf::Style::FPS, "Frame Time");

    while !window.should_close()
    {
    	let t: f64 = glfw.get_time();
    	let dt: f64 = t - prevt;
    	prevt = t;
    	fps.update(dt);

        let (mx, my) = window.get_cursor_pos(); // (f64,f64)
        let (winWidth, winHeight) = window.get_size();  // (i32,i32)
        let (fbWidth, fbHeight) = window.get_framebuffer_size();
        // Calculate pixel ration for hi-dpi devices.
        let pxRatio = fbWidth as f32 / winWidth as f32;

        // Update and render
        glcheck!(unsafe {gl::Viewport(0, 0, fbWidth, fbHeight)});
        if unsafe {premult} {
            glcheck!(unsafe {gl::ClearColor(0.0, 0.0, 0.0, 0.0)});
        } else {
            glcheck!(unsafe {gl::ClearColor(0.3, 0.3, 0.32, 1.0)});
        }
        glcheck!(unsafe {gl::Clear(gl::COLOR_BUFFER_BIT|gl::DEPTH_BUFFER_BIT|gl::STENCIL_BUFFER_BIT)});

        glcheck!(unsafe {gl::Enable(gl::BLEND)});
        glcheck!(unsafe {gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA)});
        glcheck!(unsafe {gl::Enable(gl::CULL_FACE)});
        glcheck!(unsafe {gl::Disable(gl::DEPTH_TEST)});

        vg.begin_frame(winWidth, winHeight, pxRatio as f32);

        unsafe { demo::render_demo(&vg, mx as f32,my as f32, winWidth as f32,winHeight as f32, t as f32, blowup, &data); }
        fps.render(&vg, 5.0, 5.0);

        vg.end_frame();

        unsafe {gl::Enable(gl::DEPTH_TEST);}
        unsafe {
	        if screenshot {
	        	screenshot = false;
	        	demo::save_screenshot(fbWidth as u32, fbHeight as u32, premult, "dump.png");
	        }
        }

    	window.swap_buffers();

        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    match event {
        glfw::WindowEvent::Key(glfw::Key::Escape, _, glfw::Action::Press, _) => {
            window.set_should_close(true)
        }
        glfw::WindowEvent::Key(glfw::Key::Space, _, glfw::Action::Press, _) => {
            unsafe {blowup = !blowup};
        }
        glfw::WindowEvent::Key(glfw::Key::S, _, glfw::Action::Press, _) => {
            unsafe {screenshot = true};
        }
        glfw::WindowEvent::Key(glfw::Key::P, _, glfw::Action::Press, _) => {
            unsafe {premult = !premult};
        }
        _ => {}
    }
}

//// think linebreaks api needs some love
//fn test_linebreaks(vg:Ctx) {
//    let x=0.0; let y=0.0;
//    let width = 120.0;
//
//    let text = "This is longer chunk of text.\n  \n  Would have used lorem ipsum but she    was busy jumping over the lazy dog with the fox and all the men who came to the aid of the party.";
//    //let text = "01234 6789 1234 6789 1234 6789 123456789012345678901234567890123456789012345678901234567890123456789";
//
//
//    // The text break API can be used to fill a large buffer of rows,
//    // or to iterate over the text just few lines (or just one) at a time.
//    // The "next" variable of the last returned item tells where to continue.
//    let mut start: uint = 0;    // byte pos in utf8 'text' str
//    let end: uint = text.len(); // exclusive
//    'chunks: loop {
//        let text = text.slice(start, end);
//
//println!("{}", text);
//
//        let rows = vg.text_break_lines(text, width, 3);
//        let nrows = rows.len();
//        if nrows == 0 { break 'chunks; }
//        for i in range(0, nrows) {
//            let row = &rows[i];
//            let line = text.slice(row.start_index(), row.end_index());
//
//println!("i: {}  st: {}, en: {}  \t {} \tnext: {}", i, row.start_index(), row.end_index(), line, row.next_index());
//
//        }
//        // Keep going...
//        start += rows[nrows-1].next_index();
//    }
//}
<commit_msg>Fixed the error callback after figuring out what was missing.<commit_after>
#![feature(start)]
#![allow(dead_code)]
#![allow(unreachable_code)]
#![allow(unused_variables)]
#![allow(non_snake_case)]
#![allow(unstable)]

extern crate num;
extern crate libc;

extern crate glfw;
extern crate gl;
extern crate nanovg;

use glfw::Context;
use std::cell::Cell; // for glfw error count
use nanovg::Ctx;

/// evaluate the expression, then check for GL error.
macro_rules! glcheck {
    ($e: expr) => (
        {
            $e;
            assert_eq!(unsafe {gl::GetError()}, 0);
        }
    )
}

mod perf;
mod demo;

/// give GLFW a way to report errors, and count them.
fn error_callback(_: glfw::Error, description: String, error_count: &Cell<usize>) {
    println!("GLFW error {}: {}", error_count.get(), description);
    error_count.set(error_count.get() + 1);
}

fn init_gl() {
    glcheck!(unsafe {gl::FrontFace(gl::CCW)});
    glcheck!(unsafe {gl::Enable(gl::DEPTH_TEST)});
    glcheck!(unsafe {gl::Enable(gl::SCISSOR_TEST)});
    glcheck!(unsafe {gl::DepthFunc(gl::LEQUAL)});
    glcheck!(unsafe {gl::FrontFace(gl::CCW)});
    glcheck!(unsafe {gl::Enable(gl::CULL_FACE)});
    glcheck!(unsafe {gl::CullFace(gl::BACK)});
}

static mut blowup: bool = false;
static mut screenshot: bool = false;
static mut premult: bool = false;

fn main()
{
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

	// set up GLFW error callback, with an error-counter
	glfw.set_error_callback(Some(
	    glfw::Callback {
	        f: error_callback as fn(glfw::Error, String, &Cell<usize>),
	        data: Cell::new(0),
	    }
	));

	glfw.window_hint(glfw::WindowHint::ContextVersion(3, 2));
 	glfw.window_hint(glfw::WindowHint::OpenglForwardCompat(true));
 	glfw.window_hint(glfw::WindowHint::OpenglProfile(glfw::OpenGlProfileHint::Core));
 	glfw.window_hint(glfw::WindowHint::OpenglDebugContext(true));

    let (mut window, events) = glfw.create_window(1100, 800, "NanoVG GL3 Rust demo", glfw::WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

	// window.set_key_callback(key);
    window.set_key_polling(true);

    window.make_current();

    // use glfw to load GL function pointers
    glcheck!(gl::load_with(|name| window.get_proc_address(name)));
    init_gl();

   	let vg: nanovg::Ctx = nanovg::Ctx::create_gl3(nanovg::ANTIALIAS | nanovg::STENCIL_STROKES);
   	//assert!(!vg.ptr.is_null());

    let data = demo::DemoData::load(&vg, "../../res");

//    return test_linebreaks(vg);

	glfw.set_swap_interval(0);

	glfw.set_time(0.0);
	let mut prevt = glfw.get_time();

	let mut fps = perf::PerfGraph::init(perf::Style::FPS, "Frame Time");

    while !window.should_close()
    {
    	let t: f64 = glfw.get_time();
    	let dt: f64 = t - prevt;
    	prevt = t;
    	fps.update(dt);

        let (mx, my) = window.get_cursor_pos(); // (f64,f64)
        let (winWidth, winHeight) = window.get_size();  // (i32,i32)
        let (fbWidth, fbHeight) = window.get_framebuffer_size();
        // Calculate pixel ration for hi-dpi devices.
        let pxRatio = fbWidth as f32 / winWidth as f32;

        // Update and render
        glcheck!(unsafe {gl::Viewport(0, 0, fbWidth, fbHeight)});
        if unsafe {premult} {
            glcheck!(unsafe {gl::ClearColor(0.0, 0.0, 0.0, 0.0)});
        } else {
            glcheck!(unsafe {gl::ClearColor(0.3, 0.3, 0.32, 1.0)});
        }
        glcheck!(unsafe {gl::Clear(gl::COLOR_BUFFER_BIT|gl::DEPTH_BUFFER_BIT|gl::STENCIL_BUFFER_BIT)});

        glcheck!(unsafe {gl::Enable(gl::BLEND)});
        glcheck!(unsafe {gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA)});
        glcheck!(unsafe {gl::Enable(gl::CULL_FACE)});
        glcheck!(unsafe {gl::Disable(gl::DEPTH_TEST)});

        vg.begin_frame(winWidth, winHeight, pxRatio as f32);

        unsafe { demo::render_demo(&vg, mx as f32,my as f32, winWidth as f32,winHeight as f32, t as f32, blowup, &data); }
        fps.render(&vg, 5.0, 5.0);

        vg.end_frame();

        unsafe {gl::Enable(gl::DEPTH_TEST);}
        unsafe {
	        if screenshot {
	        	screenshot = false;
	        	demo::save_screenshot(fbWidth as u32, fbHeight as u32, premult, "dump.png");
	        }
        }

    	window.swap_buffers();

        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    match event {
        glfw::WindowEvent::Key(glfw::Key::Escape, _, glfw::Action::Press, _) => {
            window.set_should_close(true)
        }
        glfw::WindowEvent::Key(glfw::Key::Space, _, glfw::Action::Press, _) => {
            unsafe {blowup = !blowup};
        }
        glfw::WindowEvent::Key(glfw::Key::S, _, glfw::Action::Press, _) => {
            unsafe {screenshot = true};
        }
        glfw::WindowEvent::Key(glfw::Key::P, _, glfw::Action::Press, _) => {
            unsafe {premult = !premult};
        }
        _ => {}
    }
}

//// think linebreaks api needs some love
//fn test_linebreaks(vg:Ctx) {
//    let x=0.0; let y=0.0;
//    let width = 120.0;
//
//    let text = "This is longer chunk of text.\n  \n  Would have used lorem ipsum but she    was busy jumping over the lazy dog with the fox and all the men who came to the aid of the party.";
//    //let text = "01234 6789 1234 6789 1234 6789 123456789012345678901234567890123456789012345678901234567890123456789";
//
//
//    // The text break API can be used to fill a large buffer of rows,
//    // or to iterate over the text just few lines (or just one) at a time.
//    // The "next" variable of the last returned item tells where to continue.
//    let mut start: uint = 0;    // byte pos in utf8 'text' str
//    let end: uint = text.len(); // exclusive
//    'chunks: loop {
//        let text = text.slice(start, end);
//
//println!("{}", text);
//
//        let rows = vg.text_break_lines(text, width, 3);
//        let nrows = rows.len();
//        if nrows == 0 { break 'chunks; }
//        for i in range(0, nrows) {
//            let row = &rows[i];
//            let line = text.slice(row.start_index(), row.end_index());
//
//println!("i: {}  st: {}, en: {}  \t {} \tnext: {}", i, row.start_index(), row.end_index(), line, row.next_index());
//
//        }
//        // Keep going...
//        start += rows[nrows-1].next_index();
//    }
//}
<|endoftext|>


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

use std::fmt;

#[derive(Debug, Clone)]
pub enum FnctlError {
    /// Operation is prohibited by locks held by other processes.
    EAGAIN,
    /// fd is not an open file descriptor, or the command was F_SETLK or F_SETLKW and the
    /// file descriptor open mode doesn't match with the type of lock requested.
    EBADF,
    /// It was detected that the specified F_SETLKW command would cause a deadlock.
    EDEADLK,
    /// Lock is outside your accessible address space.
    EFAULT,
    /// For F_SETLKW, the command was interrupted by a signal; see signal(7).
    /// For F_GETLK and F_SETLK, the command was interrupted by a signal before the lock
    /// was checked or acquired. Most likely when locking a remote
    /// file (e.g., locking over NFS), but can sometimes happen locally.
    EINTR,
    /// For F_DUPFD, arg is negative or is greater than the maximum allowable value.
    /// For F_SETSIG, arg is not an allowable signal number.
    EINVAL,
    /// For F_DUPFD, the process already has the maximum number of file descriptors open.
    EMFILE,
    /// Too many segment locks open, lock table is full, or a remote locking protocol
    /// failed (e.g., locking over NFS).
    ENOLCK,
    /// Attempted to clear the O_APPEND flag on a file that has the append-only attribute set.
    EPERM
}

#[derive(Debug, Clone)]
pub enum ReadError {
    /// System is out of memory
    ENOMEM,
    /// The file descriptor fd refers to a file other than a socket and has been
    /// marked nonblocking (O_NONBLOCK), and the read would block.
    EAGAIN,
    /// fd is not a valid file descriptor or is not open for reading.
    EBADF,
    /// buf is outside your accessible address space.
    EFAULT,
    /// The call was interrupted by a signal before any data was read; see signal(7).
    EINTR,
    /// fd is attached to an object which is unsuitable for reading; or the file was opened
    /// with the O_DIRECT flag, and either the address specified in buf, the value specified
    /// in count, or the current file offset is not suitably aligned.
    /// OR
    /// fd was created via a call to timerfd_create(2) and the wrong size buffer was given to
    /// read(); see timerfd_create(2) for further information.
    EINVAL,
    /// I/O error. This will happen for example when the process is in a background process
    /// group, tries to read from its controlling terminal, and either it is ignoring or
    /// blocking SIGTTIN or its process group is orphaned. It may also occur when there
    /// is a low-level I/O error while reading from a disk or tape.
    EIO,
    /// fd refers to a directory.
    EISDIR,
    /// End of file has been reached. No more can be read from this socket.
    EOF,
    /// fd is connected to a TCP socket where the other end has been closed, but the write
    /// command has not had enough time to finish writing to the internal buffer
    ECONNRESET
}

#[derive(Debug, Clone)]
pub enum WriteError {
    /// The file descriptor fd refers to a file other than a socket and has been
    /// marked nonblocking (O_NONBLOCK), and the write would block.
    EAGAIN,
    /// The file descriptor fd refers to a socket and has been marked nonblocking (O_NONBLOCK),
    /// and the write would block. POSIX.1-2001 allows either error to be returned for this case,
    /// and does not require these constants to have the same value, so a portable application
    /// should check for both possibilities.
    EWOULDBLOCK,
    /// fd is not a valid file descriptor or is not open for writing.
    EBADF,
    /// fd refers to a datagram socket for which a peer address has not been set using connect(2).
    EDESTADDRREQ,
    /// The user's quota of disk blocks on the file system containing the file referred
    /// to by fd has been exhausted.
    EDQUOT,
    /// buf is outside your accessible address space.
    EFAULT,
    /// An attempt was made to write a file that exceeds the implementation-defined maximum
    /// file size or the process's file size limit, or to write at a position past the
    /// maximum allowed offset.
    EFBIG,
    /// The call was interrupted by a signal before any data was written; see signal(7).
    EINTR,
    /// fd is attached to an object which is unsuitable for writing; or the file was opened
    /// with the O_DIRECT flag, and either the address specified in buf, the value specified
    /// in count, or the current file offset is not suitably aligned.
    EINVAL,
    /// A low-level I/O error occurred while modifying the inode.
    EIO,
    /// The device containing the file referred to by fd has no room for the data.
    ENOSPC,
    /// fd is connected to a pipe or socket whose reading end is closed. When this happens
    /// the writing process will also receive a SIGPIPE signal. (Thus, the write return value
    /// is seen only if the program catches, blocks or ignores this signal.)
    EPIPE,
    /// fd is connected to a TCP socket where the other end has been closed, but the write
    /// command has not had enough time to finish writing to the internal buffer
    ECONNRESET
}

impl fmt::Display for FnctlError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FnctlError::EAGAIN => "EAGAIN".fmt(f),
            FnctlError::EBADF => "EBADF".fmt(f),
            FnctlError::EDEADLK => "EDEADLK".fmt(f),
            FnctlError::EFAULT => "EFAULT".fmt(f),
            FnctlError::EINTR => "EINTR".fmt(f),
            FnctlError::EINVAL => "EINVAL".fmt(f),
            FnctlError::EMFILE => "EMFILE".fmt(f),
            FnctlError::ENOLCK => "ENOLCK".fmt(f),
            FnctlError::EPERM => "EPERM".fmt(f),
        }
    }
}

impl fmt::Display for ReadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ReadError::ENOMEM => "ENOMEM".fmt(f),
            ReadError::EAGAIN => "EAGAIN".fmt(f),
            ReadError::EBADF => "EBADF".fmt(f),
            ReadError::EFAULT => "EFAULT".fmt(f),
            ReadError::EINTR => "EINTR".fmt(f),
            ReadError::EINVAL => "EINVAL".fmt(f),
            ReadError::EIO => "EIO".fmt(f),
            ReadError::EISDIR => "EISDIR".fmt(f),
            ReadError::EOF => "EOF".fmt(f),
            ReadError::ECONNRESET => "ECONNRESET".fmt(f)
        }
    }
}

impl fmt::Display for WriteError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            WriteError::EAGAIN => "EAGAIN".fmt(f),
            WriteError::EWOULDBLOCK => "EWOULDBLOCK".fmt(f),
            WriteError::EBADF => "EBADF".fmt(f),
            WriteError::EDESTADDRREQ => "EDESTADDRREQ".fmt(f),
            WriteError::EDQUOT => "EDQUOT".fmt(f),
            WriteError::EFAULT => "EFAULT".fmt(f),
            WriteError::EFBIG => "EFBIG".fmt(f),
            WriteError::EINTR => "EINTR".fmt(f),
            WriteError::EINVAL => "EINVAL".fmt(f),
            WriteError::EIO => "EIO".fmt(f),
            WriteError::ENOSPC => "ENOSPC".fmt(f),
            WriteError::EPIPE => "EPIPE".fmt(f),
            WriteError::ECONNRESET => "ECONNRESET".fmt(f)
        }
    }
}
<commit_msg>Debug, Clone, Eq, PartialEq added for types<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.

use std::fmt;

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum FnctlError {
    /// Operation is prohibited by locks held by other processes.
    EAGAIN,
    /// fd is not an open file descriptor, or the command was F_SETLK or F_SETLKW and the
    /// file descriptor open mode doesn't match with the type of lock requested.
    EBADF,
    /// It was detected that the specified F_SETLKW command would cause a deadlock.
    EDEADLK,
    /// Lock is outside your accessible address space.
    EFAULT,
    /// For F_SETLKW, the command was interrupted by a signal; see signal(7).
    /// For F_GETLK and F_SETLK, the command was interrupted by a signal before the lock
    /// was checked or acquired. Most likely when locking a remote
    /// file (e.g., locking over NFS), but can sometimes happen locally.
    EINTR,
    /// For F_DUPFD, arg is negative or is greater than the maximum allowable value.
    /// For F_SETSIG, arg is not an allowable signal number.
    EINVAL,
    /// For F_DUPFD, the process already has the maximum number of file descriptors open.
    EMFILE,
    /// Too many segment locks open, lock table is full, or a remote locking protocol
    /// failed (e.g., locking over NFS).
    ENOLCK,
    /// Attempted to clear the O_APPEND flag on a file that has the append-only attribute set.
    EPERM
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ReadError {
    /// System is out of memory
    ENOMEM,
    /// The file descriptor fd refers to a file other than a socket and has been
    /// marked nonblocking (O_NONBLOCK), and the read would block.
    EAGAIN,
    /// fd is not a valid file descriptor or is not open for reading.
    EBADF,
    /// buf is outside your accessible address space.
    EFAULT,
    /// The call was interrupted by a signal before any data was read; see signal(7).
    EINTR,
    /// fd is attached to an object which is unsuitable for reading; or the file was opened
    /// with the O_DIRECT flag, and either the address specified in buf, the value specified
    /// in count, or the current file offset is not suitably aligned.
    /// OR
    /// fd was created via a call to timerfd_create(2) and the wrong size buffer was given to
    /// read(); see timerfd_create(2) for further information.
    EINVAL,
    /// I/O error. This will happen for example when the process is in a background process
    /// group, tries to read from its controlling terminal, and either it is ignoring or
    /// blocking SIGTTIN or its process group is orphaned. It may also occur when there
    /// is a low-level I/O error while reading from a disk or tape.
    EIO,
    /// fd refers to a directory.
    EISDIR,
    /// End of file has been reached. No more can be read from this socket.
    EOF,
    /// fd is connected to a TCP socket where the other end has been closed, but the write
    /// command has not had enough time to finish writing to the internal buffer
    ECONNRESET
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum WriteError {
    /// The file descriptor fd refers to a file other than a socket and has been
    /// marked nonblocking (O_NONBLOCK), and the write would block.
    EAGAIN,
    /// The file descriptor fd refers to a socket and has been marked nonblocking (O_NONBLOCK),
    /// and the write would block. POSIX.1-2001 allows either error to be returned for this case,
    /// and does not require these constants to have the same value, so a portable application
    /// should check for both possibilities.
    EWOULDBLOCK,
    /// fd is not a valid file descriptor or is not open for writing.
    EBADF,
    /// fd refers to a datagram socket for which a peer address has not been set using connect(2).
    EDESTADDRREQ,
    /// The user's quota of disk blocks on the file system containing the file referred
    /// to by fd has been exhausted.
    EDQUOT,
    /// buf is outside your accessible address space.
    EFAULT,
    /// An attempt was made to write a file that exceeds the implementation-defined maximum
    /// file size or the process's file size limit, or to write at a position past the
    /// maximum allowed offset.
    EFBIG,
    /// The call was interrupted by a signal before any data was written; see signal(7).
    EINTR,
    /// fd is attached to an object which is unsuitable for writing; or the file was opened
    /// with the O_DIRECT flag, and either the address specified in buf, the value specified
    /// in count, or the current file offset is not suitably aligned.
    EINVAL,
    /// A low-level I/O error occurred while modifying the inode.
    EIO,
    /// The device containing the file referred to by fd has no room for the data.
    ENOSPC,
    /// fd is connected to a pipe or socket whose reading end is closed. When this happens
    /// the writing process will also receive a SIGPIPE signal. (Thus, the write return value
    /// is seen only if the program catches, blocks or ignores this signal.)
    EPIPE,
    /// fd is connected to a TCP socket where the other end has been closed, but the write
    /// command has not had enough time to finish writing to the internal buffer
    ECONNRESET
}

impl fmt::Display for FnctlError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FnctlError::EAGAIN => "EAGAIN".fmt(f),
            FnctlError::EBADF => "EBADF".fmt(f),
            FnctlError::EDEADLK => "EDEADLK".fmt(f),
            FnctlError::EFAULT => "EFAULT".fmt(f),
            FnctlError::EINTR => "EINTR".fmt(f),
            FnctlError::EINVAL => "EINVAL".fmt(f),
            FnctlError::EMFILE => "EMFILE".fmt(f),
            FnctlError::ENOLCK => "ENOLCK".fmt(f),
            FnctlError::EPERM => "EPERM".fmt(f),
        }
    }
}

impl fmt::Display for ReadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ReadError::ENOMEM => "ENOMEM".fmt(f),
            ReadError::EAGAIN => "EAGAIN".fmt(f),
            ReadError::EBADF => "EBADF".fmt(f),
            ReadError::EFAULT => "EFAULT".fmt(f),
            ReadError::EINTR => "EINTR".fmt(f),
            ReadError::EINVAL => "EINVAL".fmt(f),
            ReadError::EIO => "EIO".fmt(f),
            ReadError::EISDIR => "EISDIR".fmt(f),
            ReadError::EOF => "EOF".fmt(f),
            ReadError::ECONNRESET => "ECONNRESET".fmt(f)
        }
    }
}

impl fmt::Display for WriteError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            WriteError::EAGAIN => "EAGAIN".fmt(f),
            WriteError::EWOULDBLOCK => "EWOULDBLOCK".fmt(f),
            WriteError::EBADF => "EBADF".fmt(f),
            WriteError::EDESTADDRREQ => "EDESTADDRREQ".fmt(f),
            WriteError::EDQUOT => "EDQUOT".fmt(f),
            WriteError::EFAULT => "EFAULT".fmt(f),
            WriteError::EFBIG => "EFBIG".fmt(f),
            WriteError::EINTR => "EINTR".fmt(f),
            WriteError::EINVAL => "EINVAL".fmt(f),
            WriteError::EIO => "EIO".fmt(f),
            WriteError::ENOSPC => "ENOSPC".fmt(f),
            WriteError::EPIPE => "EPIPE".fmt(f),
            WriteError::ECONNRESET => "ECONNRESET".fmt(f)
        }
    }
}
<|endoftext|>