<commit_before>/* vim: set et: */

use types::folder::FolderId;
use types::recording::ProgramId;
use std::fmt;

pub enum EVUrl {
    Login,
    Folder(FolderId),
    Program(ProgramId),
    Move(ProgramId, FolderId)
}
impl fmt::Show for EVUrl {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            EVUrl::Login => write!(fmt, "https//api.elisaviihde.fi/etvrecorder/login.sl"),
            EVUrl::Folder(ref id) => match *id {
                FolderId::Root => write!(fmt, "https://api.elisaviihde.fi/etvrecorder/ready.sl?ajax=true"),
                ref id => write!(fmt, "https://api.elisaviihde.fi/etvrecorder/ready.sl?folderid={}&ppos=0&ajax=true", id),
            },
            EVUrl::Program(ref id) => write!(fmt, "https://api.elisaviihde.fi/etvrecorder/program.sl?programid={}&ppos=0&ajax=true", id),
            EVUrl::Move(ref pid, ref fid) => write!(fmt, "https://api.elisaviihde.fi/etvrecorder/ready.sl?ajax=true&move=true&destination={}&programviewid={}", fid, pid)
        }
    }
}

#[test]
fn show_login_url() {
    let url = EVUrl::Login;
    assert!(url.to_string() == "https//api.elisaviihde.fi/etvrecorder/login.sl");
}

#[test]
fn show_root_folder_url() {
    let url = EVUrl::Folder(FolderId::Root);
    assert!(url.to_string() == "https://api.elisaviihde.fi/etvrecorder/ready.sl?ajax=true");
}

#[test]
fn show_non_root_folder_url() {
    let url = EVUrl::Folder(FolderId::FolderId(123));
    assert!(url.to_string() == "https://api.elisaviihde.fi/etvrecorder/ready.sl?folderid=123&ppos=0&ajax=true");
}

#[test]
fn show_program_url() {
    let url = EVUrl::Program(ProgramId::ProgramId(123));
    assert!(url.to_string() == "https://api.elisaviihde.fi/etvrecorder/program.sl?programid=123&ppos=0&ajax=true");
}
<commit_msg>Move url test<commit_after>/* vim: set et: */

use types::folder::FolderId;
use types::recording::ProgramId;
use std::fmt;

pub enum EVUrl {
    Login,
    Folder(FolderId),
    Program(ProgramId),
    Move(ProgramId, FolderId)
}
impl fmt::Show for EVUrl {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            EVUrl::Login => write!(fmt, "https//api.elisaviihde.fi/etvrecorder/login.sl"),
            EVUrl::Folder(ref id) => match *id {
                FolderId::Root => write!(fmt, "https://api.elisaviihde.fi/etvrecorder/ready.sl?ajax=true"),
                ref id => write!(fmt, "https://api.elisaviihde.fi/etvrecorder/ready.sl?folderid={}&ppos=0&ajax=true", id),
            },
            EVUrl::Program(ref id) => write!(fmt, "https://api.elisaviihde.fi/etvrecorder/program.sl?programid={}&ppos=0&ajax=true", id),
            EVUrl::Move(ref pid, ref fid) => write!(fmt, "https://api.elisaviihde.fi/etvrecorder/ready.sl?ajax=true&move=true&destination={}&programviewid={}", fid, pid)
        }
    }
}

#[test]
fn show_login_url() {
    let url = EVUrl::Login;
    assert!(url.to_string() == "https//api.elisaviihde.fi/etvrecorder/login.sl");
}

#[test]
fn show_root_folder_url() {
    let url = EVUrl::Folder(FolderId::Root);
    assert!(url.to_string() == "https://api.elisaviihde.fi/etvrecorder/ready.sl?ajax=true");
}

#[test]
fn show_non_root_folder_url() {
    let url = EVUrl::Folder(FolderId::FolderId(123));
    assert!(url.to_string() == "https://api.elisaviihde.fi/etvrecorder/ready.sl?folderid=123&ppos=0&ajax=true");
}

#[test]
fn show_program_url() {
    let url = EVUrl::Program(ProgramId::ProgramId(123));
    assert!(url.to_string() == "https://api.elisaviihde.fi/etvrecorder/program.sl?programid=123&ppos=0&ajax=true");
}

#[test]
fn show_move_url() {
    let url = EVUrl::Move(ProgramId::ProgramId(123), FolderId::FolderId(321));
    assert!(url.to_string() == "https://api.elisaviihde.fi/etvrecorder/ready.sl?ajax=true&move=true&destination=321&programviewid=123");
}
<|endoftext|>


<commit_before>pub fn escape_single_quote(text: &str) -> String {
    text.replace("'", "'\\''")
}
<commit_msg>[util] move helper functions to util<commit_after>use unicode_width::UnicodeWidthChar;

pub fn escape_single_quote(text: &str) -> String {
    text.replace("'", "'\\''")
}

/// return an array, arr[i] store the display width till char[i]
pub fn accumulate_text_width(text: &str, tabstop: usize) -> Vec<usize> {
    let mut ret = Vec::new();
    let mut w = 0;
    for ch in text.chars() {
        w += if ch == '\t' {
            tabstop - (w % tabstop)
        } else {
            ch.width().unwrap_or(2)
        };
        ret.push(w);
    }
    ret
}

/// "smartly" calculate the "start" position of the string in order to show the matched contents
/// for example, if the match appear in the end of a long string, we need to show the right part.
/// ```
/// xxxxxxxxxxxxxxxxxxxxxxxxxxMMxxxxxMxxxxx
///               shift ->|               |
/// ```
///
/// return (left_shift, full_print_width)
pub fn reshape_string(
    text: &str,
    container_width: usize,
    match_start: usize,
    match_end: usize,
    tabstop: usize,
) -> (usize, usize) {
    if text.is_empty() {
        return (0, 0);
    }

    let acc_width = accumulate_text_width(text, tabstop);
    let full_width = acc_width[acc_width.len() - 1];
    if full_width <= container_width {
        return (0, full_width);
    }

    // w1, w2, w3 = len_before_matched, len_matched, len_after_matched
    let w1 = if match_start == 0 {
        0
    } else {
        acc_width[match_start - 1]
    };
    let w2 = if match_end >= acc_width.len() {
        full_width - w1
    } else {
        acc_width[match_end] - w1
    };
    let w3 = acc_width[acc_width.len() - 1] - w1 - w2;

    if (w1 > w3 && w2 + w3 <= container_width) || (w3 <= 2) {
        // right-fixed
        //(right_fixed(&acc_width, container_width), full_width)
        (full_width - container_width, full_width)
    } else if w1 <= w3 && w1 + w2 <= container_width {
        // left-fixed
        (0, full_width)
    } else {
        // left-right
        (acc_width[match_end] - container_width + 2, full_width)
    }
}

#[cfg(test)]
mod tests {
    use super::{accumulate_text_width, reshape_string};

    #[test]
    fn test_accumulate_text_width() {
        assert_eq!(accumulate_text_width("abcdefg", 8), vec![1, 2, 3, 4, 5, 6, 7]);
        assert_eq!(accumulate_text_width("ab中de国g", 8), vec![1, 2, 4, 5, 6, 8, 9]);
        assert_eq!(accumulate_text_width("ab\tdefg", 8), vec![1, 2, 8, 9, 10, 11, 12]);
        assert_eq!(accumulate_text_width("ab中\te国g", 8), vec![1, 2, 4, 8, 9, 11, 12]);
    }

    #[test]
    fn test_reshape_string() {
        // no match, left fixed to 0
        assert_eq!(reshape_string("abc", 10, 0, 0, 8), (0, 3));
        assert_eq!(reshape_string("a\tbc", 8, 0, 0, 8), (0, 10));
        assert_eq!(reshape_string("a\tb\tc", 10, 0, 0, 8), (0, 17));
        assert_eq!(reshape_string("a\t中b\tc", 8, 0, 0, 8), (0, 17));
        assert_eq!(reshape_string("a\t中b\tc012345", 8, 0, 0, 8), (0, 23));
    }
}
<|endoftext|>


<commit_before>//! Module containing various utility functions.

/// Default fruit names.
pub static FRUITS: &'static [&'static str] = &["Avocado", "Banana", "Melon", "Orange", "Pear", "Watermelon"];

/// Uppercase the first character of the supplied string.
///
/// Based on http://stackoverflow.com/a/38406885/2851815
///
/// # Examples
///
/// ```
/// # use poke_a_mango::util::uppercase_first;
/// assert_eq!(uppercase_first("abolish"), "Abolish".to_string());
/// ```
pub fn uppercase_first(s: &str) -> String {
    let mut c = s.chars();
    match c.next() {
        None => String::new(),
        Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
    }
}

/// Get the fruit name from the format used in `GameStatus::Playing::fruit`.
///
/// # Examples
///
/// ```
/// # use poke_a_mango::util::fruit_name;
/// assert_eq!(fruit_name(&None), "Mango");
/// ```
pub fn fruit_name(fruit: &Option<usize>) -> &'static str {
    match *fruit {
        Some(i) => FRUITS[i],
        None => "Mango",
    }
}
<commit_msg>Add util::mul_str()<commit_after>//! Module containing various utility functions.

use std::iter;

/// Default fruit names.
pub static FRUITS: &'static [&'static str] = &["Avocado", "Banana", "Melon", "Orange", "Pear", "Watermelon"];

/// Uppercase the first character of the supplied string.
///
/// Based on http://stackoverflow.com/a/38406885/2851815
///
/// # Examples
///
/// ```
/// # use poke_a_mango::util::uppercase_first;
/// assert_eq!(uppercase_first("abolish"), "Abolish".to_string());
/// ```
pub fn uppercase_first(s: &str) -> String {
    let mut c = s.chars();
    match c.next() {
        None => String::new(),
        Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
    }
}

/// Get the fruit name from the format used in `GameStatus::Playing::fruit`.
///
/// # Examples
///
/// ```
/// # use poke_a_mango::util::fruit_name;
/// assert_eq!(fruit_name(&None), "Mango");
/// ```
pub fn fruit_name(fruit: &Option<usize>) -> &'static str {
    match *fruit {
        Some(i) => FRUITS[i],
        None => "Mango",
    }
}

/// Create a string consisting of `n` repetitions of `what`.
///
/// # Examples
///
/// ```
/// # use poke_a_mango::util::mul_str;
/// assert_eq!(mul_str("Го! ", 3), "Го! Го! Го! ".to_string());
/// ```
pub fn mul_str(what: &str, n: usize) -> String {
    iter::repeat(what).take(n).collect()
}
<|endoftext|>


<commit_before>use mime::{Mime, TopLevel, SubLevel};
use image;

// XXX: Move into Piston?
pub trait AsImageFormat {
    fn as_image_format(&self) -> Option<image::ImageFormat>;
}

impl AsImageFormat for Mime {
    fn as_image_format(&self) -> Option<image::ImageFormat> {
        Some(match *self {
            Mime(TopLevel::Image, SubLevel::Png, _) => image::ImageFormat::PNG,
            Mime(TopLevel::Image, SubLevel::Jpeg, _) => image::ImageFormat::JPEG,
            Mime(TopLevel::Image, SubLevel::Gif, _) => image::ImageFormat::GIF,
            Mime(TopLevel::Image, SubLevel::Ext(ref i), _) if i == "x-icon" => image::ImageFormat::ICO,
            _ => return None
        })
    }
}
<commit_msg>Be sloppier on favicon MIME-type<commit_after>use mime::{Mime, TopLevel, SubLevel};
use image;

// XXX: Move into Piston?
pub trait AsImageFormat {
    fn as_image_format(&self) -> Option<image::ImageFormat>;
}

impl AsImageFormat for Mime {
    fn as_image_format(&self) -> Option<image::ImageFormat> {
        Some(match *self {
            Mime(TopLevel::Image, SubLevel::Png, _) => image::ImageFormat::PNG,
            Mime(TopLevel::Image, SubLevel::Jpeg, _) => image::ImageFormat::JPEG,
            Mime(TopLevel::Image, SubLevel::Gif, _) => image::ImageFormat::GIF,
            Mime(_, SubLevel::Ext(ref i), _) if i == "x-icon" => image::ImageFormat::ICO,
            _ => return None
        })
    }
}
<|endoftext|>


<commit_before>use std::process::Command;
use XML;

pub fn panel_xslt() -> String {
    let scss = Command::new("/usr/local/bin/sassc").arg("/Users/jadencarver/dev/superconductor/assets/__pm.scss").output().unwrap();
    let css = String::from_utf8(scss.stdout).unwrap();

    let markup = html! {
        xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" {
            xsl:output method="html" indent="yes" {}

            xsl:template match="/" {
                div#__pm__panel {
                    style type="text/css" (css)
                    style type="text/css" "@import url('//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.10.0/styles/agate.min.css');"
                    form#__pm__commit method="post" name="commit" {
                        ul#__pm__commits {
                            xsl:apply-templates select="/state/log/commit" {}
                        }
                        hr {}
                        dl.properties {
                            xsl:apply-templates select="/state/properties/property" {
                                xsl:with-param name="value" "5"
                            }
                        }
                        textarea id="__pm__commit__message" tabindex="1" name="message" placeholder="Add a Comment" {
                            xsl:value-of select="/state/message" {}
                        }
                        div#__pm__new_commit {
                            input type="submit" tabindex="4" name="save_update" value="Save Update" {}
                            xsl:if test="/state/changes/change" {
                                fieldset#__pm__commit__changes.details {
                                    legend#__pm__commit__changes_legend tabindex="2" role="button" {
                                        "Include Changes"
                                        span#__pm__commit__changes__statistics.token {
                                            xsl:if test="/state/changes/statistics/files != 0" {
                                                span {
                                                    xsl:value-of select="format-number(/state/changes/statistics/files, '#,###.##')" {}
                                                    " file"
                                                    xsl:if test="/state/changes/statistics/files != 1" {
                                                        "s"
                                                    }
                                                }
                                            }
                                            xsl:if test="/state/changes/statistics/insertions != 0" {
                                                span.token--positive {
                                                    "+"
                                                    xsl:value-of select="format-number(/state/changes/statistics/insertions, '#,###.##')" {}
                                                }
                                            }
                                            xsl:if test="/state/changes/statistics/deletions != 0" {
                                                span.token--negative {
                                                    "-"
                                                    xsl:value-of select="format-number(/state/changes/statistics/deletions, '#,###.##')" {}
                                                }
                                            }
                                        }
                                    }
                                    ul {
                                        xsl:apply-templates select="/state/changes/change" {}
                                    }
                                }
                            }
                        }
                    }
                    xsl:choose {
                        xsl:when test="/state/diffs/*" {
                            xsl:apply-templates select="/state/diffs" {}
                        }
                        xsl:otherwise {
                            xsl:apply-templates select="/state/tasks" {}
                        }
                    }
                }
            }
            xsl:template match="/state/properties/property" {
                div.property {
                    xsl:choose {
                        xsl:when test="name = 'Status'" {
                            dt { label for="__pm__commit__properties--status" "Status" }
                            dd.select tabindex="1" {
                                xsl:value-of select="value" {}
                                select id="__pm__commit__properties--status" name="property" data-name="Status" {
                                    xsl:apply-templates "options/option" {}
                                }
                            }
                        }
                        xsl:when test="name = 'Developer'" {
                            dt "Developer"
                            dd.select {
                                input type="text" value="Jaden Carver" {}
                                select name="property" data-name="Developer" {
                                    xsl:apply-templates "options/option" {}
                                }
                            }
                        }
                        xsl:when test="name = 'Description'" {
                            dt "Description"
                            dd {
                                textarea name="property" data-name="Description" {
                                    xsl:value-of select="value" {}
                                }
                            }
                        }
                        xsl:otherwise {
                            dt "Estimate"
                            dd.input {
                                input type="text" name="property" data-name="Estimate" value="{value}" {}
                            }
                        }
                    }
                }
            }
            xsl:template match="/state/properties/property/options/option" {
                xsl:element name="option" {
                    xsl:attribute name="value" {
                        xsl:value-of select="." {}
                    }
                    xsl:if test="./parent::options/parent::property/value = ." {
                        xsl:attribute name="selected" "selected"
                    }
                    xsl:value-of select="." {}
                }
            }
            xsl:template match="/state/diffs" {
                div.diff {
                    pre {
                        code {
                            xsl:copy-of select="*" {}
                        }
                    }
                }
            }
            xsl:template name="diff-lines" {
                xsl:param name="limit" select="1" {}
                xsl:param name="count" select="1" {}
                xsl:if test="$count <= $limit" {
                    li {
                        xsl:value-of select="$count" {}
                    }
                    xsl:call-template name="diff-lines" {
                        xsl:with-param name="limit" select="$limit" {}
                        xsl:with-param name="count" select="$count + 1" {}
                    }
                }
            }
            xsl:template match="task" {
                li {
                    div draggable="true" class="{type}" {
                        strong {
                            xsl:value-of select="name" {}
                        }
                        xsl:value-of select="property" {}
                        "Properties"
                        xsl:value-of select="after/parent::property[name]" {}
                    }
                }
            }
            xsl:template match="/state/tasks" {
                ul.tiles {
                    header "Sprint"
                    xsl:apply-templates select="task" {}
                }
                ul.tiles {
                    header {
                        "In Progress"
                    }
                    xsl:apply-templates select="/state/task" {}
                }
                ul.tiles {
                    header "In Review"
                }
                ul.tiles {
                    header "Blocked"
                }
                ul.tiles {
                    header "Done"
                }
            }
            xsl:template match="/state/log/commit" {
                li {
                    xsl:if test="./preceding-sibling::commit[1]/user/email=user/email and ./preceding-sibling::commit[1]/timestamp - timestamp > -7200" {
                        xsl:attribute name="class" "continuous"
                    }
                    img src="{user/image}" alt="{user/name} <{user/email}>" {}
                    xsl:if test="changes" {
                        button.button--medium.attachments {
                            svg id="i-paperclip" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="20" height="20" fill="none" stroke="currentcolor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" {
                                path d="M10 9 L10 24 C10 28 13 30 16 30 19 30 22 28 22 24 L22 6 C22 3 20 2 18 2 16 2 14 3 14 6 L14 23 C14 24 15 25 16 25 17 25 18 24 18 23 L18 9" {}
                            }
                        }
                    }
                    blockquote {
                        a.user__name href="#" {
                            xsl:value-of select="user/name" {}
                        }
                        xsl:value-of select="message" {}
                    }
                    xsl:if test="task" {
                        dl.tasks {
                            xsl:apply-templates select="task[property]" {}
                        }
                    }
                    div {
                        time datetime="{localtime}" {
                            xsl:value-of select="localtime" {}
                        }
                    }
                }
            }
            xsl:template match="/state/log/commit/task" {
                dt { xsl:value-of select="name" {} }
                dd {
                    ul.properties {
                        xsl:apply-templates select="property" {}
                    }
                }
            }
            xsl:template match="/state/log/commit/task/property" {
                li.token {
                    span.name { xsl:value-of select="name" {} }
                    xsl:if test="before" {
                        span.before.token--neutral { xsl:value-of select="before" {} }
                    }
                    span.after.token--positive { xsl:value-of select="after" {} }
                }
            }
            xsl:template match="/state/changes/change" {
                li tabindex="3" id="{concat('__pm__changes__checkbox--', @id)}" {
                    xsl:element name="input" {
                        xsl:attribute name="name" { "include" }
                        xsl:attribute name="id" {
                            xsl:value-of select="concat('__pm__changes--', @id)" {}
                        }
                        xsl:attribute name="value" {
                            xsl:value-of select="path" {}
                        }
                        xsl:attribute name="tabindex" "-1"
                        xsl:attribute name="type" "checkbox"
                        xsl:if test="included='true'" {
                            xsl:attribute name="checked" {}
                        }
                        xsl:if test="removal='true'" {
                            xsl:attribute name="class" { "delete" }
                        }
                    }
                    label for="__pm__changes--{@id}" {
                        xsl:value-of select="path" {}
                    }
                    button.button--tiny name="diff" value="{path}" { " +10 -10" }
                }
            }
        }
    };
    format!("{}{}", XML, markup.into_string())
}

<commit_msg>--- BLBA-1234:   Alpha: Omega   Description: I am the alpha and the omega<commit_after>use std::process::Command;
use XML;

pub fn panel_xslt() -> String {
    let scss = Command::new("/usr/local/bin/sassc").arg("/Users/jadencarver/dev/superconductor/assets/__pm.scss").output().unwrap();
    let css = String::from_utf8(scss.stdout).unwrap();

    let markup = html! {
        xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" {
            xsl:output method="html" indent="yes" {}

            xsl:template match="/" {
                div#__pm__panel {
                    style type="text/css" (css)
                    style type="text/css" "@import url('//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.10.0/styles/agate.min.css');"
                    form#__pm__commit method="post" name="commit" {
                        ul#__pm__commits {
                            xsl:apply-templates select="/state/log/commit" {}
                        }
                        hr {}
                        dl.properties {
                            xsl:apply-templates select="/state/properties/property" {
                                xsl:with-param name="value" "5"
                            }
                        }
                        textarea id="__pm__commit__message" tabindex="1" name="message" placeholder="Add a Comment" {
                            xsl:value-of select="/state/message" {}
                        }
                        div#__pm__new_commit {
                            input type="submit" tabindex="4" name="save_update" value="Save Update" {}
                            xsl:if test="/state/changes/change" {
                                fieldset#__pm__commit__changes.details {
                                    legend#__pm__commit__changes_legend tabindex="2" role="button" {
                                        "Include Changes"
                                        span#__pm__commit__changes__statistics.token {
                                            xsl:if test="/state/changes/statistics/files != 0" {
                                                span {
                                                    xsl:value-of select="format-number(/state/changes/statistics/files, '#,###.##')" {}
                                                    " file"
                                                    xsl:if test="/state/changes/statistics/files != 1" {
                                                        "s"
                                                    }
                                                }
                                            }
                                            xsl:if test="/state/changes/statistics/insertions != 0" {
                                                span.token--positive {
                                                    "+"
                                                    xsl:value-of select="format-number(/state/changes/statistics/insertions, '#,###.##')" {}
                                                }
                                            }
                                            xsl:if test="/state/changes/statistics/deletions != 0" {
                                                span.token--negative {
                                                    "-"
                                                    xsl:value-of select="format-number(/state/changes/statistics/deletions, '#,###.##')" {}
                                                }
                                            }
                                        }
                                    }
                                    ul {
                                        xsl:apply-templates select="/state/changes/change" {}
                                    }
                                }
                            }
                        }
                    }
                    xsl:choose {
                        xsl:when test="/state/diffs/*" {
                            xsl:apply-templates select="/state/diffs" {}
                        }
                        xsl:otherwise {
                            xsl:apply-templates select="/state/tasks" {}
                        }
                    }
                }
            }
            xsl:template match="/state/properties/property" {
                div.property {
                    xsl:choose {
                        xsl:when test="name = 'Status'" {
                            dt { label for="__pm__commit__properties--status" "Status" }
                            dd.select tabindex="1" {
                                xsl:value-of select="value" {}
                                select id="__pm__commit__properties--status" name="property" data-name="Status" {
                                    xsl:apply-templates "options/option" {}
                                }
                            }
                        }
                        xsl:when test="name = 'Developer'" {
                            dt "Developer"
                            dd.select {
                                input type="text" value="Jaden Carver" {}
                                select name="property" data-name="Developer" {
                                    xsl:apply-templates "options/option" {}
                                }
                            }
                        }
                        xsl:when test="name = 'Description'" {
                            dt "Description"
                            dd {
                                textarea name="property" data-name="Description" {
                                    xsl:value-of select="value" {}
                                }
                            }
                        }
                        xsl:otherwise {
                            dt "Estimate"
                            dd.input {
                                input type="text" name="property" data-name="Estimate" value="{value}" {}
                            }
                        }
                    }
                }
            }
            xsl:template match="/state/properties/property/options/option" {
                xsl:element name="option" {
                    xsl:attribute name="value" {
                        xsl:value-of select="." {}
                    }
                    xsl:if test="./parent::options/parent::property/value = ." {
                        xsl:attribute name="selected" "selected"
                    }
                    xsl:value-of select="." {}
                }
            }
            xsl:template match="/state/diffs" {
                div.diff {
                    pre {
                        code {
                            xsl:copy-of select="*" {}
                        }
                    }
                }
            }
            xsl:template name="diff-lines" {
                xsl:param name="limit" select="1" {}
                xsl:param name="count" select="1" {}
                xsl:if test="$count <= $limit" {
                    li {
                        xsl:value-of select="$count" {}
                    }
                    xsl:call-template name="diff-lines" {
                        xsl:with-param name="limit" select="$limit" {}
                        xsl:with-param name="count" select="$count + 1" {}
                    }
                }
            }
            xsl:template match="task" {
                li {
                    div draggable="true" class="{type}" {
                        strong {
                            xsl:value-of select="name" {}
                        }
                        xsl:value-of select="property[name[text()='Description']]/after" {}
                    }
                }
            }
            xsl:template match="/state/tasks" {
                ul.tiles {
                    header "Sprint"
                    xsl:apply-templates select="task" {}
                }
                ul.tiles {
                    header {
                        "In Progress"
                    }
                    xsl:apply-templates select="/state/task" {}
                }
                ul.tiles {
                    header "In Review"
                }
                ul.tiles {
                    header "Blocked"
                }
                ul.tiles {
                    header "Done"
                }
            }
            xsl:template match="/state/log/commit" {
                li {
                    xsl:if test="./preceding-sibling::commit[1]/user/email=user/email and ./preceding-sibling::commit[1]/timestamp - timestamp > -7200" {
                        xsl:attribute name="class" "continuous"
                    }
                    img src="{user/image}" alt="{user/name} <{user/email}>" {}
                    xsl:if test="changes" {
                        button.button--medium.attachments {
                            svg id="i-paperclip" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="20" height="20" fill="none" stroke="currentcolor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" {
                                path d="M10 9 L10 24 C10 28 13 30 16 30 19 30 22 28 22 24 L22 6 C22 3 20 2 18 2 16 2 14 3 14 6 L14 23 C14 24 15 25 16 25 17 25 18 24 18 23 L18 9" {}
                            }
                        }
                    }
                    blockquote {
                        a.user__name href="#" {
                            xsl:value-of select="user/name" {}
                        }
                        xsl:value-of select="message" {}
                    }
                    xsl:if test="task" {
                        dl.tasks {
                            xsl:apply-templates select="task[property]" {}
                        }
                    }
                    div {
                        time datetime="{localtime}" {
                            xsl:value-of select="localtime" {}
                        }
                    }
                }
            }
            xsl:template match="/state/log/commit/task" {
                dt { xsl:value-of select="name" {} }
                dd {
                    ul.properties {
                        xsl:apply-templates select="property" {}
                    }
                }
            }
            xsl:template match="/state/log/commit/task/property" {
                li.token {
                    span.name { xsl:value-of select="name" {} }
                    xsl:if test="before" {
                        span.before.token--neutral { xsl:value-of select="before" {} }
                    }
                    span.after.token--positive { xsl:value-of select="after" {} }
                }
            }
            xsl:template match="/state/changes/change" {
                li tabindex="3" id="{concat('__pm__changes__checkbox--', @id)}" {
                    xsl:element name="input" {
                        xsl:attribute name="name" { "include" }
                        xsl:attribute name="id" {
                            xsl:value-of select="concat('__pm__changes--', @id)" {}
                        }
                        xsl:attribute name="value" {
                            xsl:value-of select="path" {}
                        }
                        xsl:attribute name="tabindex" "-1"
                        xsl:attribute name="type" "checkbox"
                        xsl:if test="included='true'" {
                            xsl:attribute name="checked" {}
                        }
                        xsl:if test="removal='true'" {
                            xsl:attribute name="class" { "delete" }
                        }
                    }
                    label for="__pm__changes--{@id}" {
                        xsl:value-of select="path" {}
                    }
                    button.button--tiny name="diff" value="{path}" { " +10 -10" }
                }
            }
        }
    };
    format!("{}{}", XML, markup.into_string())
}

<|endoftext|>


<commit_before>use std::cmp::min;
use std::collections::{BTreeMap, HashSet};
use std::convert::TryInto;
use std::fmt;
use std::sync::Arc;
use std::time::Duration;

use bazel_protos::{self, call_option};
use bytes::{Bytes, BytesMut};
use futures::compat::Future01CompatExt;
use futures::future::{FutureExt, TryFutureExt};
use futures01::{future, Future, Sink, Stream};
use hashing::Digest;
use serverset::{retry, Serverset};
use workunit_store::new_span_id;

use super::{BackoffConfig, EntryType};

#[derive(Clone)]
pub struct ByteStore {
  instance_name: Option<String>,
  chunk_size_bytes: usize,
  upload_timeout: Duration,
  rpc_attempts: usize,
  env: Arc<grpcio::Environment>,
  serverset: Serverset<grpcio::Channel>,
  headers: BTreeMap<String, String>,
}

impl fmt::Debug for ByteStore {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    write!(f, "ByteStore(name={:?})", self.instance_name)
  }
}

impl ByteStore {
  pub fn new(
    cas_addresses: Vec<String>,
    instance_name: Option<String>,
    root_ca_certs: Option<Vec<u8>>,
    oauth_bearer_token: Option<String>,
    thread_count: usize,
    chunk_size_bytes: usize,
    upload_timeout: Duration,
    backoff_config: BackoffConfig,
    rpc_retries: usize,
    connection_limit: usize,
  ) -> Result<ByteStore, String> {
    let env = Arc::new(grpcio::Environment::new(thread_count));
    let env2 = env.clone();

    let connect = move |cas_address: &str| {
      let builder = grpcio::ChannelBuilder::new(env2.clone());
      if let Some(ref root_ca_certs) = root_ca_certs {
        let creds = grpcio::ChannelCredentialsBuilder::new()
          .root_cert(root_ca_certs.clone())
          .build();
        builder.secure_connect(cas_address, creds)
      } else {
        builder.connect(cas_address)
      }
    };

    let serverset = Serverset::new(cas_addresses, connect, connection_limit, backoff_config)?;

    Ok(ByteStore {
      instance_name,
      chunk_size_bytes,
      upload_timeout,
      rpc_attempts: rpc_retries + 1,
      env,
      serverset,
      headers: oauth_bearer_token
        .iter()
        .map(|t| (String::from("authorization"), format!("Bearer {}", t)))
        .collect(),
    })
  }

  async fn with_byte_stream_client<
    Value: Send,
    Fut: std::future::Future<Output = Result<Value, String>>,
    F: Fn(bazel_protos::bytestream_grpc::ByteStreamClient) -> Fut,
  >(
    &self,
    f: F,
  ) -> Result<Value, String> {
    retry::all_errors_immediately(&self.serverset, self.rpc_attempts, move |channel| {
      f(bazel_protos::bytestream_grpc::ByteStreamClient::new(
        channel,
      ))
    })
    .await
  }

  async fn with_cas_client<
    Value: Send,
    Fut: std::future::Future<Output = Result<Value, String>>,
    F: Fn(bazel_protos::remote_execution_grpc::ContentAddressableStorageClient) -> Fut,
  >(
    &self,
    f: F,
  ) -> Result<Value, String> {
    retry::all_errors_immediately(&self.serverset, self.rpc_attempts, move |channel| {
      f(bazel_protos::remote_execution_grpc::ContentAddressableStorageClient::new(channel))
    })
    .await
  }

  pub async fn store_bytes(&self, bytes: &[u8]) -> Result<Digest, String> {
    let len = bytes.len();
    let digest = Digest::of_bytes(&bytes);
    let resource_name = format!(
      "{}/uploads/{}/blobs/{}/{}",
      self.instance_name.clone().unwrap_or_default(),
      uuid::Uuid::new_v4(),
      digest.0,
      digest.1,
    );
    let workunit_name = format!("store_bytes({})", resource_name.clone());
    let span_id = new_span_id();
    if let Some(workunit_state) = workunit_store::get_workunit_state() {
      let parent_id = workunit_state.parent_id;
      let metadata = workunit_store::WorkunitMetadata::new();
      workunit_state
        .store
        .start_workunit(span_id.clone(), workunit_name, parent_id, metadata);
    }
    let store = self.clone();

    let result = self
      .with_byte_stream_client(move |client| {
        let resource_name = resource_name.clone();
        let store = store.clone();
        async move {
          let (sender, receiver) = client
            .write_opt(call_option(&store.headers, None)?.timeout(store.upload_timeout))
            .map_err(|err| {
              format!(
                "Error attempting to connect to upload digest {:?}: {:?}",
                digest, err
              )
            })?;

          let chunk_size_bytes = store.chunk_size_bytes;
          let resource_name = resource_name.clone();
          let stream = futures01::stream::unfold::<_, _, future::FutureResult<_, grpcio::Error>, _>(
            (0, false),
            move |(offset, has_sent_any)| {
              if offset >= bytes.len() && has_sent_any {
                None
              } else {
                let mut req = bazel_protos::bytestream::WriteRequest::new();
                req.set_resource_name(resource_name.clone());
                req.set_write_offset(offset as i64);
                let next_offset = min(offset + chunk_size_bytes, bytes.len());
                req.set_finish_write(next_offset == bytes.len());
                req.set_data(Bytes::from(&bytes[offset..next_offset]));
                Some(future::ok((
                  (req, grpcio::WriteFlags::default()),
                  (next_offset, true),
                )))
              }
            },
          );

          sender
            .send_all(stream)
            .map(|_| ())
            .or_else(move |e| {
              match e {
                // Some implementations of the remote execution API early-return if the blob has
                // been concurrently uploaded by another client. In this case, they return a
                // WriteResponse with a committed_size equal to the digest's entire size before
                // closing the stream.
                // Because the server then closes the stream, the client gets an RpcFinished
                // error in this case. We ignore this, and will later on verify that the
                // committed_size we received from the server is equal to the expected one. If
                // these are not equal, the upload will be considered a failure at that point.
                // Whether this type of response will become part of the official API is up for
                // discussion: see
                // https://groups.google.com/d/topic/remote-execution-apis/NXUe3ItCw68/discussion.
                grpcio::Error::RpcFinished(None) => Ok(()),
                e => Err(format!(
                  "Error attempting to upload digest {:?}: {:?}",
                  digest, e
                )),
              }
            })
            .compat()
            .await?;

          let received = receiver
            .map_err(move |e| {
              format!(
                "Error from server when uploading digest {:?}: {:?}",
                digest, e
              )
            })
            .compat()
            .await?;

          if received.get_committed_size() == len as i64 {
            Ok(digest)
          } else {
            Err(format!(
              "Uploading file with digest {:?}: want committed size {} but got {}",
              digest,
              len,
              received.get_committed_size()
            ))
          }
        }
      })
      .await;

    if let Some(workunit_state) = workunit_store::get_workunit_state() {
      workunit_state.store.complete_workunit(span_id)
    }

    result
  }

  pub async fn load_bytes_with<
    T: Send + 'static,
    F: Fn(Bytes) -> T + Send + Sync + Clone + 'static,
  >(
    &self,
    _entry_type: EntryType,
    digest: Digest,
    f: F,
  ) -> Result<Option<T>, String> {
    let store = self.clone();
    let resource_name = format!(
      "{}/blobs/{}/{}",
      store.instance_name.clone().unwrap_or_default(),
      digest.0,
      digest.1
    );
    let workunit_name = format!("load_bytes_with({})", resource_name.clone());
    let span_id = new_span_id();
    if let Some(workunit_state) = workunit_store::get_workunit_state() {
      let parent_id = workunit_state.parent_id;
      let metadata = workunit_store::WorkunitMetadata::new();
      workunit_state
        .store
        .start_workunit(span_id.clone(), workunit_name, parent_id, metadata);
    }

    let result = self
      .with_byte_stream_client(move |client| {
        let resource_name = resource_name.clone();
        let store = store.clone();
        let f = f.clone();
        async move {
          let stream = client
            .read_opt(
              &{
                let mut req = bazel_protos::bytestream::ReadRequest::new();
                req.set_resource_name(resource_name.clone());
                req.set_read_offset(0);
                // 0 means no limit.
                req.set_read_limit(0);
                req
              },
              call_option(&store.headers, None)?,
            )
            .map_err(|err| format!("Error making CAS read request for {:?}: {:?}", digest, err))?;

          let bytes_res = stream
            .fold(BytesMut::with_capacity(digest.1), move |mut bytes, r| {
              bytes.extend_from_slice(&r.data);
              future::ok::<_, grpcio::Error>(bytes)
            })
            .compat()
            .await;

          // We ensure that we hold onto the client until after we've consumed the stream as a
          // workaround for https://github.com/pingcap/grpc-rs/issues/123
          std::mem::drop(client);

          let maybe_bytes = match bytes_res {
            Ok(bytes) => Some(bytes.freeze()),
            Err(grpcio::Error::RpcFailure(grpcio::RpcStatus {
              status: grpcio::RpcStatusCode::NOT_FOUND,
              ..
            })) => None,
            Err(e) => {
              return Err(format!(
                "Error from server in response to CAS read request: {:?}",
                e
              ))
            }
          };

          Ok(maybe_bytes.map(f))
        }
      })
      .await;

    if let Some(workunit_state) = workunit_store::get_workunit_state() {
      workunit_state.store.complete_workunit(span_id);
    }

    result
  }

  ///
  /// Given a collection of Digests (digests),
  /// returns the set of digests from that collection not present in the CAS.
  ///
  pub fn list_missing_digests(
    &self,
    request: bazel_protos::remote_execution::FindMissingBlobsRequest,
  ) -> impl Future<Item = HashSet<Digest>, Error = String> {
    let store = self.clone();
    let workunit_name = format!(
      "list_missing_digests({})",
      store.instance_name.clone().unwrap_or_default()
    );
    let span_id = new_span_id();
    if let Some(workunit_state) = workunit_store::get_workunit_state() {
      let parent_id = workunit_state.parent_id;
      let metadata = workunit_store::WorkunitMetadata::new();
      workunit_state
        .store
        .start_workunit(span_id.clone(), workunit_name, parent_id, metadata);
    }

    async move {
      let store2 = store.clone();
      let res = store2
        .with_cas_client(move |client| {
          let request = request.clone();
          let store = store.clone();
          async move {
            let response = client
              .find_missing_blobs_opt(&request, call_option(&store.headers, None)?)
              .map_err(|err| {
                format!(
                  "Error from server in response to find_missing_blobs_request: {:?}",
                  err
                )
              })?;
            response
              .get_missing_blob_digests()
              .iter()
              .map(|digest| digest.try_into())
              .collect::<Result<HashSet<_>, _>>()
          }
        })
        .await;
      if let Some(workunit_state) = workunit_store::get_workunit_state() {
        workunit_state.store.complete_workunit(span_id);
      }
      res
    }
    .boxed()
    .compat()
  }

  pub(super) fn find_missing_blobs_request<'a, Digests: Iterator<Item = &'a Digest>>(
    &self,
    digests: Digests,
  ) -> bazel_protos::remote_execution::FindMissingBlobsRequest {
    let mut request = bazel_protos::remote_execution::FindMissingBlobsRequest::new();
    if let Some(ref instance_name) = self.instance_name {
      request.set_instance_name(instance_name.clone());
    }
    for digest in digests {
      request.mut_blob_digests().push(digest.into());
    }
    request
  }
}
<commit_msg> Use debug level for remote store workunits #10238 <commit_after>use std::cmp::min;
use std::collections::{BTreeMap, HashSet};
use std::convert::TryInto;
use std::fmt;
use std::sync::Arc;
use std::time::Duration;

use bazel_protos::{self, call_option};
use bytes::{Bytes, BytesMut};
use futures::compat::Future01CompatExt;
use futures::future::{FutureExt, TryFutureExt};
use futures01::{future, Future, Sink, Stream};
use hashing::Digest;
use log::Level;
use serverset::{retry, Serverset};
use workunit_store::new_span_id;

use super::{BackoffConfig, EntryType};

#[derive(Clone)]
pub struct ByteStore {
  instance_name: Option<String>,
  chunk_size_bytes: usize,
  upload_timeout: Duration,
  rpc_attempts: usize,
  env: Arc<grpcio::Environment>,
  serverset: Serverset<grpcio::Channel>,
  headers: BTreeMap<String, String>,
}

impl fmt::Debug for ByteStore {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    write!(f, "ByteStore(name={:?})", self.instance_name)
  }
}

impl ByteStore {
  pub fn new(
    cas_addresses: Vec<String>,
    instance_name: Option<String>,
    root_ca_certs: Option<Vec<u8>>,
    oauth_bearer_token: Option<String>,
    thread_count: usize,
    chunk_size_bytes: usize,
    upload_timeout: Duration,
    backoff_config: BackoffConfig,
    rpc_retries: usize,
    connection_limit: usize,
  ) -> Result<ByteStore, String> {
    let env = Arc::new(grpcio::Environment::new(thread_count));
    let env2 = env.clone();

    let connect = move |cas_address: &str| {
      let builder = grpcio::ChannelBuilder::new(env2.clone());
      if let Some(ref root_ca_certs) = root_ca_certs {
        let creds = grpcio::ChannelCredentialsBuilder::new()
          .root_cert(root_ca_certs.clone())
          .build();
        builder.secure_connect(cas_address, creds)
      } else {
        builder.connect(cas_address)
      }
    };

    let serverset = Serverset::new(cas_addresses, connect, connection_limit, backoff_config)?;

    Ok(ByteStore {
      instance_name,
      chunk_size_bytes,
      upload_timeout,
      rpc_attempts: rpc_retries + 1,
      env,
      serverset,
      headers: oauth_bearer_token
        .iter()
        .map(|t| (String::from("authorization"), format!("Bearer {}", t)))
        .collect(),
    })
  }

  async fn with_byte_stream_client<
    Value: Send,
    Fut: std::future::Future<Output = Result<Value, String>>,
    F: Fn(bazel_protos::bytestream_grpc::ByteStreamClient) -> Fut,
  >(
    &self,
    f: F,
  ) -> Result<Value, String> {
    retry::all_errors_immediately(&self.serverset, self.rpc_attempts, move |channel| {
      f(bazel_protos::bytestream_grpc::ByteStreamClient::new(
        channel,
      ))
    })
    .await
  }

  async fn with_cas_client<
    Value: Send,
    Fut: std::future::Future<Output = Result<Value, String>>,
    F: Fn(bazel_protos::remote_execution_grpc::ContentAddressableStorageClient) -> Fut,
  >(
    &self,
    f: F,
  ) -> Result<Value, String> {
    retry::all_errors_immediately(&self.serverset, self.rpc_attempts, move |channel| {
      f(bazel_protos::remote_execution_grpc::ContentAddressableStorageClient::new(channel))
    })
    .await
  }

  pub async fn store_bytes(&self, bytes: &[u8]) -> Result<Digest, String> {
    let len = bytes.len();
    let digest = Digest::of_bytes(&bytes);
    let resource_name = format!(
      "{}/uploads/{}/blobs/{}/{}",
      self.instance_name.clone().unwrap_or_default(),
      uuid::Uuid::new_v4(),
      digest.0,
      digest.1,
    );
    let workunit_name = format!("store_bytes({})", resource_name.clone());
    let span_id = new_span_id();
    if let Some(workunit_state) = workunit_store::get_workunit_state() {
      let parent_id = workunit_state.parent_id;
      let metadata = workunit_store::WorkunitMetadata::with_level(Level::Debug);
      workunit_state
        .store
        .start_workunit(span_id.clone(), workunit_name, parent_id, metadata);
    }
    let store = self.clone();

    let result = self
      .with_byte_stream_client(move |client| {
        let resource_name = resource_name.clone();
        let store = store.clone();
        async move {
          let (sender, receiver) = client
            .write_opt(call_option(&store.headers, None)?.timeout(store.upload_timeout))
            .map_err(|err| {
              format!(
                "Error attempting to connect to upload digest {:?}: {:?}",
                digest, err
              )
            })?;

          let chunk_size_bytes = store.chunk_size_bytes;
          let resource_name = resource_name.clone();
          let stream = futures01::stream::unfold::<_, _, future::FutureResult<_, grpcio::Error>, _>(
            (0, false),
            move |(offset, has_sent_any)| {
              if offset >= bytes.len() && has_sent_any {
                None
              } else {
                let mut req = bazel_protos::bytestream::WriteRequest::new();
                req.set_resource_name(resource_name.clone());
                req.set_write_offset(offset as i64);
                let next_offset = min(offset + chunk_size_bytes, bytes.len());
                req.set_finish_write(next_offset == bytes.len());
                req.set_data(Bytes::from(&bytes[offset..next_offset]));
                Some(future::ok((
                  (req, grpcio::WriteFlags::default()),
                  (next_offset, true),
                )))
              }
            },
          );

          sender
            .send_all(stream)
            .map(|_| ())
            .or_else(move |e| {
              match e {
                // Some implementations of the remote execution API early-return if the blob has
                // been concurrently uploaded by another client. In this case, they return a
                // WriteResponse with a committed_size equal to the digest's entire size before
                // closing the stream.
                // Because the server then closes the stream, the client gets an RpcFinished
                // error in this case. We ignore this, and will later on verify that the
                // committed_size we received from the server is equal to the expected one. If
                // these are not equal, the upload will be considered a failure at that point.
                // Whether this type of response will become part of the official API is up for
                // discussion: see
                // https://groups.google.com/d/topic/remote-execution-apis/NXUe3ItCw68/discussion.
                grpcio::Error::RpcFinished(None) => Ok(()),
                e => Err(format!(
                  "Error attempting to upload digest {:?}: {:?}",
                  digest, e
                )),
              }
            })
            .compat()
            .await?;

          let received = receiver
            .map_err(move |e| {
              format!(
                "Error from server when uploading digest {:?}: {:?}",
                digest, e
              )
            })
            .compat()
            .await?;

          if received.get_committed_size() == len as i64 {
            Ok(digest)
          } else {
            Err(format!(
              "Uploading file with digest {:?}: want committed size {} but got {}",
              digest,
              len,
              received.get_committed_size()
            ))
          }
        }
      })
      .await;

    if let Some(workunit_state) = workunit_store::get_workunit_state() {
      workunit_state.store.complete_workunit(span_id)
    }

    result
  }

  pub async fn load_bytes_with<
    T: Send + 'static,
    F: Fn(Bytes) -> T + Send + Sync + Clone + 'static,
  >(
    &self,
    _entry_type: EntryType,
    digest: Digest,
    f: F,
  ) -> Result<Option<T>, String> {
    let store = self.clone();
    let resource_name = format!(
      "{}/blobs/{}/{}",
      store.instance_name.clone().unwrap_or_default(),
      digest.0,
      digest.1
    );
    let workunit_name = format!("load_bytes_with({})", resource_name.clone());
    let span_id = new_span_id();
    if let Some(workunit_state) = workunit_store::get_workunit_state() {
      let parent_id = workunit_state.parent_id;
      let metadata = workunit_store::WorkunitMetadata::with_level(Level::Debug);
      workunit_state
        .store
        .start_workunit(span_id.clone(), workunit_name, parent_id, metadata);
    }

    let result = self
      .with_byte_stream_client(move |client| {
        let resource_name = resource_name.clone();
        let store = store.clone();
        let f = f.clone();
        async move {
          let stream = client
            .read_opt(
              &{
                let mut req = bazel_protos::bytestream::ReadRequest::new();
                req.set_resource_name(resource_name.clone());
                req.set_read_offset(0);
                // 0 means no limit.
                req.set_read_limit(0);
                req
              },
              call_option(&store.headers, None)?,
            )
            .map_err(|err| format!("Error making CAS read request for {:?}: {:?}", digest, err))?;

          let bytes_res = stream
            .fold(BytesMut::with_capacity(digest.1), move |mut bytes, r| {
              bytes.extend_from_slice(&r.data);
              future::ok::<_, grpcio::Error>(bytes)
            })
            .compat()
            .await;

          // We ensure that we hold onto the client until after we've consumed the stream as a
          // workaround for https://github.com/pingcap/grpc-rs/issues/123
          std::mem::drop(client);

          let maybe_bytes = match bytes_res {
            Ok(bytes) => Some(bytes.freeze()),
            Err(grpcio::Error::RpcFailure(grpcio::RpcStatus {
              status: grpcio::RpcStatusCode::NOT_FOUND,
              ..
            })) => None,
            Err(e) => {
              return Err(format!(
                "Error from server in response to CAS read request: {:?}",
                e
              ))
            }
          };

          Ok(maybe_bytes.map(f))
        }
      })
      .await;

    if let Some(workunit_state) = workunit_store::get_workunit_state() {
      workunit_state.store.complete_workunit(span_id);
    }

    result
  }

  ///
  /// Given a collection of Digests (digests),
  /// returns the set of digests from that collection not present in the CAS.
  ///
  pub fn list_missing_digests(
    &self,
    request: bazel_protos::remote_execution::FindMissingBlobsRequest,
  ) -> impl Future<Item = HashSet<Digest>, Error = String> {
    let store = self.clone();
    let workunit_name = format!(
      "list_missing_digests({})",
      store.instance_name.clone().unwrap_or_default()
    );
    let span_id = new_span_id();
    if let Some(workunit_state) = workunit_store::get_workunit_state() {
      let parent_id = workunit_state.parent_id;
      let metadata = workunit_store::WorkunitMetadata::with_level(Level::Debug);
      workunit_state
        .store
        .start_workunit(span_id.clone(), workunit_name, parent_id, metadata);
    }

    async move {
      let store2 = store.clone();
      let res = store2
        .with_cas_client(move |client| {
          let request = request.clone();
          let store = store.clone();
          async move {
            let response = client
              .find_missing_blobs_opt(&request, call_option(&store.headers, None)?)
              .map_err(|err| {
                format!(
                  "Error from server in response to find_missing_blobs_request: {:?}",
                  err
                )
              })?;
            response
              .get_missing_blob_digests()
              .iter()
              .map(|digest| digest.try_into())
              .collect::<Result<HashSet<_>, _>>()
          }
        })
        .await;
      if let Some(workunit_state) = workunit_store::get_workunit_state() {
        workunit_state.store.complete_workunit(span_id);
      }
      res
    }
    .boxed()
    .compat()
  }

  pub(super) fn find_missing_blobs_request<'a, Digests: Iterator<Item = &'a Digest>>(
    &self,
    digests: Digests,
  ) -> bazel_protos::remote_execution::FindMissingBlobsRequest {
    let mut request = bazel_protos::remote_execution::FindMissingBlobsRequest::new();
    if let Some(ref instance_name) = self.instance_name {
      request.set_instance_name(instance_name.clone());
    }
    for digest in digests {
      request.mut_blob_digests().push(digest.into());
    }
    request
  }
}
<|endoftext|>


<commit_before>//! This is a simle crate module

use std::io::prelude::*;
use std::io::BufReader;
use std::io::Error;
use std::fs::File;
use std::path::PathBuf;

use rustc_serialize::json::Json;
use rustc_serialize::json::ParserError;

/// Really simple crate model
#[derive(Debug)]
pub struct Crate {
    /// Name of crate
    pub name: String,
    /// Versions of crate
    pub versions: Vec<String>,
}

#[derive(Debug)]
pub enum CrateOpenError {
    FileNotFound,
    ParseError(ParserError),
    IoError(Error),
    NotObject,
    NameNotFound,
    VersNotFound,
}

impl Crate {
    /// Returns a new Crate
    ///
    /// # Examples
    ///
    /// ```
    /// let crte = Crate::new("cratesfyi".to_string(),
    ///                       vec!["0.1.0".to_string()]);
    /// assert_eq!(crte.name, "cratesfyi");
    /// ```
    pub fn new(name: String, versions: Vec<String>) -> Crate {
        Crate {
            name: name,
            versions: versions,
        }
    }

    pub fn from_cargo_index_file(path: PathBuf) -> Result<Crate, CrateOpenError> {

        let mut file = match File::open(path) {
            Ok(f) => BufReader::new(f),
            Err(_) => return Err(CrateOpenError::FileNotFound),
        };

        let mut line = String::new();

        let mut name = String::new();
        let mut versions = Vec::new();

        while file.read_line(&mut line).unwrap() > 0 {

            let (cname, vers) = match Crate::parse_cargo_index_line(&line) {
                Ok((c, v)) => (c, v),
                Err(e) => return Err(e)
            };

            name = cname;
            versions.push(vers);

            line.clear();
        }

        versions.reverse();

        Ok(Crate {
            name: name,
            versions: versions
        })
    }

    /// Create Crate from crate name and try to find it in crates.io-index
    /// to load versions
    pub fn from_cargo_index_path(name: &str, path: &PathBuf) -> Result<Crate, CrateOpenError> {

        if !path.is_dir() {
            return Err(CrateOpenError::FileNotFound);
        }

        for file in try!(path.read_dir().map_err(CrateOpenError::IoError)) {

            let file = try!(file.map_err(CrateOpenError::IoError));

            let path = file.path();

            // skip files under .git and config.json
            if path.to_str().unwrap().contains(".git") ||
                path.file_name().unwrap() == "config.json" {
                    continue;
                }

            if path.is_dir() {
                if let Ok(c) = Crate::from_cargo_index_path(&name, &path) {
                    return Ok(c);
                }
            } else if file.file_name().into_string().unwrap() == name {
                return Crate::from_cargo_index_file(path);
            }

        }

        Err(CrateOpenError::FileNotFound)
    }

    fn parse_cargo_index_line(line: &String) -> Result<(String, String), CrateOpenError> {
        let data = try!(Json::from_str(line.trim()).map_err(CrateOpenError::ParseError));
        let obj = try!(data.as_object().ok_or(CrateOpenError::NotObject));

        let crate_name = try!(obj.get("name")
                              .and_then(|n| n.as_string())
                              .ok_or(CrateOpenError::NameNotFound));

        let vers = try!(obj.get("vers")
                        .and_then(|n| n.as_string())
                        .ok_or(CrateOpenError::VersNotFound));

        Ok((String::from(crate_name), String::from(vers)))
    }

    pub fn get_version_index(&self, requested_version: &str) -> Option<usize> {
        for i in 0..self.versions.len() {
            if self.versions[i] == requested_version {
                return Some(i);
            }
        }
        None
    }

    pub fn version_starts_with(&self, version: String) -> Option<usize> {
        // if version is "*" return latest version index which is 0
        if version == "*" {
            return Some(0);
        }
        for i in 0..self.versions.len() {
            if self.versions[i].starts_with(&version) {
                return Some(i)
            }
        }
        None
    }

    pub fn canonical_name(&self, version_index: usize) -> String {
        format!("{}-{}", self.name, self.versions[version_index])
    }

}

#[cfg(test)]
mod test {
    use super::*;
    use std::env;
    use std::path::PathBuf;

    #[test]
    fn test_get_vesion_index() {
        let crte = Crate::new("cratesfyi".to_string(),
                              vec!["0.1.0".to_string(), "0.1.1".to_string()]);
        assert_eq!(crte.get_version_index("0.1.0"), Some(0));
        assert_eq!(crte.get_version_index("0.1.1"), Some(1));
        assert_eq!(crte.get_version_index("0.1.2"), None);
    }

    // Rest of the tests only works if crates.io-index is exists in:
    // ../cratesfyi-prefix/crates.io-index

    #[test]
    #[ignore]
    fn test_from_cargo_index_path() {
        let mut path = PathBuf::from(env::current_dir().unwrap());
        path.push("../cratesfyi-prefix/crates.io-index");

        if !path.exists() {
            return;
        }

        let crte = Crate::from_cargo_index_path("rand", &path).unwrap();
        assert_eq!(crte.name, "rand");
        assert!(crte.versions.len() > 0);
    }

    #[test]
    #[ignore]
    fn test_version_starts_with() {
        let mut path = PathBuf::from(env::current_dir().unwrap());
        path.push("../cratesfyi-prefix/crates.io-index");

        if !path.exists() {
            return;
        }

        let crte = Crate::from_cargo_index_path("rand", &path).unwrap();
        assert!(crte.version_starts_with("0.1".to_string()).is_some());
        assert!(crte.version_starts_with("*".to_string()).is_some());
        assert!(crte.version_starts_with("999.099.99".to_string()).is_none());
    }

}
<commit_msg>Use &str parameter in version_starts_with<commit_after>//! This is a simle crate module

use std::io::prelude::*;
use std::io::BufReader;
use std::io::Error;
use std::fs::File;
use std::path::PathBuf;

use rustc_serialize::json::Json;
use rustc_serialize::json::ParserError;

/// Really simple crate model
#[derive(Debug)]
pub struct Crate {
    /// Name of crate
    pub name: String,
    /// Versions of crate
    pub versions: Vec<String>,
}

#[derive(Debug)]
pub enum CrateOpenError {
    FileNotFound,
    ParseError(ParserError),
    IoError(Error),
    NotObject,
    NameNotFound,
    VersNotFound,
}

impl Crate {
    /// Returns a new Crate
    ///
    /// # Examples
    ///
    /// ```
    /// let crte = Crate::new("cratesfyi".to_string(),
    ///                       vec!["0.1.0".to_string()]);
    /// assert_eq!(crte.name, "cratesfyi");
    /// ```
    pub fn new(name: String, versions: Vec<String>) -> Crate {
        Crate {
            name: name,
            versions: versions,
        }
    }

    pub fn from_cargo_index_file(path: PathBuf) -> Result<Crate, CrateOpenError> {

        let mut file = match File::open(path) {
            Ok(f) => BufReader::new(f),
            Err(_) => return Err(CrateOpenError::FileNotFound),
        };

        let mut line = String::new();

        let mut name = String::new();
        let mut versions = Vec::new();

        while file.read_line(&mut line).unwrap() > 0 {

            let (cname, vers) = match Crate::parse_cargo_index_line(&line) {
                Ok((c, v)) => (c, v),
                Err(e) => return Err(e)
            };

            name = cname;
            versions.push(vers);

            line.clear();
        }

        versions.reverse();

        Ok(Crate {
            name: name,
            versions: versions
        })
    }

    /// Create Crate from crate name and try to find it in crates.io-index
    /// to load versions
    pub fn from_cargo_index_path(name: &str, path: &PathBuf) -> Result<Crate, CrateOpenError> {

        if !path.is_dir() {
            return Err(CrateOpenError::FileNotFound);
        }

        for file in try!(path.read_dir().map_err(CrateOpenError::IoError)) {

            let file = try!(file.map_err(CrateOpenError::IoError));

            let path = file.path();

            // skip files under .git and config.json
            if path.to_str().unwrap().contains(".git") ||
                path.file_name().unwrap() == "config.json" {
                    continue;
                }

            if path.is_dir() {
                if let Ok(c) = Crate::from_cargo_index_path(&name, &path) {
                    return Ok(c);
                }
            } else if file.file_name().into_string().unwrap() == name {
                return Crate::from_cargo_index_file(path);
            }

        }

        Err(CrateOpenError::FileNotFound)
    }

    fn parse_cargo_index_line(line: &String) -> Result<(String, String), CrateOpenError> {
        let data = try!(Json::from_str(line.trim()).map_err(CrateOpenError::ParseError));
        let obj = try!(data.as_object().ok_or(CrateOpenError::NotObject));

        let crate_name = try!(obj.get("name")
                              .and_then(|n| n.as_string())
                              .ok_or(CrateOpenError::NameNotFound));

        let vers = try!(obj.get("vers")
                        .and_then(|n| n.as_string())
                        .ok_or(CrateOpenError::VersNotFound));

        Ok((String::from(crate_name), String::from(vers)))
    }

    pub fn get_version_index(&self, requested_version: &str) -> Option<usize> {
        for i in 0..self.versions.len() {
            if self.versions[i] == requested_version {
                return Some(i);
            }
        }
        None
    }

    pub fn version_starts_with(&self, version: &str) -> Option<usize> {
        // if version is "*" return latest version index which is 0
        if version == "*" {
            return Some(0);
        }
        for i in 0..self.versions.len() {
            if self.versions[i].starts_with(&version) {
                return Some(i)
            }
        }
        None
    }

    pub fn canonical_name(&self, version_index: usize) -> String {
        format!("{}-{}", self.name, self.versions[version_index])
    }

}

#[cfg(test)]
mod test {
    use super::*;
    use std::env;
    use std::path::PathBuf;

    #[test]
    fn test_get_vesion_index() {
        let crte = Crate::new("cratesfyi".to_string(),
                              vec!["0.1.0".to_string(), "0.1.1".to_string()]);
        assert_eq!(crte.get_version_index("0.1.0"), Some(0));
        assert_eq!(crte.get_version_index("0.1.1"), Some(1));
        assert_eq!(crte.get_version_index("0.1.2"), None);
    }

    // Rest of the tests only works if crates.io-index is exists in:
    // ../cratesfyi-prefix/crates.io-index

    #[test]
    #[ignore]
    fn test_from_cargo_index_path() {
        let mut path = PathBuf::from(env::current_dir().unwrap());
        path.push("../cratesfyi-prefix/crates.io-index");

        if !path.exists() {
            return;
        }

        let crte = Crate::from_cargo_index_path("rand", &path).unwrap();
        assert_eq!(crte.name, "rand");
        assert!(crte.versions.len() > 0);
    }

    #[test]
    #[ignore]
    fn test_version_starts_with() {
        let mut path = PathBuf::from(env::current_dir().unwrap());
        path.push("../cratesfyi-prefix/crates.io-index");

        if !path.exists() {
            return;
        }

        let crte = Crate::from_cargo_index_path("rand", &path).unwrap();
        assert!(crte.version_starts_with("0.1".to_string()).is_some());
        assert!(crte.version_starts_with("*".to_string()).is_some());
        assert!(crte.version_starts_with("999.099.99".to_string()).is_none());
    }

}
<|endoftext|>


<commit_before>#[repr(i32)]
pub enum HintStyle {
  Default = 0,
  None = 1,
  Slight = 2,
  Medium = 3,
  Full = 4
}

<commit_msg>Copied documentation from Cairo for hint_style<commit_after>//! Describe font hint style

///  Specifies the type of hinting to do on font outlines. Hinting is the process of fitting outlines to the pixel grid in order to improve the appearance of the result. Since hinting outlines involves distorting them, it also reduces the faithfulness to the original outline shapes. Not all of the outline hinting styles are supported by all font backends.
///
/// New entries may be added in future versions.
///
/// Since 1.0
#[repr(i32)]
pub enum HintStyle {
  /// Use the default hint style for font backend and target device, since 1.0
  Default = 0,
  /// Do not hint outlines, since 1.0
  None = 1,
  /// Hint outlines slightly to improve contrast while retaining good fidelity to the original shapes, since 1.0
  Slight = 2,
  /// Hint outlines with medium strength giving a compromise between fidelity to the original shapes and contrast, since 1.0
  Medium = 3,
  /// Hint outlines to maximize contrast, since 1.0
  Full = 4
}

<|endoftext|>


<commit_before>use std::io::{Listener, Acceptor};
use std::io::net::ip::SocketAddr;
use time::precise_time_ns;

use std::io::net::tcp::TcpListener;

use buffer::BufferedStream;

pub use self::request::{RequestBuffer, Request};
pub use self::response::ResponseWriter;

pub mod request;
pub mod response;

pub trait Server: Send + Clone {
	fn handle_request(&self, request: Request, response: &mut ResponseWriter) -> ();

	// XXX: this could also be implemented on the serve methods
	fn get_config(&self) -> Config;

	/**
	 * Attempt to bind to the address and port and start serving forever.
	 *
	 * This will only return if the initial connection fails or something else blows up.
	 */
    fn serve_forever(self) {
        let config = self.get_config();
        debug!("About to bind to {}", config.bind_address);
        let mut acceptor = match TcpListener::bind(config.bind_address.ip.to_str().as_slice(), config.bind_address.port).listen() {
            Err(err) => {
                error!("bind or listen failed :-(: {}", err);
                return;
            },
            Ok(acceptor) => acceptor,
        };
        debug!("listening");
        let (perf_sender, perf_receiver) = channel();
        spawn(proc() {
            perf_dumper(perf_receiver);
        });
        loop {
            let time_start = precise_time_ns();
            let stream = match acceptor.accept() {
                Err(error) => {
                    debug!("accept failed: {}", error);
                    // Question: is this the correct thing to do? We should probably be more
                    // intelligent, for there are some accept failures that are likely to be
                    // permanent, such that continuing would be a very bad idea, such as
                    // ENOBUFS/ENOMEM; and some where it should just be ignored, e.g.
                    // ECONNABORTED. TODO.
                    continue;
                },
                Ok(socket) => socket,
            };
            let child_perf_sender = perf_sender.clone();
            let child_self = self.clone();
            spawn(proc() {
                let mut time_start = time_start;
                let mut stream = BufferedStream::new(stream);
                debug!("accepted connection");
                let mut first = true;
                loop {  // A keep-alive loop, condition at end
                    let mut time_spawned = precise_time_ns();
                    let (request, err_status) = Request::load(&mut stream);
                    let close_connection = request.close_connection;
                    let time_request_made = precise_time_ns();
                    if !first {
                        // Subsequent requests on this connection have no spawn time.
                        // Moreover we cannot detect the time spent parsing the request as we have
                        // not exposed the time when the first byte was received.
                        time_start = time_request_made;
                        time_spawned = time_request_made;
                    }
                    let mut response = box ResponseWriter::new(&mut stream);
                    let time_response_made = precise_time_ns();
                    match err_status {
                        Ok(()) => {
                            child_self.handle_request(request, response);
                            // Ensure that we actually do send a response:
                            match response.try_write_headers() {
                                Err(err) => {
                                    error!("Writing headers failed: {}", err);
                                    return;  // Presumably bad connection, so give up.
                                },
                                Ok(_) => (),
                            }
                        },
                        Err(status) => {
                            // Uh oh, it's a response that I as a server cannot cope with.
                            // No good user-agent should have caused this, so for the moment
                            // at least I am content to send no body in the response.
                            response.status = status;
                            response.headers.content_length = Some(0);
                            match response.write_headers() {
                                Err(err) => {
                                    error!("Writing headers failed: {}", err);
                                    return;  // Presumably bad connection, so give up.
                                },
                                Ok(_) => (),
                            }
                        },
                    }
                    // Ensure the request is flushed, any Transfer-Encoding completed, etc.
                    match response.finish_response() {
                        Err(err) => {
                            error!("finishing response failed: {}", err);
                            return;  // Presumably bad connection, so give up.
                        },
                        Ok(_) => (),
                    }
                    let time_finished = precise_time_ns();
                    child_perf_sender.send((time_start, time_spawned, time_request_made, time_response_made, time_finished));

                    if close_connection {
                        break;
                    }
                    first = false;
                }
            });
        }
    }
}

/// The necessary configuration for an HTTP server.
///
/// At present, only the IP address and port to bind to are needed, but it's possible that other
/// options may turn up later.
pub struct Config {
	pub bind_address: SocketAddr,
}

static PERF_DUMP_FREQUENCY : u64 = 10_000;

/// Simple function to dump out perf stats every `PERF_DUMP_FREQUENCY` requests
fn perf_dumper(perf_receiver: Receiver<(u64, u64, u64, u64, u64)>) {
    // Total durations
    let mut td_spawn = 0u64;
    let mut td_request = 0u64;
    let mut td_response = 0u64;
    let mut td_handle = 0u64;
    let mut td_total = 0u64;
    let mut i = 0u64;
    loop {
        let data = perf_receiver.recv();
        let (start, spawned, request_made, response_made, finished) = data;
        td_spawn += spawned - start;
        td_request += request_made - spawned;
        td_response += response_made - request_made;
        td_handle += finished - response_made;
        td_total += finished - start;
        i += 1;
        if i % PERF_DUMP_FREQUENCY == 0 {
            println!("");
            println!("{} requests made thus far. Current means:", i);
            println!("- Total:               100%, {:12f}",
                     td_total as f64 / i as f64);
            println!("- Spawn:               {:3f}%, {:12f}",
                     100f64 * td_spawn as f64 / td_total as f64,
                     td_spawn as f64 / i as f64);
            println!("- Load request:        {:3f}%, {:12f}",
                     100f64 * td_request as f64 / td_total as f64,
                     td_request as f64 / i as f64);
            println!("- Initialise response: {:3f}%, {:12f}",
                     100f64 * td_response as f64 / td_total as f64,
                     td_response as f64 / i as f64);
            println!("- Handle:              {:3f}%, {:12f}",
                     100f64 * td_handle as f64 / td_total as f64,
                     td_handle as f64 / i as f64);
        }
    }
}
<commit_msg>(fix) ResponseWriter dereference.<commit_after>use std::io::{Listener, Acceptor};
use std::io::net::ip::SocketAddr;
use time::precise_time_ns;

use std::io::net::tcp::TcpListener;

use buffer::BufferedStream;

pub use self::request::{RequestBuffer, Request};
pub use self::response::ResponseWriter;

pub mod request;
pub mod response;

pub trait Server: Send + Clone {
	fn handle_request(&self, request: Request, response: &mut ResponseWriter) -> ();

	// XXX: this could also be implemented on the serve methods
	fn get_config(&self) -> Config;

	/**
	 * Attempt to bind to the address and port and start serving forever.
	 *
	 * This will only return if the initial connection fails or something else blows up.
	 */
    fn serve_forever(self) {
        let config = self.get_config();
        debug!("About to bind to {}", config.bind_address);
        let mut acceptor = match TcpListener::bind(config.bind_address.ip.to_str().as_slice(), config.bind_address.port).listen() {
            Err(err) => {
                error!("bind or listen failed :-(: {}", err);
                return;
            },
            Ok(acceptor) => acceptor,
        };
        debug!("listening");
        let (perf_sender, perf_receiver) = channel();
        spawn(proc() {
            perf_dumper(perf_receiver);
        });
        loop {
            let time_start = precise_time_ns();
            let stream = match acceptor.accept() {
                Err(error) => {
                    debug!("accept failed: {}", error);
                    // Question: is this the correct thing to do? We should probably be more
                    // intelligent, for there are some accept failures that are likely to be
                    // permanent, such that continuing would be a very bad idea, such as
                    // ENOBUFS/ENOMEM; and some where it should just be ignored, e.g.
                    // ECONNABORTED. TODO.
                    continue;
                },
                Ok(socket) => socket,
            };
            let child_perf_sender = perf_sender.clone();
            let child_self = self.clone();
            spawn(proc() {
                let mut time_start = time_start;
                let mut stream = BufferedStream::new(stream);
                debug!("accepted connection");
                let mut first = true;
                loop {  // A keep-alive loop, condition at end
                    let mut time_spawned = precise_time_ns();
                    let (request, err_status) = Request::load(&mut stream);
                    let close_connection = request.close_connection;
                    let time_request_made = precise_time_ns();
                    if !first {
                        // Subsequent requests on this connection have no spawn time.
                        // Moreover we cannot detect the time spent parsing the request as we have
                        // not exposed the time when the first byte was received.
                        time_start = time_request_made;
                        time_spawned = time_request_made;
                    }
                    let mut response = box ResponseWriter::new(&mut stream);
                    let time_response_made = precise_time_ns();
                    match err_status {
                        Ok(()) => {
                            child_self.handle_request(request, &mut *response);
                            // Ensure that we actually do send a response:
                            match response.try_write_headers() {
                                Err(err) => {
                                    error!("Writing headers failed: {}", err);
                                    return;  // Presumably bad connection, so give up.
                                },
                                Ok(_) => (),
                            }
                        },
                        Err(status) => {
                            // Uh oh, it's a response that I as a server cannot cope with.
                            // No good user-agent should have caused this, so for the moment
                            // at least I am content to send no body in the response.
                            response.status = status;
                            response.headers.content_length = Some(0);
                            match response.write_headers() {
                                Err(err) => {
                                    error!("Writing headers failed: {}", err);
                                    return;  // Presumably bad connection, so give up.
                                },
                                Ok(_) => (),
                            }
                        },
                    }
                    // Ensure the request is flushed, any Transfer-Encoding completed, etc.
                    match response.finish_response() {
                        Err(err) => {
                            error!("finishing response failed: {}", err);
                            return;  // Presumably bad connection, so give up.
                        },
                        Ok(_) => (),
                    }
                    let time_finished = precise_time_ns();
                    child_perf_sender.send((time_start, time_spawned, time_request_made, time_response_made, time_finished));

                    if close_connection {
                        break;
                    }
                    first = false;
                }
            });
        }
    }
}

/// The necessary configuration for an HTTP server.
///
/// At present, only the IP address and port to bind to are needed, but it's possible that other
/// options may turn up later.
pub struct Config {
	pub bind_address: SocketAddr,
}

static PERF_DUMP_FREQUENCY : u64 = 10_000;

/// Simple function to dump out perf stats every `PERF_DUMP_FREQUENCY` requests
fn perf_dumper(perf_receiver: Receiver<(u64, u64, u64, u64, u64)>) {
    // Total durations
    let mut td_spawn = 0u64;
    let mut td_request = 0u64;
    let mut td_response = 0u64;
    let mut td_handle = 0u64;
    let mut td_total = 0u64;
    let mut i = 0u64;
    loop {
        let data = perf_receiver.recv();
        let (start, spawned, request_made, response_made, finished) = data;
        td_spawn += spawned - start;
        td_request += request_made - spawned;
        td_response += response_made - request_made;
        td_handle += finished - response_made;
        td_total += finished - start;
        i += 1;
        if i % PERF_DUMP_FREQUENCY == 0 {
            println!("");
            println!("{} requests made thus far. Current means:", i);
            println!("- Total:               100%, {:12f}",
                     td_total as f64 / i as f64);
            println!("- Spawn:               {:3f}%, {:12f}",
                     100f64 * td_spawn as f64 / td_total as f64,
                     td_spawn as f64 / i as f64);
            println!("- Load request:        {:3f}%, {:12f}",
                     100f64 * td_request as f64 / td_total as f64,
                     td_request as f64 / i as f64);
            println!("- Initialise response: {:3f}%, {:12f}",
                     100f64 * td_response as f64 / td_total as f64,
                     td_response as f64 / i as f64);
            println!("- Handle:              {:3f}%, {:12f}",
                     100f64 * td_handle as f64 / td_total as f64,
                     td_handle as f64 / i as f64);
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
    let z = ();
    log(error, z[0]); //! ERROR cannot index a value of type `()`
}
<commit_msg>Fix a test I messed up.<commit_after>// error-pattern:cannot index a value of type `()`
fn main() {
    let z = ();
    log(error, z[0]);
}
<|endoftext|>