<commit_before>use std::ffi::CString;
use std::convert::Into;
use std::mem;

use libc::c_uint;

use rustc::lib::llvm;
use rustc::lib::llvm::{ ContextRef
                      , ModuleRef
                      , ValueRef
                      , BuilderRef
                      , TypeRef
                  };
use seax::compiler_tools::ForkTable;

use position::Positional;
use ast::{Form, DefForm};
use semantic::types::{Type, Reference, Primitive};

pub type IRResult = Result<ValueRef, Positional<String>>;
pub type SymbolTable<'a> = ForkTable<'a, &'a str, ValueRef>;

#[inline] fn word_size() -> c_uint { mem::size_of::<isize>() as c_uint }

/// Trait for that which may join in The Great Work
pub trait Compile {
    fn to_ir(&self, context: LLVMContext) -> IRResult;
}

pub trait TranslateType {
    fn translate_type(&self, context: LLVMContext) -> TypeRef;
}

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext<'a> { pub llctx: ContextRef
                           , pub llmod: ModuleRef
                           , pub llbuilder: BuilderRef
                           , pub names: SymbolTable<'a>
                           }

// because we are in the Raw Pointer Sadness Zone (read: unsafe),
// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            panic!("assertion failed: {} returned null!", stringify!($target));
        } else { e }
    })
}

impl<'a> LLVMContext<'a> {

    pub fn new(module_name: &str) -> Self {
        let name = CString::new(module_name).unwrap();
        unsafe {
            let ctx = not_null!(llvm::LLVMContextCreate());
            LLVMContext {
                llctx: ctx
              , llmod: not_null!(llvm::LLVMModuleCreateWithNameInContext(name.into_raw(), ctx))
              , llbuilder: not_null!(llvm::LLVMCreateBuilderInContext(ctx))
              , names: SymbolTable::new()
            }
        }
    }

    /// Dump the module's contents to stderr for debugging
    ///
    /// Apparently this is the only reasonable way to get a textual
    /// representation of a `ModuleRef` in `librustc_llvm`...
    pub fn dump(&self) {
        unsafe { llvm::LLVMDumpModule(self.llmod); }
    }
}

impl<'a> Drop for LLVMContext<'a> {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeModule(self.llmod);
            llvm::LLVMDisposeBuilder(self.llbuilder);
            llvm::LLVMContextDispose(self.llctx);
        }
    }
}

impl Compile for Form {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match self {
            &Form::Define(ref form) => form.to_ir(context)
        }
    }
}

impl Compile for DefForm {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match *self {
            DefForm::TopLevel { ref name, ref value, .. } =>
                unimplemented!(),
            DefForm::Function { ref name, ref body, .. } =>
                unsafe {
                    let name_ptr // function name as C string pointer
                        = CString::new((&name.value).clone()).unwrap().as_ptr();
                    let prev_decl // check LLVM module for previous declaration
                        = llvm::LLVMGetNamedFunction(context.llmod, name_ptr);

                    if !prev_decl.is_null() { // a previous declaration exists
                        unimplemented!() // TODO: overloading rules happen here
                    } else { // new function declaration
                        unimplemented!()
                    }
                }
        }
    }
}

impl TranslateType for Type {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        match *self {
            Type::Ref(ref reference)  => reference.translate_type(context),
            Type::Prim(ref primitive) => primitive.translate_type(context),
            _ => unimplemented!() // TODO: figure this out
        }
    }
}

impl TranslateType for Reference {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        unimplemented!() // TODO: figure this out
    }
}

impl TranslateType for Primitive {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        unsafe {
            match *self {
                Primitive::Int => // Integers are machine word size
                    llvm::LLVMIntTypeInContext(context.llctx, word_size()),
                Primitive::Float => // Floats are single precision
                    llvm::LLVMFloatTypeInContext(context.llctx),
                Primitive::Double => // Doubles are obvious precision
                    llvm::LLVMDoubleTypeInContext(context.llctx),
                Primitive::Byte => // Bytes are 8 bits (duh)
                    llvm::LLVMInt8TypeInContext(context.llctx),
                _ => unimplemented!() // TODO: figure this out
            }
        }
    }
}
<commit_msg>Additional null safety<commit_after>use std::ffi::CString;
use std::convert::Into;
use std::mem;

use libc::c_uint;

use rustc::lib::llvm;
use rustc::lib::llvm::{ ContextRef
                      , ModuleRef
                      , ValueRef
                      , BuilderRef
                      , TypeRef
                  };
use seax::compiler_tools::ForkTable;

use position::Positional;
use ast::{Form, DefForm};
use semantic::types::{ Type
                     , Reference
                     , Primitive
                     , Annotated
                     };

pub type IRResult = Result<ValueRef, Positional<String>>;
pub type SymbolTable<'a> = ForkTable<'a, &'a str, ValueRef>;

#[inline] fn word_size() -> c_uint { mem::size_of::<isize>() as c_uint }

/// Trait for that which may join in The Great Work
pub trait Compile {
    fn to_ir(&self, context: LLVMContext) -> IRResult;
}

pub trait TranslateType {
    fn translate_type(&self, context: LLVMContext) -> TypeRef;
}

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext<'a> { pub llctx: ContextRef
                           , pub llmod: ModuleRef
                           , pub llbuilder: BuilderRef
                           , pub names: SymbolTable<'a>
                           }

// because we are in the Raw Pointer Sadness Zone (read: unsafe),
// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            panic!("assertion failed: {} returned null!", stringify!($target));
        } else { e }
    })
}

impl<'a> LLVMContext<'a> {

    pub fn new(module_name: &str) -> Self {
        let name = CString::new(module_name).unwrap();
        unsafe {
            let ctx = not_null!(llvm::LLVMContextCreate());
            LLVMContext {
                llctx: ctx
              , llmod: not_null!(llvm::LLVMModuleCreateWithNameInContext(name.into_raw(), ctx))
              , llbuilder: not_null!(llvm::LLVMCreateBuilderInContext(ctx))
              , names: SymbolTable::new()
            }
        }
    }

    /// Dump the module's contents to stderr for debugging
    ///
    /// Apparently this is the only reasonable way to get a textual
    /// representation of a `ModuleRef` in `librustc_llvm`...
    pub fn dump(&self) {
        unsafe { llvm::LLVMDumpModule(self.llmod); }
    }
}

impl<'a> Drop for LLVMContext<'a> {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeModule(self.llmod);
            llvm::LLVMDisposeBuilder(self.llbuilder);
            llvm::LLVMContextDispose(self.llctx);
        }
    }
}

impl Compile for Form {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match self {
            &Form::Define(ref form) => form.to_ir(context)
        }
    }
}

impl Compile for DefForm {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match *self {
            DefForm::TopLevel { ref name, ref value, .. } =>
                unimplemented!(),
            DefForm::Function { ref name, ref body, .. } =>
                unsafe {
                    let name_ptr // function name as C string pointer
                        = CString::new((&name.value).clone()).unwrap().as_ptr();
                    let prev_decl // check LLVM module for previous declaration
                        = llvm::LLVMGetNamedFunction(context.llmod, name_ptr);

                    if !prev_decl.is_null() { // a previous declaration exists
                        unimplemented!() // TODO: overloading rules happen here
                    } else { // new function declaration
                        unimplemented!()
                    }
                }
        }
    }
}

impl TranslateType for Type {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        match *self {
            Type::Ref(ref reference)  => reference.translate_type(context),
            Type::Prim(ref primitive) => primitive.translate_type(context),
            _ => unimplemented!() // TODO: figure this out
        }
    }
}

impl TranslateType for Reference {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        unimplemented!() // TODO: figure this out
    }
}

impl TranslateType for Primitive {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        unsafe {
            not_null!(match *self {
                Primitive::Int => // Integers are machine word size
                    llvm::LLVMIntTypeInContext(context.llctx, word_size()),
                Primitive::Float => // Floats are single precision
                    llvm::LLVMFloatTypeInContext(context.llctx),
                Primitive::Double => // Doubles are obvious precision
                    llvm::LLVMDoubleTypeInContext(context.llctx),
                Primitive::Byte => // Bytes are 8 bits (duh)
                    llvm::LLVMInt8TypeInContext(context.llctx),
                _ => unimplemented!() // TODO: figure this out
            })
        }
    }
}
<|endoftext|>


<commit_before>use std::io;

use hyper::Uri;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};

pub async fn connect<T: AsyncRead + AsyncWrite + Unpin>(
    mut connection: T,
    connect_url: &str,
) -> io::Result<T> {
    let uri = connect_url.parse::<Uri>().unwrap();
    let mut buffer = format!(
        "CONNECT {0}:{1} HTTP/1.1\r\n\
         \r\n",
        uri.host().unwrap_or_else(|| panic!("No host in {}", uri)),
        uri.port().unwrap_or_else(|| panic!("No port in {}", uri))
    )
    .into_bytes();
    connection.write_all(buffer.as_ref()).await?;

    buffer.clear();
    connection.read_to_end(&mut buffer).await?;
    if buffer.is_empty() {
        return Err(io::Error::new(io::ErrorKind::Other, "Early EOF from proxy"));
    }

    let mut headers = [httparse::EMPTY_HEADER; 16];
    let mut response = httparse::Response::new(&mut headers);

    response
        .parse(&buffer[..])
        .map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?;

    match response.code {
        Some(200) => Ok(connection), // Proxy says all is well
        Some(code) => {
            let reason = response.reason.unwrap_or("no reason");
            let msg = format!("Proxy responded with {}: {}", code, reason);
            Err(io::Error::new(io::ErrorKind::Other, msg))
        }
        None => Err(io::Error::new(
            io::ErrorKind::Other,
            "Malformed response from proxy",
        )),
    }
}
<commit_msg>Fixed ProxyTunnel<commit_after>use std::io;

use hyper::Uri;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};

pub async fn connect<T: AsyncRead + AsyncWrite + Unpin>(
    mut connection: T,
    connect_url: &str,
) -> io::Result<T> {
    let uri = connect_url.parse::<Uri>().unwrap();
    let mut buffer = format!(
        "CONNECT {0}:{1} HTTP/1.1\r\n\
         \r\n",
        uri.host().unwrap_or_else(|| panic!("No host in {}", uri)),
        uri.port().unwrap_or_else(|| panic!("No port in {}", uri))
    )
    .into_bytes();
    connection.write_all(buffer.as_ref()).await?;

    buffer.resize(buffer.capacity(), 0);

    let mut offset = 0;
    loop {
        let bytes_read = connection.read(&mut buffer[offset..]).await?;
        if bytes_read == 0 {
            return Err(io::Error::new(io::ErrorKind::Other, "Early EOF from proxy"));
        }
        offset += bytes_read;

        let mut headers = [httparse::EMPTY_HEADER; 16];
        let mut response = httparse::Response::new(&mut headers);

        let status = response
            .parse(&buffer[..offset])
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;

        if status.is_complete() {
            return match response.code {
                Some(200) => Ok(connection), // Proxy says all is well
                Some(code) => {
                    let reason = response.reason.unwrap_or("no reason");
                    let msg = format!("Proxy responded with {}: {}", code, reason);
                    Err(io::Error::new(io::ErrorKind::Other, msg))
                }
                None => Err(io::Error::new(
                    io::ErrorKind::Other,
                    "Malformed response from proxy",
                )),
            };
        }

        if offset >= buffer.len() {
            buffer.resize(buffer.len() * 2, 0);
        }
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;

use backend::Backend;
use platform::platform::Platform;
use provider::Provider;
use provider::file::FileProvider;
use provider::file::inline::posix::Posix;
use provider::file::shell::linux::Linux;

#[derive(Clone)]
pub struct Ubuntu {
    name: String,
    release: String,
}

fn detect_from_content(content: &str) -> Option<Box<Platform>> {
    let mut lines = content.lines();
    let line = lines.next().unwrap();
    if line.starts_with("DISTRIB_ID") {
        let id = line.split("=").nth(1).unwrap().trim();
        if id == "Ubuntu" {
            let line = lines.next().unwrap();
            let release = line.split("=").nth(1).unwrap();
            let u = Ubuntu {
                name: id.to_string(),
                release: release.to_string(),
            };

            return Some(Box::new(u));
        }
    }
    None
}

impl Platform for Ubuntu {
    fn new() -> Ubuntu {
        Ubuntu {
            name: "".to_string(),
            release: "".to_string(),
        }
    }

    fn inline_detector(&self) -> Option<Box<Platform>> {
        let mut file = File::open("/etc/lsb-release").unwrap();
        let mut contents = String::new();
        let _ = file.read_to_string(&mut contents);
        detect_from_content(&contents)
    }

    fn shell_detector(&self, b: &Backend) -> Option<Box<Platform>> {
        let contents = b.run_command("cat /etc/lsb-release").unwrap();
        detect_from_content(&contents)
    }

    fn get_provider(&self) -> Box<Provider> {
        let fp = FileProvider {
            inline: Box::new(Posix),
            shell: Box::new(Linux),
        };

        let p = Provider { file: Box::new(fp) };

        Box::new(p)
    }
}
<commit_msg>Correct the function name<commit_after>use std::fs::File;
use std::io::prelude::*;

use backend::Backend;
use platform::platform::Platform;
use provider::Provider;
use provider::file::FileProvider;
use provider::file::inline::posix::Posix;
use provider::file::shell::linux::Linux;

#[derive(Clone)]
pub struct Ubuntu {
    name: String,
    release: String,
}

fn detect_by_lsb_releae(content: &str) -> Option<Box<Platform>> {
    let mut lines = content.lines();
    let line = lines.next().unwrap();
    if line.starts_with("DISTRIB_ID") {
        let id = line.split("=").nth(1).unwrap().trim();
        if id == "Ubuntu" {
            let line = lines.next().unwrap();
            let release = line.split("=").nth(1).unwrap();
            let u = Ubuntu {
                name: id.to_string(),
                release: release.to_string(),
            };

            return Some(Box::new(u));
        }
    }
    None
}

impl Platform for Ubuntu {
    fn new() -> Ubuntu {
        Ubuntu {
            name: "".to_string(),
            release: "".to_string(),
        }
    }

    fn inline_detector(&self) -> Option<Box<Platform>> {
        let mut file = File::open("/etc/lsb-release").unwrap();
        let mut content = String::new();
        let _ = file.read_to_string(&mut content);
        detect_by_lsb_releae(&content)
    }

    fn shell_detector(&self, b: &Backend) -> Option<Box<Platform>> {
        let content = b.run_command("cat /etc/lsb-release").unwrap();
        detect_by_lsb_releae(&content)
    }

    fn get_provider(&self) -> Box<Provider> {
        let fp = FileProvider {
            inline: Box::new(Posix),
            shell: Box::new(Linux),
        };

        let p = Provider { file: Box::new(fp) };

        Box::new(p)
    }
}
<|endoftext|>


<commit_before>/*
 * The region checking pass. Ensures that region-annotated pointers never
 * outlive their referents.
 */

import driver::session::session;
import middle::ty;
import std::map::hashmap;
import syntax::{ast, visit};

// An "extended region", which includes the ordinarily-unnamed reference-
// counted heap and exchange heap regions. This is used to detect borrowing.
enum region_ext {
    re_rc,
    re_exheap,
    re_region(ty::region)
}

type ctxt = {
    tcx: ty::ctxt,
    enclosing_block: option<ast::node_id>
};

fn check_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
    ty::walk_ty(cx.tcx, ty::expr_ty(cx.tcx, expr)) { |t|
        alt ty::get(t).struct {
            ty::ty_rptr(region, _) {
                alt region {
                    ty::re_named(_) | ty::re_caller(_) { /* ok */ }
                    ty::re_block(rbi) {
                        let referent_block_id = rbi;
                        let enclosing_block_id = alt cx.enclosing_block {
                            none {
                                cx.tcx.sess.span_bug(expr.span, "block " +
                                                     "region type outside " +
                                                     "a block?!");
                            }
                            some(eb) { eb }
                        };

                        let parent_blocks = cx.tcx.region_map.parent_blocks;
                        while enclosing_block_id != referent_block_id {
                            if parent_blocks.contains_key(referent_block_id) {
                                referent_block_id =
                                    parent_blocks.get(referent_block_id);
                            } else {
                                // TODO: Enable this.

                                //cx.tcx.sess.span_err(expr.span,
                                //                     "reference escapes " +
                                //                     "its block");
                                break;
                            }
                        }
                    }
                }
            }
            _ { /* no-op */ }
        }
    }

    visit::visit_expr(expr, cx, visitor);
}

fn check_block(blk: ast::blk, cx: ctxt, visitor: visit::vt<ctxt>) {
    let new_cx: ctxt = { enclosing_block: some(blk.node.id) with cx };
    visit::visit_block(blk, new_cx, visitor);
}

fn check_crate(ty_cx: ty::ctxt, crate: @ast::crate) {
    let cx: ctxt = {tcx: ty_cx, enclosing_block: none};
    let visitor = visit::mk_vt(@{
        visit_expr: check_expr,
        visit_block: check_block
        with *visit::default_visitor()
    });
    visit::visit_crate(*crate, cx, visitor);
}

<commit_msg>rustc: Turn on errors for region checking<commit_after>/*
 * The region checking pass. Ensures that region-annotated pointers never
 * outlive their referents.
 */

import driver::session::session;
import middle::ty;
import std::map::hashmap;
import syntax::{ast, visit};

// An "extended region", which includes the ordinarily-unnamed reference-
// counted heap and exchange heap regions. This is used to detect borrowing.
enum region_ext {
    re_rc,
    re_exheap,
    re_region(ty::region)
}

type ctxt = {
    tcx: ty::ctxt,
    enclosing_block: option<ast::node_id>
};

fn check_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
    ty::walk_ty(cx.tcx, ty::expr_ty(cx.tcx, expr)) { |t|
        alt ty::get(t).struct {
            ty::ty_rptr(region, _) {
                alt region {
                    ty::re_named(_) | ty::re_caller(_) { /* ok */ }
                    ty::re_block(rbi) {
                        let referent_block_id = rbi;
                        let enclosing_block_id = alt cx.enclosing_block {
                            none {
                                cx.tcx.sess.span_bug(expr.span, "block " +
                                                     "region type outside " +
                                                     "a block?!");
                            }
                            some(eb) { eb }
                        };

                        let parent_blocks = cx.tcx.region_map.parent_blocks;
                        while enclosing_block_id != referent_block_id {
                            if parent_blocks.contains_key(referent_block_id) {
                                referent_block_id =
                                    parent_blocks.get(referent_block_id);
                            } else {
                                cx.tcx.sess.span_err(expr.span,
                                                     "reference escapes " +
                                                     "its block");
                                break;
                            }
                        }
                    }
                }
            }
            _ { /* no-op */ }
        }
    }

    visit::visit_expr(expr, cx, visitor);
}

fn check_block(blk: ast::blk, cx: ctxt, visitor: visit::vt<ctxt>) {
    let new_cx: ctxt = { enclosing_block: some(blk.node.id) with cx };
    visit::visit_block(blk, new_cx, visitor);
}

fn check_crate(ty_cx: ty::ctxt, crate: @ast::crate) {
    let cx: ctxt = {tcx: ty_cx, enclosing_block: none};
    let visitor = visit::mk_vt(@{
        visit_expr: check_expr,
        visit_block: check_block
        with *visit::default_visitor()
    });
    visit::visit_crate(*crate, cx, visitor);
}

<|endoftext|>


<commit_before>use super::*;

// TODO
// Merged
// LeftMerge(head: Raw, rhs: PageId, hi: Bound)
// ParentMerge(lhs: PageId, rhs: PageId)
// TxBegin(TxID), // in-mem
// TxCommit(TxID), // in-mem
// TxAbort(TxID), // in-mem

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) enum Frag {
    Set(IVec, IVec),
    Del(IVec),
    Merge(IVec, IVec),
    Base(Node),
    ChildSplit(ChildSplit),
    ParentSplit(ParentSplit),
    Counter(usize),
    Meta(Meta),
}

impl Frag {
    pub(super) fn unwrap_base(&self) -> &Node {
        if let Frag::Base(base, ..) = self {
            base
        } else {
            panic!("called unwrap_base_ptr on non-Base Frag!")
        }
    }

    pub(super) fn unwrap_meta(&self) -> &Meta {
        if let Frag::Meta(meta) = self {
            meta
        } else {
            panic!("called unwrap_base_ptr on non-Base Frag!")
        }
    }
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct ParentSplit {
    pub(crate) at: IVec,
    pub(crate) to: PageId,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct ChildSplit {
    pub(crate) at: IVec,
    pub(crate) to: PageId,
}
<commit_msg>Add set_key method to Frag<commit_after>use super::*;

// TODO
// Merged
// LeftMerge(head: Raw, rhs: PageId, hi: Bound)
// ParentMerge(lhs: PageId, rhs: PageId)
// TxBegin(TxID), // in-mem
// TxCommit(TxID), // in-mem
// TxAbort(TxID), // in-mem

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) enum Frag {
    Set(IVec, IVec),
    Del(IVec),
    Merge(IVec, IVec),
    Base(Node),
    ChildSplit(ChildSplit),
    ParentSplit(ParentSplit),
    Counter(usize),
    Meta(Meta),
}

impl Frag {
    pub(super) fn unwrap_base(&self) -> &Node {
        if let Frag::Base(base, ..) = self {
            base
        } else {
            panic!("called unwrap_base_ptr on non-Base Frag!")
        }
    }

    pub(super) fn unwrap_meta(&self) -> &Meta {
        if let Frag::Meta(meta) = self {
            meta
        } else {
            panic!("called unwrap_base_ptr on non-Base Frag!")
        }
    }

    pub(super) fn set_key(&mut self, key: IVec) {
        match self {
            Frag::Set(_, v) => *self = Frag::Set(key, v.take()),
            Frag::Del(_) => *self = Frag::Del(key),
            Frag::Merge(_, v) => *self = Frag::Merge(key, v.take()),
            other => panic!("set_key called on {:?}", other),
        }
    }
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct ParentSplit {
    pub(crate) at: IVec,
    pub(crate) to: PageId,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct ChildSplit {
    pub(crate) at: IVec,
    pub(crate) to: PageId,
}
<|endoftext|>


<commit_before>extern crate libc;

#[macro_use]
extern crate apache2;

use libc::{c_void, c_char};
use apache2::{Request, Status, ffi};

pub const X: u32 = ffi::NONFATAL_OVERRIDE | ffi::NONFATAL_UNKNOWN;

#[allow(unused_variables)]
pub extern "C" fn cmd(parms: *mut ffi::cmd_parms, mconfig: *mut c_void, w: *const c_char) -> *const c_char {
   std::ptr::null()
}

const SOME_CMD: ffi::command_rec = ffi::command_rec {
   name: b"SomeCmd\0" as *const u8 as *const c_char,
   func: ffi::cmd_func {
      _bindgen_data_: [cmd as u64]
   },
   cmd_data: 0 as *mut c_void,
   req_override: 0,
   args_how: 0,
   errmsg: b"Error message\0" as *const u8 as *const c_char
};

const EXAMPLE_DIRECTIVES: [*const ffi::command_rec; 2] = [
   &SOME_CMD,
   0 as *const ffi::command_rec
];

AP_DECLARE_MODULE!(
   conf_module,
   b"mod_conf\0",
   None,
   None,
   None,
   None,
   EXAMPLE_DIRECTIVES[0],
   Some(c_module_hooks)
);

extern "C" fn c_module_hooks(_: *mut apache2::ffi::apr_pool_t) {
   unsafe {
      apache2::ffi::ap_hook_handler(
         Some(c_conf_handler),
         std::ptr::null(),
         std::ptr::null(),
         apache2::HookOrder::MIDDLE.into()
      );
   }
}

#[no_mangle]
pub extern "C" fn c_conf_handler(r: *mut apache2::ffi::request_rec) -> apache2::c_int {
   match apache2::httpd::Request::from_raw_ptr(r) {
      Err(_) => apache2::httpd::Status::DECLINED.into(),
      Ok(mut request) => match conf_handler(&mut request) {
         Ok(status) => status,
         Err(_) => apache2::httpd::Status::HTTP_INTERNAL_SERVER_ERROR
      }.into()
   }
}

fn conf_handler(r: &mut Request) -> Result<Status, ()> {
   r.set_content_type("text/plain; charset=utf-8");

   try!(r.write("CONF: *****"));

   Ok(Status::OK)
}
<commit_msg>Filling in the experimental command_rec in the conf module.<commit_after>extern crate libc;

#[macro_use]
extern crate apache2;

use libc::{c_void, c_char};
use apache2::{Request, Status, ffi};

#[allow(unused_variables)]
pub extern "C" fn cmd(parms: *mut ffi::cmd_parms, mconfig: *mut c_void, w: *const c_char) -> *const c_char {
   std::ptr::null()
}

const SOME_CMD: ffi::command_rec = ffi::command_rec {
   name: b"SomeCmd\0" as *const u8 as *const c_char,
   func: ffi::cmd_func {
      _bindgen_data_: [cmd as u64]
   },
   cmd_data: 0 as *mut c_void,
   req_override: apache2::ffi::RSRC_CONF,
   args_how: apache2::ffi::TAKE1,
   errmsg: b"Error message\0" as *const u8 as *const c_char
};

const EXAMPLE_DIRECTIVES: [*const ffi::command_rec; 2] = [
   &SOME_CMD,
   0 as *const ffi::command_rec
];

AP_DECLARE_MODULE!(
   conf_module,
   b"mod_conf\0",
   None,
   None,
   None,
   None,
   EXAMPLE_DIRECTIVES[0],
   Some(c_module_hooks)
);

extern "C" fn c_module_hooks(_: *mut apache2::ffi::apr_pool_t) {
   unsafe {
      apache2::ffi::ap_hook_handler(
         Some(c_conf_handler),
         std::ptr::null(),
         std::ptr::null(),
         apache2::HookOrder::MIDDLE.into()
      );
   }
}

#[no_mangle]
pub extern "C" fn c_conf_handler(r: *mut apache2::ffi::request_rec) -> apache2::c_int {
   match apache2::httpd::Request::from_raw_ptr(r) {
      Err(_) => apache2::httpd::Status::DECLINED.into(),
      Ok(mut request) => match conf_handler(&mut request) {
         Ok(status) => status,
         Err(_) => apache2::httpd::Status::HTTP_INTERNAL_SERVER_ERROR
      }.into()
   }
}

fn conf_handler(r: &mut Request) -> Result<Status, ()> {
   r.set_content_type("text/plain; charset=utf-8");

   try!(r.write("CONF: *****"));

   Ok(Status::OK)
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate timely;
extern crate differential_dataflow;

use std::time::Instant;
use std::mem;
use std::hash::Hash;

use timely::dataflow::*;

use differential_dataflow::lattice::Lattice;
use differential_dataflow::input::Input;
use differential_dataflow::Collection;
use differential_dataflow::operators::*;
use differential_dataflow::operators::arrange::ArrangeByKey;

use differential_dataflow::trace::implementations::ord::OrdValSpine as DefaultValTrace;
use differential_dataflow::operators::arrange::TraceAgent;
use differential_dataflow::operators::arrange::Arranged;

type Arrange<G, K, V, R> = Arranged<G, K, V, R, TraceAgent<K, V, <G as ScopeParent>::Timestamp, R, DefaultValTrace<K, V, <G as ScopeParent>::Timestamp, R>>>;

type Node = u32;
type Edge = (Node, Node);

fn main() {

    // snag a filename to use for the input graph.
    let filename = std::env::args().nth(1).unwrap();
    let program = std::env::args().nth(2).unwrap();
    let inspect = std::env::args().any(|x| x == "inspect");

    timely::execute_from_args(std::env::args().skip(1), move |worker| {

        let peers = worker.peers();
        let index = worker.index();

        let mut input = worker.dataflow::<(),_,_>(|scope| {

            let (input, graph) = scope.new_collection();

            // each edge should exist in both directions.
            let graph = graph.arrange_by_key();

            match program.as_str() {
                "tc"    => tc(&graph).filter(move |_| inspect).map(|_| ()).consolidate().inspect(|x| println!("tc count: {:?}", x)).probe(),
                "sc"    => _strongly_connected(&graph.as_collection(|k,v| (*k,*v))).filter(move |_| inspect).map(|_| ()).consolidate().inspect(|x| println!("tc count: {:?}", x)).probe(),
                "sg"    => sg(&graph).filter(move |_| inspect).map(|_| ()).consolidate().inspect(|x| println!("sg count: {:?}", x)).probe(),
                _       => panic!("must specify one of 'tc', 'sg'.")
            };

            input
        });

        let timer = Instant::now();

        let mut nodes = 0;

        use std::io::{BufReader, BufRead};
        use std::fs::File;

        let file = BufReader::new(File::open(filename.clone()).unwrap());
        for (count, readline) in file.lines().enumerate() {
            let line = readline.ok().expect("read error");
            if count % peers == index && !line.starts_with('#') {
                let mut elts = line[..].split_whitespace();
                let src: u32 = elts.next().unwrap().parse().ok().expect("malformed src");
                let dst: u32 = elts.next().unwrap().parse().ok().expect("malformed dst");
                if nodes < src { nodes = src; }
                if nodes < dst { nodes = dst; }
                input.insert((src, dst));
            }
        }

        if index == 0 { println!("{:?}\tData ingested", timer.elapsed()); }

        input.close();
        while worker.step() { }

        if index == 0 { println!("{:?}\tComputation complete", timer.elapsed()); }

    }).unwrap();
}

use timely::progress::nested::product::Product;
use timely::progress::timestamp::RootTimestamp;

fn _trim_and_flip<G: Scope>(graph: &Collection<G, Edge>) -> Collection<G, Edge>
where G::Timestamp: Lattice+Ord+Hash {
    graph.iterate(|edges| {
        // keep edges from active edge destinations.
        let active = edges.map(|(src,_dst)| src)
                          .distinct();

        graph.enter(&edges.scope())
             .arrange_by_key()
             .semijoin(&active)
    })
    .map_in_place(|x| mem::swap(&mut x.0, &mut x.1))
}

fn _strongly_connected<G: Scope>(graph: &Collection<G, Edge>) -> Collection<G, Edge>
where G::Timestamp: Lattice+Ord+Hash {
    graph.iterate(|inner| {
        let edges = graph.enter(&inner.scope());
        let trans = edges.map_in_place(|x| mem::swap(&mut x.0, &mut x.1));
        _trim_edges(&_trim_edges(inner, &edges), &trans)
    })
}

fn _trim_edges<G: Scope>(cycle: &Collection<G, Edge>, edges: &Collection<G, Edge>)
    -> Collection<G, Edge> where G::Timestamp: Lattice+Ord+Hash {

    let nodes = edges.map_in_place(|x| x.0 = x.1)
                     .consolidate();

    let labels = _reachability(&cycle, &nodes);

    edges.join_map(&labels, |&e1,&e2,&l1| (e2,(e1,l1)))
         .join_map(&labels, |&e2,&(e1,l1),&l2| ((e1,e2),(l1,l2)))
         .filter(|&(_,(l1,l2))| l1 == l2)
         .map(|((x1,x2),_)| (x2,x1))
}

fn _reachability<G: Scope>(edges: &Collection<G, Edge>, nodes: &Collection<G, (Node, Node)>) -> Collection<G, Edge>
where G::Timestamp: Lattice+Ord+Hash {

    edges.filter(|_| false)
         .iterate(|inner| {
             let edges = edges.enter(&inner.scope());
             let nodes = nodes.enter_at(&inner.scope(), |r| 256 * (64 - (r.0 as u64).leading_zeros() as u64));

             inner.join_map(&edges, |_k,l,d| (*d,*l))
                  .concat(&nodes)
                  .group(|_, s, t| t.push((*s[0].0, 1)))

         })
}

// returns pairs (n, s) indicating node n can be reached from a root in s steps.
fn tc<G: Scope<Timestamp=Product<RootTimestamp, ()>>>(edges: &Arrange<G, Node, Node, isize>) -> Collection<G, (Node, Node)> {

    use timely::dataflow::operators::Inspect;
    use timely::dataflow::operators::Accumulate;

    // repeatedly update minimal distances each node can be reached from each root
    edges
        .as_collection(|&k,&v| (k,v))
        .iterate(|inner| {

            inner.inner.count().inspect_batch(|t,xs| println!("{:?}\t{:?}", t, xs));

            let edges = edges.enter(&inner.scope());

            inner
                .map(|(x,y)| (y,x))
                .join_core(&edges, |_y,&x,&z| Some((x, z)))
                .concat(&edges.as_collection(|&k,&v| (k,v)))
                .distinct_total()
        }
    )
}

// returns pairs (n, s) indicating node n can be reached from a root in s steps.
fn sg<G: Scope<Timestamp=Product<RootTimestamp, ()>>>(edges: &Arrange<G, Node, Node, isize>) -> Collection<G, (Node, Node)> {

    let peers = edges.join_core(&edges, |_,&x,&y| Some((x,y))).filter(|&(x,y)| x != y);

    // repeatedly update minimal distances each node can be reached from each root
    peers
        .iterate(|inner| {

            let edges = edges.enter(&inner.scope());
            let peers = peers.enter(&inner.scope());

            inner
                .join_core(&edges, |_,&x,&z| Some((x, z)))
                .join_core(&edges, |_,&x,&z| Some((x, z)))
                .concat(&peers)
                .distinct_total()
        }
    )
}<commit_msg>flexible types<commit_after>extern crate rand;
extern crate timely;
extern crate differential_dataflow;

use std::time::Instant;
use std::mem;
use std::hash::Hash;

use timely::dataflow::*;

use differential_dataflow::lattice::Lattice;
use differential_dataflow::input::Input;
use differential_dataflow::Collection;
use differential_dataflow::operators::*;
use differential_dataflow::operators::arrange::ArrangeByKey;

use differential_dataflow::trace::implementations::ord::OrdValSpine as DefaultValTrace;
use differential_dataflow::operators::arrange::TraceAgent;
use differential_dataflow::operators::arrange::Arranged;
use differential_dataflow::operators::iterate::Variable;

type Arrange<G, K, V, R> = Arranged<G, K, V, R, TraceAgent<K, V, <G as ScopeParent>::Timestamp, R, DefaultValTrace<K, V, <G as ScopeParent>::Timestamp, R>>>;

type Node = u32;
type Edge = (Node, Node);
type Iter = u32;
type Diff = i32;

fn main() {

    // snag a filename to use for the input graph.
    let filename = std::env::args().nth(1).unwrap();
    let program = std::env::args().nth(2).unwrap();
    let inspect = std::env::args().any(|x| x == "inspect");

    timely::execute_from_args(std::env::args().skip(1), move |worker| {

        let peers = worker.peers();
        let index = worker.index();

        let mut input = worker.dataflow::<(),_,_>(|scope| {

            let (input, graph) = scope.new_collection();

            // each edge should exist in both directions.
            let graph = graph.arrange_by_key();

            match program.as_str() {
                "tc"    => tc(&graph).filter(move |_| inspect).map(|_| ()).consolidate().inspect(|x| println!("tc count: {:?}", x)).probe(),
                // "sc"    => _strongly_connected(&graph.as_collection(|k,v| (*k,*v))).filter(move |_| inspect).map(|_| ()).consolidate().inspect(|x| println!("tc count: {:?}", x)).probe(),
                "sg"    => sg(&graph).filter(move |_| inspect).map(|_| ()).consolidate().inspect(|x| println!("sg count: {:?}", x)).probe(),
                _       => panic!("must specify one of 'tc', 'sg'.")
            };

            input
        });

        let timer = Instant::now();

        let mut nodes = 0;

        use std::io::{BufReader, BufRead};
        use std::fs::File;

        let file = BufReader::new(File::open(filename.clone()).unwrap());
        for (count, readline) in file.lines().enumerate() {
            let line = readline.ok().expect("read error");
            if count % peers == index && !line.starts_with('#') {
                let mut elts = line[..].split_whitespace();
                let src: u32 = elts.next().unwrap().parse().ok().expect("malformed src");
                let dst: u32 = elts.next().unwrap().parse().ok().expect("malformed dst");
                if nodes < src { nodes = src; }
                if nodes < dst { nodes = dst; }
                input.update((src, dst), 1);
            }
        }

        if index == 0 { println!("{:?}\tData ingested", timer.elapsed()); }

        input.close();
        while worker.step() { }

        if index == 0 { println!("{:?}\tComputation complete", timer.elapsed()); }

    }).unwrap();
}

use timely::progress::nested::product::Product;
use timely::progress::timestamp::RootTimestamp;

fn _trim_and_flip<G: Scope>(graph: &Collection<G, Edge>) -> Collection<G, Edge>
where G::Timestamp: Lattice+Ord+Hash {
    graph.iterate(|edges| {
        // keep edges from active edge destinations.
        let active = edges.map(|(src,_dst)| src)
                          .distinct();

        graph.enter(&edges.scope())
             .arrange_by_key()
             .semijoin(&active)
    })
    .map_in_place(|x| mem::swap(&mut x.0, &mut x.1))
}

fn _strongly_connected<G: Scope>(graph: &Collection<G, Edge>) -> Collection<G, Edge>
where G::Timestamp: Lattice+Ord+Hash {
    graph.iterate(|inner| {
        let edges = graph.enter(&inner.scope());
        let trans = edges.map_in_place(|x| mem::swap(&mut x.0, &mut x.1));
        _trim_edges(&_trim_edges(inner, &edges), &trans)
    })
}

fn _trim_edges<G: Scope>(cycle: &Collection<G, Edge>, edges: &Collection<G, Edge>)
    -> Collection<G, Edge> where G::Timestamp: Lattice+Ord+Hash {

    let nodes = edges.map_in_place(|x| x.0 = x.1)
                     .consolidate();

    let labels = _reachability(&cycle, &nodes);

    edges.join_map(&labels, |&e1,&e2,&l1| (e2,(e1,l1)))
         .join_map(&labels, |&e2,&(e1,l1),&l2| ((e1,e2),(l1,l2)))
         .filter(|&(_,(l1,l2))| l1 == l2)
         .map(|((x1,x2),_)| (x2,x1))
}

fn _reachability<G: Scope>(edges: &Collection<G, Edge>, nodes: &Collection<G, (Node, Node)>) -> Collection<G, Edge>
where G::Timestamp: Lattice+Ord+Hash {

    edges.filter(|_| false)
         .iterate(|inner| {
             let edges = edges.enter(&inner.scope());
             let nodes = nodes.enter_at(&inner.scope(), |r| 256 * (64 - (r.0 as u64).leading_zeros() as u64));

             inner.join_map(&edges, |_k,l,d| (*d,*l))
                  .concat(&nodes)
                  .group(|_, s, t| t.push((*s[0].0, 1)))

         })
}

// returns pairs (n, s) indicating node n can be reached from a root in s steps.
fn tc<G: Scope<Timestamp=Product<RootTimestamp, ()>>>(edges: &Arrange<G, Node, Node, Diff>) -> Collection<G, Edge, Diff> {

    // repeatedly update minimal distances each node can be reached from each root
    edges.stream.scope().scoped(|scope| {

            let inner = Variable::new(scope, Iter::max_value(), 1);
            let edges = edges.enter(&inner.scope());

            let result =
            inner
                .map(|(x,y)| (y,x))
                .join_core(&edges, |_y,&x,&z| Some((x, z)))
                .concat(&edges.as_collection(|&k,&v| (k,v)))
                .threshold_total(|_| 1);

            inner.set(&result);
            result.leave()
        }
    )
}

// returns pairs (n, s) indicating node n can be reached from a root in s steps.
fn sg<G: Scope<Timestamp=Product<RootTimestamp, ()>>>(edges: &Arrange<G, Node, Node, Diff>) -> Collection<G, Edge, Diff> {

    let peers = edges.join_core(&edges, |_,&x,&y| Some((x,y))).filter(|&(x,y)| x != y);

    // repeatedly update minimal distances each node can be reached from each root
    peers.scope().scoped(|scope| {

            let inner = Variable::new(scope, Iter::max_value(), 1);
            let edges = edges.enter(&inner.scope());
            let peers = peers.enter(&inner.scope());

            let result =
            inner
                .join_core(&edges, |_,&x,&z| Some((x, z)))
                .join_core(&edges, |_,&x,&z| Some((x, z)))
                .concat(&peers)
                .threshold_total(|_| 1);

            inner.set(&result);
            result.leave()
        }
    )
}<|endoftext|>


<commit_before>use std::io;

use futures::stream::Stream;
use futures::{Future, Task, Poll};
use futures_io::{Ready, IoFuture};

use event_loop::{IoSource, LoopHandle};

/// A concrete implementation of a stream of readiness notifications for I/O
/// objects that originates from an event loop.
///
/// Created by the `ReadinessStream::new` method, each `ReadinessStream` is
/// associated with a specific event loop and source of events that will be
/// registered with an event loop.
///
/// Currently readiness streams have "edge" semantics. That is, if a stream
/// receives a readable notification it will not receive another readable
/// notification until all bytes have been read from the stream.
///
/// Note that the precise semantics of when notifications are received will
/// likely be configurable in the future.
pub struct ReadinessStream {
    io_token: usize,
    loop_handle: LoopHandle,
    source: IoSource,
}

impl ReadinessStream {
    /// Creates a new readiness stream associated with the provided
    /// `loop_handle` and for the given `source`.
    ///
    /// This method returns a future which will resolve to the readiness stream
    /// when it's ready.
    pub fn new(loop_handle: LoopHandle, source: IoSource)
               -> Box<IoFuture<ReadinessStream>> {
        loop_handle.add_source(source.clone()).map(|token| {
            ReadinessStream {
                io_token: token,
                source: source,
                loop_handle: loop_handle,
            }
        }).boxed()
    }
}

impl Stream for ReadinessStream {
    type Item = Ready;
    type Error = io::Error;

    fn poll(&mut self, _task: &mut Task) -> Poll<Option<Ready>, io::Error> {
        match self.source.take_readiness() {
            None => Poll::NotReady,
            Some(r) => Poll::Ok(Some(r)),
        }
    }

    fn schedule(&mut self, task: &mut Task) {
        self.loop_handle.schedule(self.io_token, task)
    }
}

impl Drop for ReadinessStream {
    fn drop(&mut self) {
        self.loop_handle.drop_source(self.io_token)
    }
}
<commit_msg>Remove extraneous allocation on ReadinessStream::new<commit_after>use std::io;

use futures::stream::Stream;
use futures::{Future, Task, Poll};
use futures_io::{Ready};

use event_loop::{IoSource, LoopHandle, AddSource};

/// A concrete implementation of a stream of readiness notifications for I/O
/// objects that originates from an event loop.
///
/// Created by the `ReadinessStream::new` method, each `ReadinessStream` is
/// associated with a specific event loop and source of events that will be
/// registered with an event loop.
///
/// Currently readiness streams have "edge" semantics. That is, if a stream
/// receives a readable notification it will not receive another readable
/// notification until all bytes have been read from the stream.
///
/// Note that the precise semantics of when notifications are received will
/// likely be configurable in the future.
pub struct ReadinessStream {
    io_token: usize,
    loop_handle: LoopHandle,
    source: IoSource,
}

pub struct ReadinessStreamNew {
    inner: AddSource,
    handle: Option<LoopHandle>,
    source: Option<IoSource>,
}

impl ReadinessStream {
    /// Creates a new readiness stream associated with the provided
    /// `loop_handle` and for the given `source`.
    ///
    /// This method returns a future which will resolve to the readiness stream
    /// when it's ready.
    pub fn new(loop_handle: LoopHandle, source: IoSource)
               -> ReadinessStreamNew {
        ReadinessStreamNew {
            inner: loop_handle.add_source(source.clone()),
            source: Some(source),
            handle: Some(loop_handle),
        }
    }
}

impl Future for ReadinessStreamNew {
    type Item = ReadinessStream;
    type Error = io::Error;

    fn poll(&mut self, task: &mut Task) -> Poll<ReadinessStream, io::Error> {
        self.inner.poll(task).map(|token| {
            ReadinessStream {
                io_token: token,
                source: self.source.take().unwrap(),
                loop_handle: self.handle.take().unwrap(),
            }
        })
    }

    fn schedule(&mut self, task: &mut Task) {
        self.inner.schedule(task)
    }
}

impl Stream for ReadinessStream {
    type Item = Ready;
    type Error = io::Error;

    fn poll(&mut self, _task: &mut Task) -> Poll<Option<Ready>, io::Error> {
        match self.source.take_readiness() {
            None => Poll::NotReady,
            Some(r) => Poll::Ok(Some(r)),
        }
    }

    fn schedule(&mut self, task: &mut Task) {
        self.loop_handle.schedule(self.io_token, task)
    }
}

impl Drop for ReadinessStream {
    fn drop(&mut self) {
        self.loop_handle.drop_source(self.io_token)
    }
}
<|endoftext|>


<commit_before>use crate::builders::{CrateBuilder, VersionBuilder};
use crate::util::{RequestHelper, TestApp};
use cargo_registry::views::EncodableVersionDownload;
use chrono::{Duration, Utc};
use http::StatusCode;

#[derive(Deserialize)]
struct Downloads {
    version_downloads: Vec<EncodableVersionDownload>,
}

#[test]
fn download() {
    let (app, anon, user) = TestApp::init().with_user();
    let user = user.as_model();

    app.db(|conn| {
        CrateBuilder::new("foo_download", user.id)
            .version(VersionBuilder::new("1.0.0"))
            .expect_build(conn);
    });

    let assert_dl_count = |name_and_version: &str, query: Option<&str>, count: i32| {
        let url = format!("/api/v1/crates/{}/downloads", name_and_version);
        let downloads: Downloads = if let Some(query) = query {
            anon.get_with_query(&url, query).good()
        } else {
            anon.get(&url).good()
        };
        let total_downloads = downloads
            .version_downloads
            .iter()
            .map(|vd| vd.downloads)
            .sum::<i32>();
        assert_eq!(total_downloads, count);
    };

    let download = |name_and_version: &str| {
        let url = format!("/api/v1/crates/{}/download", name_and_version);
        let response = anon.get::<()>(&url);
        assert_eq!(response.status(), StatusCode::FOUND);
        // TODO: test the with_json code path
    };

    download("foo_download/1.0.0");
    assert_dl_count("foo_download/1.0.0", None, 1);
    assert_dl_count("foo_download", None, 1);

    download("FOO_DOWNLOAD/1.0.0");
    assert_dl_count("FOO_DOWNLOAD/1.0.0", None, 2);
    assert_dl_count("FOO_DOWNLOAD", None, 2);

    let yesterday = (Utc::today() + Duration::days(-1)).format("%F");
    let query = format!("before_date={}", yesterday);
    assert_dl_count("FOO_DOWNLOAD/1.0.0", Some(&query), 0);
    // crate/downloads always returns the last 90 days and ignores date params
    assert_dl_count("FOO_DOWNLOAD", Some(&query), 2);

    let tomorrow = (Utc::today() + Duration::days(1)).format("%F");
    let query = format!("before_date={}", tomorrow);
    assert_dl_count("FOO_DOWNLOAD/1.0.0", Some(&query), 2);
    assert_dl_count("FOO_DOWNLOAD", Some(&query), 2);
}

#[test]
fn download_nonexistent_version_of_existing_crate_404s() {
    let (app, anon, user) = TestApp::init().with_user();
    let user = user.as_model();

    app.db(|conn| {
        CrateBuilder::new("foo_bad", user.id).expect_build(conn);
    });

    anon.get("/api/v1/crates/foo_bad/0.1.0/download")
        .assert_not_found();
}

#[test]
fn download_noncanonical_crate_name() {
    let (app, anon, user) = TestApp::init().with_user();
    let user = user.as_model();

    app.db(|conn| {
        CrateBuilder::new("foo_download", user.id)
            .version(VersionBuilder::new("1.0.0"))
            .expect_build(conn);
    });

    // Request download for "foo-download" with a dash instead of an underscore,
    // and assert that the correct download link is returned.
    anon.get::<()>("/api/v1/crates/foo-download/1.0.0/download")
        .assert_redirect_ends_with("/crates/foo_download/foo_download-1.0.0.crate");
}
<commit_msg>tests: update download test to work with downloads_counter<commit_after>use crate::builders::{CrateBuilder, VersionBuilder};
use crate::util::{RequestHelper, TestApp};
use cargo_registry::views::EncodableVersionDownload;
use chrono::{Duration, Utc};
use http::StatusCode;

#[derive(Deserialize)]
struct Downloads {
    version_downloads: Vec<EncodableVersionDownload>,
}

#[test]
fn download() {
    let (app, anon, user) = TestApp::init().with_user();
    let user = user.as_model();

    app.db(|conn| {
        CrateBuilder::new("foo_download", user.id)
            .version(VersionBuilder::new("1.0.0"))
            .expect_build(conn);
    });

    let assert_dl_count = |name_and_version: &str, query: Option<&str>, count: i32| {
        let url = format!("/api/v1/crates/{}/downloads", name_and_version);
        let downloads: Downloads = if let Some(query) = query {
            anon.get_with_query(&url, query).good()
        } else {
            anon.get(&url).good()
        };
        let total_downloads = downloads
            .version_downloads
            .iter()
            .map(|vd| vd.downloads)
            .sum::<i32>();
        assert_eq!(total_downloads, count);
    };

    let download = |name_and_version: &str| {
        let url = format!("/api/v1/crates/{}/download", name_and_version);
        let response = anon.get::<()>(&url);
        assert_eq!(response.status(), StatusCode::FOUND);
        // TODO: test the with_json code path
    };

    let persist_downloads_count = || {
        app.as_inner()
            .downloads_counter
            .persist_all_shards(app.as_inner())
            .expect("failed to persist downloads count");
    };

    download("foo_download/1.0.0");
    // No downloads are counted until the counters are persisted
    assert_dl_count("foo_download/1.0.0", None, 0);
    assert_dl_count("foo_download", None, 0);
    persist_downloads_count();
    // Now that the counters are persisted the download counts show up.
    assert_dl_count("foo_download/1.0.0", None, 1);
    assert_dl_count("foo_download", None, 1);

    download("FOO_DOWNLOAD/1.0.0");
    persist_downloads_count();
    assert_dl_count("FOO_DOWNLOAD/1.0.0", None, 2);
    assert_dl_count("FOO_DOWNLOAD", None, 2);

    let yesterday = (Utc::today() + Duration::days(-1)).format("%F");
    let query = format!("before_date={}", yesterday);
    assert_dl_count("FOO_DOWNLOAD/1.0.0", Some(&query), 0);
    // crate/downloads always returns the last 90 days and ignores date params
    assert_dl_count("FOO_DOWNLOAD", Some(&query), 2);

    let tomorrow = (Utc::today() + Duration::days(1)).format("%F");
    let query = format!("before_date={}", tomorrow);
    assert_dl_count("FOO_DOWNLOAD/1.0.0", Some(&query), 2);
    assert_dl_count("FOO_DOWNLOAD", Some(&query), 2);
}

#[test]
fn download_nonexistent_version_of_existing_crate_404s() {
    let (app, anon, user) = TestApp::init().with_user();
    let user = user.as_model();

    app.db(|conn| {
        CrateBuilder::new("foo_bad", user.id).expect_build(conn);
    });

    anon.get("/api/v1/crates/foo_bad/0.1.0/download")
        .assert_not_found();
}

#[test]
fn download_noncanonical_crate_name() {
    let (app, anon, user) = TestApp::init().with_user();
    let user = user.as_model();

    app.db(|conn| {
        CrateBuilder::new("foo_download", user.id)
            .version(VersionBuilder::new("1.0.0"))
            .expect_build(conn);
    });

    // Request download for "foo-download" with a dash instead of an underscore,
    // and assert that the correct download link is returned.
    anon.get::<()>("/api/v1/crates/foo-download/1.0.0/download")
        .assert_redirect_ends_with("/crates/foo_download/foo_download-1.0.0.crate");
}
<|endoftext|>


<commit_before>//! Wrappers to transform the timestamps of updates.
//!
//! These wrappers are primarily intended to support the re-use of a multi-version index
//! as if it were frozen at a particular (nested) timestamp. For example, if one wants to
//! re-use an index multiple times with minor edits, and only observe the edits at one
//! logical time (meaning: observing all edits less or equal to that time, advanced to that
//! time), this should allow that behavior.
//!
//! Informally, this wrapper is parameterized by a function `F: Fn(&T)->Option<T>` which
//! provides the opportunity to alter the time at which an update happens and to suppress
//! that update, if appropriate. For example, the function
//!
//! ```ignore
//! |t| if t.inner < 10 { let mut t = t.clone(); t.inner = 10; Some(t) } else { None }
//! ```
//!
//! could be used to present all updates through inner iteration 10, but advanced to inner
//! iteration 10, as if they all occurred exactly at that moment.

use std::rc::Rc;

use lattice::Lattice;
use trace::{TraceReader, BatchReader, Description};
use trace::cursor::Cursor;

/// Wrapper to provide trace to nested scope.
pub struct TraceFreeze<K, V, T, R, Tr, F>
where
    T: Lattice+Clone+'static,
    Tr: TraceReader<K, V, T, R>,
    F: Fn(&T)->Option<T>,
{
    phantom: ::std::marker::PhantomData<(K, V, R, T)>,
    trace: Tr,
    func: Rc<F>,
}

impl<K,V,T,R,Tr,F> Clone for TraceFreeze<K, V, T, R, Tr, F>
where
    T: Lattice+Clone+'static,
    Tr: TraceReader<K, V, T, R>+Clone,
    F: Fn(&T)->Option<T>,
{
    fn clone(&self) -> Self {
        TraceFreeze {
            phantom: ::std::marker::PhantomData,
            trace: self.trace.clone(),
            func: self.func.clone(),
        }
    }
}

impl<K, V, T, R, Tr, F> TraceReader<K, V, T, R> for TraceFreeze<K, V, T, R, Tr, F>
where
    Tr: TraceReader<K, V, T, R>,
    Tr::Batch: Clone,
    K: 'static,
    V: 'static,
    T: Lattice+Clone+Default+'static,
    R: 'static,
    F: Fn(&T)->Option<T>+'static,
{
    type Batch = BatchFreeze<K, V, T, R, Tr::Batch, F>;
    type Cursor = CursorFreeze<K, V, T, R, Tr::Cursor, F>;

    fn map_batches<F2: FnMut(&Self::Batch)>(&mut self, mut f: F2) {
        let func = &self.func;
        self.trace.map_batches(|batch| {
            f(&Self::Batch::make_from(batch.clone(), func.clone()));
        })
    }

    fn advance_by(&mut self, frontier: &[T]) { self.trace.advance_by(frontier) }
    fn advance_frontier(&mut self) -> &[T] { self.trace.advance_frontier() }

    fn distinguish_since(&mut self, frontier: &[T]) { self.trace.distinguish_since(frontier) }
    fn distinguish_frontier(&mut self) -> &[T] { self.trace.distinguish_frontier() }

    fn cursor_through(&mut self, upper: &[T]) -> Option<(Self::Cursor, <Self::Cursor as Cursor<K, V, T, R>>::Storage)> {
        let func = &self.func;
        self.trace.cursor_through(upper)
            .map(|(cursor, storage)| (CursorFreeze::new(cursor, func.clone()), storage))
    }
}

impl<K, V, T, R, Tr, F> TraceFreeze<K, V, T, R, Tr, F>
where
    Tr: TraceReader<K, V, T, R>,
    Tr::Batch: Clone,
    K: 'static,
    V: 'static,
    T: Lattice+Clone+Default+'static,
    R: 'static,
    F: Fn(&T)->Option<T>,
{
    /// Makes a new trace wrapper
    pub fn make_from(trace: Tr, func: F) -> Self {
        TraceFreeze {
            phantom: ::std::marker::PhantomData,
            trace: trace,
            func: Rc::new(func),
        }
    }
}

/// Wrapper to provide batch to nested scope.
pub struct BatchFreeze<K, V, T, R, B, F> {
    phantom: ::std::marker::PhantomData<(K, V, R, T)>,
    batch: B,
    func: Rc<F>,
}

impl<K, V, T: Clone, R, B: Clone, F> Clone for BatchFreeze<K, V, T, R, B, F> {
    fn clone(&self) -> Self {
        BatchFreeze {
            phantom: ::std::marker::PhantomData,
            batch: self.batch.clone(),
            func: self.func.clone(),
        }
    }
}

impl<K, V, T, R, B, F> BatchReader<K, V, T, R> for BatchFreeze<K, V, T, R, B, F>
where
    B: BatchReader<K, V, T, R>,
    T: Clone+Default,
    F: Fn(&T)->Option<T>,
{
    type Cursor = CursorFreeze<K, V, T, R, B::Cursor, F>;

    fn cursor(&self) -> (Self::Cursor, <Self::Cursor as Cursor<K, V, T, R>>::Storage) {
        let (cursor, storage) = self.batch.cursor();
        (CursorFreeze::new(cursor, self.func.clone()), storage)
    }
    fn len(&self) -> usize { self.batch.len() }
    fn description(&self) -> &Description<T> { self.batch.description() }
}

impl<K, V, T, R, B, F> BatchFreeze<K, V, T, R, B, F>
where
    B: BatchReader<K, V, T, R>,
    T: Clone,
    F: Fn(&T)->Option<T>
{
    /// Makes a new batch wrapper
    pub fn make_from(batch: B, func: Rc<F>) -> Self {
        BatchFreeze {
            phantom: ::std::marker::PhantomData,
            batch: batch,
            func: func,
        }
    }
}

/// Wrapper to provide cursor to nested scope.
pub struct CursorFreeze<K, V, T, R, C: Cursor<K, V, T, R>, F> {
    phantom: ::std::marker::PhantomData<(K, V, R, T)>,
    cursor: C,
    func: Rc<F>,
}

impl<K, V, T, R, C: Cursor<K, V, T, R>, F> CursorFreeze<K, V, T, R, C, F> {
    fn new(cursor: C, func: Rc<F>) -> Self {
        CursorFreeze {
            phantom: ::std::marker::PhantomData,
            cursor: cursor,
            func: func,
        }
    }
}

impl<K, V, T, R, C, F> Cursor<K, V, T, R> for CursorFreeze<K, V, T, R, C, F>
where
    C: Cursor<K, V, T, R>,
    F: Fn(&T)->Option<T>,
{

    type Storage = C::Storage;

    #[inline(always)]
    fn key_valid(&self, storage: &Self::Storage) -> bool { self.cursor.key_valid(storage) }
    #[inline(always)]
    fn val_valid(&self, storage: &Self::Storage) -> bool { self.cursor.val_valid(storage) }

    #[inline(always)]
    fn key<'a>(&self, storage: &'a Self::Storage) -> &'a K { self.cursor.key(storage) }
    #[inline(always)]
    fn val<'a>(&self, storage: &'a Self::Storage) -> &'a V { self.cursor.val(storage) }

    #[inline(always)]
    fn map_times<L: FnMut(&T, R)>(&mut self, storage: &Self::Storage, mut logic: L) {
        let func = &self.func;
        self.cursor.map_times(storage, |time, diff| {
            if let Some(time) = func(time) {
                logic(&time, diff);
            }
        })
    }

    #[inline(always)]
    fn step_key(&mut self, storage: &Self::Storage) { self.cursor.step_key(storage) }
    #[inline(always)]
    fn seek_key(&mut self, storage: &Self::Storage, key: &K) { self.cursor.seek_key(storage, key) }

    #[inline(always)]
    fn step_val(&mut self, storage: &Self::Storage) { self.cursor.step_val(storage) }
    #[inline(always)]
    fn seek_val(&mut self, storage: &Self::Storage, val: &V) { self.cursor.seek_val(storage, val) }

    #[inline(always)]
    fn rewind_keys(&mut self, storage: &Self::Storage) { self.cursor.rewind_keys(storage) }
    #[inline(always)]
    fn rewind_vals(&mut self, storage: &Self::Storage) { self.cursor.rewind_vals(storage) }
}<commit_msg>added freeze method<commit_after>//! Wrappers to transform the timestamps of updates.
//!
//! These wrappers are primarily intended to support the re-use of a multi-version index
//! as if it were frozen at a particular (nested) timestamp. For example, if one wants to
//! re-use an index multiple times with minor edits, and only observe the edits at one
//! logical time (meaning: observing all edits less or equal to that time, advanced to that
//! time), this should allow that behavior.
//!
//! Informally, this wrapper is parameterized by a function `F: Fn(&T)->Option<T>` which
//! provides the opportunity to alter the time at which an update happens and to suppress
//! that update, if appropriate. For example, the function
//!
//! ```ignore
//! |t| if t.inner <= 10 { let mut t = t.clone(); t.inner = 10; Some(t) } else { None }
//! ```
//!
//! could be used to present all updates through inner iteration 10, but advanced to inner
//! iteration 10, as if they all occurred exactly at that moment.

use std::rc::Rc;

use timely::dataflow::Scope;
use timely::dataflow::operators::Map;

use operators::arrange::{Arranged, BatchWrapper};
use lattice::Lattice;
use trace::{TraceReader, BatchReader, Description};
use trace::cursor::Cursor;

/// Freezes updates to an arrangement using a supplied function.
///
/// This method is experimental, and should be used with care. The intent is that the function
/// `func` can be used to restrict and lock in updates at a particular time, as suggested in the
/// module-level documentation.
pub fn freeze<G, K, V, R, T, F>(arranged: &Arranged<G, K, V, R, T>, func: F) -> Arranged<G, K, V, R, TraceFreeze<K, V, G::Timestamp, R, T, F>>
where
    G: Scope,
    G::Timestamp: Lattice+Ord,
    K: 'static,
    V: 'static,
    R: 'static,
    T: TraceReader<K, V, G::Timestamp, R>+Clone,
    F: Fn(&G::Timestamp)->Option<G::Timestamp>+'static,
{
    let func1 = Rc::new(func);
    let func2 = func1.clone();
    Arranged {
        stream: arranged.stream.map(move |bw| BatchWrapper { item: BatchFreeze::make_from(bw.item, func1.clone()) }),
        trace: TraceFreeze::make_from(arranged.trace.clone(), func2),
    }
}

/// Wrapper to provide trace to nested scope.
pub struct TraceFreeze<K, V, T, R, Tr, F>
where
    T: Lattice+Clone+'static,
    Tr: TraceReader<K, V, T, R>,
    F: Fn(&T)->Option<T>,
{
    phantom: ::std::marker::PhantomData<(K, V, R, T)>,
    trace: Tr,
    func: Rc<F>,
}

impl<K,V,T,R,Tr,F> Clone for TraceFreeze<K, V, T, R, Tr, F>
where
    T: Lattice+Clone+'static,
    Tr: TraceReader<K, V, T, R>+Clone,
    F: Fn(&T)->Option<T>,
{
    fn clone(&self) -> Self {
        TraceFreeze {
            phantom: ::std::marker::PhantomData,
            trace: self.trace.clone(),
            func: self.func.clone(),
        }
    }
}

impl<K, V, T, R, Tr, F> TraceReader<K, V, T, R> for TraceFreeze<K, V, T, R, Tr, F>
where
    Tr: TraceReader<K, V, T, R>,
    Tr::Batch: Clone,
    K: 'static,
    V: 'static,
    T: Lattice+Clone+Default+'static,
    R: 'static,
    F: Fn(&T)->Option<T>+'static,
{
    type Batch = BatchFreeze<K, V, T, R, Tr::Batch, F>;
    type Cursor = CursorFreeze<K, V, T, R, Tr::Cursor, F>;

    fn map_batches<F2: FnMut(&Self::Batch)>(&mut self, mut f: F2) {
        let func = &self.func;
        self.trace.map_batches(|batch| {
            f(&Self::Batch::make_from(batch.clone(), func.clone()));
        })
    }

    fn advance_by(&mut self, frontier: &[T]) { self.trace.advance_by(frontier) }
    fn advance_frontier(&mut self) -> &[T] { self.trace.advance_frontier() }

    fn distinguish_since(&mut self, frontier: &[T]) { self.trace.distinguish_since(frontier) }
    fn distinguish_frontier(&mut self) -> &[T] { self.trace.distinguish_frontier() }

    fn cursor_through(&mut self, upper: &[T]) -> Option<(Self::Cursor, <Self::Cursor as Cursor<K, V, T, R>>::Storage)> {
        let func = &self.func;
        self.trace.cursor_through(upper)
            .map(|(cursor, storage)| (CursorFreeze::new(cursor, func.clone()), storage))
    }
}

impl<K, V, T, R, Tr, F> TraceFreeze<K, V, T, R, Tr, F>
where
    Tr: TraceReader<K, V, T, R>,
    Tr::Batch: Clone,
    K: 'static,
    V: 'static,
    T: Lattice+Clone+Default+'static,
    R: 'static,
    F: Fn(&T)->Option<T>,
{
    /// Makes a new trace wrapper
    pub fn make_from(trace: Tr, func: Rc<F>) -> Self {
        TraceFreeze {
            phantom: ::std::marker::PhantomData,
            trace: trace,
            func: func,
        }
    }
}

/// Wrapper to provide batch to nested scope.
pub struct BatchFreeze<K, V, T, R, B, F> {
    phantom: ::std::marker::PhantomData<(K, V, R, T)>,
    batch: B,
    func: Rc<F>,
}

impl<K, V, T: Clone, R, B: Clone, F> Clone for BatchFreeze<K, V, T, R, B, F> {
    fn clone(&self) -> Self {
        BatchFreeze {
            phantom: ::std::marker::PhantomData,
            batch: self.batch.clone(),
            func: self.func.clone(),
        }
    }
}

impl<K, V, T, R, B, F> BatchReader<K, V, T, R> for BatchFreeze<K, V, T, R, B, F>
where
    B: BatchReader<K, V, T, R>,
    T: Clone+Default,
    F: Fn(&T)->Option<T>,
{
    type Cursor = CursorFreeze<K, V, T, R, B::Cursor, F>;

    fn cursor(&self) -> (Self::Cursor, <Self::Cursor as Cursor<K, V, T, R>>::Storage) {
        let (cursor, storage) = self.batch.cursor();
        (CursorFreeze::new(cursor, self.func.clone()), storage)
    }
    fn len(&self) -> usize { self.batch.len() }
    fn description(&self) -> &Description<T> { self.batch.description() }
}

impl<K, V, T, R, B, F> BatchFreeze<K, V, T, R, B, F>
where
    B: BatchReader<K, V, T, R>,
    T: Clone,
    F: Fn(&T)->Option<T>
{
    /// Makes a new batch wrapper
    pub fn make_from(batch: B, func: Rc<F>) -> Self {
        BatchFreeze {
            phantom: ::std::marker::PhantomData,
            batch: batch,
            func: func,
        }
    }
}

/// Wrapper to provide cursor to nested scope.
pub struct CursorFreeze<K, V, T, R, C: Cursor<K, V, T, R>, F> {
    phantom: ::std::marker::PhantomData<(K, V, R, T)>,
    cursor: C,
    func: Rc<F>,
}

impl<K, V, T, R, C: Cursor<K, V, T, R>, F> CursorFreeze<K, V, T, R, C, F> {
    fn new(cursor: C, func: Rc<F>) -> Self {
        CursorFreeze {
            phantom: ::std::marker::PhantomData,
            cursor: cursor,
            func: func,
        }
    }
}

impl<K, V, T, R, C, F> Cursor<K, V, T, R> for CursorFreeze<K, V, T, R, C, F>
where
    C: Cursor<K, V, T, R>,
    F: Fn(&T)->Option<T>,
{

    type Storage = C::Storage;

    #[inline(always)]
    fn key_valid(&self, storage: &Self::Storage) -> bool { self.cursor.key_valid(storage) }
    #[inline(always)]
    fn val_valid(&self, storage: &Self::Storage) -> bool { self.cursor.val_valid(storage) }

    #[inline(always)]
    fn key<'a>(&self, storage: &'a Self::Storage) -> &'a K { self.cursor.key(storage) }
    #[inline(always)]
    fn val<'a>(&self, storage: &'a Self::Storage) -> &'a V { self.cursor.val(storage) }

    #[inline(always)]
    fn map_times<L: FnMut(&T, R)>(&mut self, storage: &Self::Storage, mut logic: L) {
        let func = &self.func;
        self.cursor.map_times(storage, |time, diff| {
            if let Some(time) = func(time) {
                logic(&time, diff);
            }
        })
    }

    #[inline(always)]
    fn step_key(&mut self, storage: &Self::Storage) { self.cursor.step_key(storage) }
    #[inline(always)]
    fn seek_key(&mut self, storage: &Self::Storage, key: &K) { self.cursor.seek_key(storage, key) }

    #[inline(always)]
    fn step_val(&mut self, storage: &Self::Storage) { self.cursor.step_val(storage) }
    #[inline(always)]
    fn seek_val(&mut self, storage: &Self::Storage, val: &V) { self.cursor.seek_val(storage, val) }

    #[inline(always)]
    fn rewind_keys(&mut self, storage: &Self::Storage) { self.cursor.rewind_keys(storage) }
    #[inline(always)]
    fn rewind_vals(&mut self, storage: &Self::Storage) { self.cursor.rewind_vals(storage) }
}<|endoftext|>


<commit_before>use gettextrs::gettext;
use gstreamer as gst;

use gtk;
use gtk::prelude::*;

use std::sync::Arc;

use metadata::Stream;

use super::{PlaybackPipeline, UIController};

const ALIGN_LEFT: f32 = 0f32;
const ALIGN_CENTER: f32 = 0.5f32;
const ALIGN_RIGHT: f32 = 1f32;

pub(super) const EXPORT_FLAG_COL: u32 = 0;
pub(super) const STREAM_ID_COL: u32 = 1;
const STREAM_ID_DISPLAY_COL: u32 = 2;
const LANGUAGE_COL: u32 = 3;
const CODEC_COL: u32 = 4;
const COMMENT_COL: u32 = 5;

const VIDEO_WIDTH_COL: u32 = 6;
const VIDEO_HEIGHT_COL: u32 = 7;

const AUDIO_RATE_COL: u32 = 6;
const AUDIO_CHANNELS_COL: u32 = 7;

const TEXT_FORMAT_COL: u32 = 6;

pub struct StreamsController {
    pub(super) page: gtk::Grid,

    pub(super) video_treeview: gtk::TreeView,
    pub(super) video_store: gtk::ListStore,
    pub(super) video_selected: Option<Arc<str>>,

    pub(super) audio_treeview: gtk::TreeView,
    pub(super) audio_store: gtk::ListStore,
    pub(super) audio_selected: Option<Arc<str>>,

    pub(super) text_treeview: gtk::TreeView,
    pub(super) text_store: gtk::ListStore,
    pub(super) text_selected: Option<Arc<str>>,
}

impl UIController for StreamsController {
    fn new_media(&mut self, pipeline: &PlaybackPipeline) {
        {
            let mut info = pipeline.info.write().unwrap();

            // Video streams
            let mut sorted_ids = info
                .streams
                .video
                .keys()
                .map(|key| Arc::clone(key))
                .collect::<Vec<Arc<str>>>();
            sorted_ids.sort();
            for stream_id in sorted_ids {
                let stream = info.streams.get_video_mut(stream_id).unwrap();
                stream.must_export = true;
                let iter = self.add_stream(&self.video_store, stream);
                let caps_structure = stream.caps.get_structure(0).unwrap();
                if let Some(width) = caps_structure.get::<i32>("width").unwrap() {
                    self.video_store
                        .set_value(&iter, VIDEO_WIDTH_COL, &gtk::Value::from(&width));
                }
                if let Some(height) = caps_structure.get::<i32>("height").unwrap() {
                    self.video_store
                        .set_value(&iter, VIDEO_HEIGHT_COL, &gtk::Value::from(&height));
                }
            }

            // Audio streams
            let mut sorted_ids = info
                .streams
                .audio
                .keys()
                .map(|key| Arc::clone(key))
                .collect::<Vec<Arc<str>>>();
            sorted_ids.sort();
            for stream_id in sorted_ids {
                let stream = info.streams.get_audio_mut(stream_id).unwrap();
                stream.must_export = true;
                let iter = self.add_stream(&self.audio_store, stream);
                let caps_structure = stream.caps.get_structure(0).unwrap();
                if let Some(rate) = caps_structure.get::<i32>("rate").unwrap() {
                    self.audio_store
                        .set_value(&iter, AUDIO_RATE_COL, &gtk::Value::from(&rate));
                }
                if let Some(channels) = caps_structure.get::<i32>("channels").unwrap() {
                    self.audio_store.set_value(
                        &iter,
                        AUDIO_CHANNELS_COL,
                        &gtk::Value::from(&channels),
                    );
                }
            }

            // Text streams
            let mut sorted_ids = info
                .streams
                .text
                .keys()
                .map(|key| Arc::clone(key))
                .collect::<Vec<Arc<str>>>();
            sorted_ids.sort();
            for stream_id in sorted_ids {
                let stream = info.streams.get_text_mut(stream_id).unwrap();
                let iter = self.add_stream(&self.text_store, stream);
                // FIXME: discard text stream export for now as it hangs the export
                // (see https://github.com/fengalin/media-toc/issues/136)
                stream.must_export = false;
                self.text_store
                    .set_value(&iter, EXPORT_FLAG_COL, &gtk::Value::from(&false));
                let caps_structure = stream.caps.get_structure(0).unwrap();
                if let Some(format) = caps_structure.get::<&str>("format").unwrap() {
                    self.text_store
                        .set_value(&iter, TEXT_FORMAT_COL, &gtk::Value::from(&format));
                }
            }
        }

        self.video_selected = self.video_store.get_iter_first().map(|ref iter| {
            self.video_treeview.get_selection().select_iter(iter);
            self.get_stream_at(&self.video_store, iter)
        });

        self.audio_selected = self.audio_store.get_iter_first().map(|ref iter| {
            self.audio_treeview.get_selection().select_iter(iter);
            self.get_stream_at(&self.audio_store, iter)
        });

        self.text_selected = self.text_store.get_iter_first().map(|ref iter| {
            self.text_treeview.get_selection().select_iter(iter);
            self.get_stream_at(&self.text_store, iter)
        });
    }

    fn cleanup(&mut self) {
        self.video_store.clear();
        self.video_selected = None;
        self.audio_store.clear();
        self.audio_selected = None;
        self.text_store.clear();
        self.text_selected = None;
    }

    fn grab_focus(&self) {
        // grab focus asynchronoulsy because it triggers the `cursor_changed` signal
        // which needs to check if the stream has changed
        let audio_treeview = self.audio_treeview.clone();
        spawn!(async move {
            audio_treeview.grab_focus();
        });
    }
}

impl StreamsController {
    pub fn new(builder: &gtk::Builder) -> Self {
        let mut ctrl = StreamsController {
            page: builder.get_object("streams-grid").unwrap(),

            video_treeview: builder.get_object("video_streams-treeview").unwrap(),
            video_store: builder.get_object("video_streams-liststore").unwrap(),
            video_selected: None,

            audio_treeview: builder.get_object("audio_streams-treeview").unwrap(),
            audio_store: builder.get_object("audio_streams-liststore").unwrap(),
            audio_selected: None,

            text_treeview: builder.get_object("text_streams-treeview").unwrap(),
            text_store: builder.get_object("text_streams-liststore").unwrap(),
            text_selected: None,
        };

        ctrl.cleanup();
        ctrl.init_treeviews();

        ctrl
    }

    pub fn get_selected_streams(&self) -> Vec<Arc<str>> {
        let mut streams: Vec<Arc<str>> = Vec::new();
        if let Some(stream) = self.video_selected.as_ref() {
            streams.push(Arc::clone(stream));
        }
        if let Some(stream) = self.audio_selected.as_ref() {
            streams.push(Arc::clone(stream));
        }
        if let Some(stream) = self.text_selected.as_ref() {
            streams.push(Arc::clone(stream));
        }

        streams
    }

    fn add_stream(&self, store: &gtk::ListStore, stream: &Stream) -> gtk::TreeIter {
        let id_parts: Vec<&str> = stream.id.split('/').collect();
        let stream_id_display = if id_parts.len() == 2 {
            id_parts[1].to_owned()
        } else {
            gettext("unknown")
        };

        let iter = store.insert_with_values(
            None,
            &[EXPORT_FLAG_COL, STREAM_ID_COL, STREAM_ID_DISPLAY_COL],
            &[&true, &stream.id.as_ref(), &stream_id_display],
        );

        let lang = stream
            .tags
            .get_index::<gst::tags::LanguageName>(0)
            .or_else(|| stream.tags.get_index::<gst::tags::LanguageCode>(0))
            .and_then(glib::TypedValue::get)
            .unwrap_or("-");
        store.set_value(&iter, LANGUAGE_COL, &gtk::Value::from(lang));

        if let Some(comment) = stream
            .tags
            .get_index::<gst::tags::Comment>(0)
            .and_then(glib::TypedValue::get)
        {
            store.set_value(&iter, COMMENT_COL, &gtk::Value::from(comment));
        }

        store.set_value(&iter, CODEC_COL, &gtk::Value::from(&stream.codec_printable));

        iter
    }

    pub fn get_stream_at(&self, store: &gtk::ListStore, iter: &gtk::TreeIter) -> Arc<str> {
        store
            .get_value(iter, STREAM_ID_COL as i32)
            .get::<String>()
            .unwrap()
            .unwrap()
            .into()
    }

    fn init_treeviews(&self) {
        self.video_treeview.set_model(Some(&self.video_store));

        let export_flag_lbl = gettext("Export?");
        let stream_id_lbl = gettext("Stream id");
        let language_lbl = gettext("Language");
        let codec_lbl = gettext("Codec");
        let comment_lbl = gettext("Comment");

        // Video
        self.add_check_column(&self.video_treeview, &export_flag_lbl, EXPORT_FLAG_COL);
        self.add_text_column(
            &self.video_treeview,
            &stream_id_lbl,
            ALIGN_LEFT,
            STREAM_ID_DISPLAY_COL,
            Some(200),
        );
        self.add_text_column(
            &self.video_treeview,
            &language_lbl,
            ALIGN_CENTER,
            LANGUAGE_COL,
            None,
        );
        self.add_text_column(
            &self.video_treeview,
            &codec_lbl,
            ALIGN_LEFT,
            CODEC_COL,
            None,
        );
        self.add_text_column(
            &self.video_treeview,
            &gettext("Width"),
            ALIGN_RIGHT,
            VIDEO_WIDTH_COL,
            None,
        );
        self.add_text_column(
            &self.video_treeview,
            &gettext("Height"),
            ALIGN_RIGHT,
            VIDEO_HEIGHT_COL,
            None,
        );
        self.add_text_column(
            &self.video_treeview,
            &comment_lbl,
            ALIGN_LEFT,
            COMMENT_COL,
            None,
        );

        // Audio
        self.audio_treeview.set_model(Some(&self.audio_store));
        self.add_check_column(&self.audio_treeview, &export_flag_lbl, EXPORT_FLAG_COL);
        self.add_text_column(
            &self.audio_treeview,
            &stream_id_lbl,
            ALIGN_LEFT,
            STREAM_ID_DISPLAY_COL,
            Some(200),
        );
        self.add_text_column(
            &self.audio_treeview,
            &language_lbl,
            ALIGN_CENTER,
            LANGUAGE_COL,
            None,
        );
        self.add_text_column(
            &self.audio_treeview,
            &codec_lbl,
            ALIGN_LEFT,
            CODEC_COL,
            None,
        );
        self.add_text_column(
            &self.audio_treeview,
            &gettext("Rate"),
            ALIGN_RIGHT,
            AUDIO_RATE_COL,
            None,
        );
        self.add_text_column(
            &self.audio_treeview,
            &gettext("Channels"),
            ALIGN_RIGHT,
            AUDIO_CHANNELS_COL,
            None,
        );
        self.add_text_column(
            &self.audio_treeview,
            &comment_lbl,
            ALIGN_LEFT,
            COMMENT_COL,
            None,
        );

        // Text
        self.text_treeview.set_model(Some(&self.text_store));
        let renderer =
            self.add_check_column(&self.text_treeview, &export_flag_lbl, EXPORT_FLAG_COL);
        // FIXME: discard text stream export for now as it hangs the export
        // (see https://github.com/fengalin/media-toc/issues/136)
        renderer.set_activatable(false);

        self.add_text_column(
            &self.text_treeview,
            &stream_id_lbl,
            ALIGN_LEFT,
            STREAM_ID_DISPLAY_COL,
            Some(200),
        );
        self.add_text_column(
            &self.text_treeview,
            &language_lbl,
            ALIGN_CENTER,
            LANGUAGE_COL,
            None,
        );
        self.add_text_column(&self.text_treeview, &codec_lbl, ALIGN_LEFT, CODEC_COL, None);
        self.add_text_column(
            &self.text_treeview,
            &gettext("Format"),
            ALIGN_LEFT,
            TEXT_FORMAT_COL,
            None,
        );
        self.add_text_column(
            &self.text_treeview,
            &comment_lbl,
            ALIGN_LEFT,
            COMMENT_COL,
            None,
        );
    }

    fn add_text_column(
        &self,
        treeview: &gtk::TreeView,
        title: &str,
        alignment: f32,
        col_id: u32,
        width: Option<i32>,
    ) {
        let col = gtk::TreeViewColumn::new();
        col.set_title(title);

        let renderer = gtk::CellRendererText::new();
        renderer.set_alignment(alignment, 0.5f32);
        col.pack_start(&renderer, true);
        col.add_attribute(&renderer, "text", col_id as i32);

        if let Some(width) = width {
            renderer.set_fixed_size(width, -1);
        }

        treeview.append_column(&col);
    }

    fn add_check_column(
        &self,
        treeview: &gtk::TreeView,
        title: &str,
        col_id: u32,
    ) -> gtk::CellRendererToggle {
        let col = gtk::TreeViewColumn::new();
        col.set_title(title);

        let renderer = gtk::CellRendererToggle::new();
        renderer.set_radio(false);
        renderer.set_activatable(true);
        col.pack_start(&renderer, true);
        col.add_attribute(&renderer, "active", col_id as i32);

        treeview.append_column(&col);
        renderer
    }
}
<commit_msg>UI: fix stream tags handling<commit_after>use gettextrs::gettext;
use gstreamer as gst;

use gtk;
use gtk::prelude::*;

use std::sync::Arc;

use metadata::Stream;

use super::{PlaybackPipeline, UIController};

const ALIGN_LEFT: f32 = 0f32;
const ALIGN_CENTER: f32 = 0.5f32;
const ALIGN_RIGHT: f32 = 1f32;

pub(super) const EXPORT_FLAG_COL: u32 = 0;
pub(super) const STREAM_ID_COL: u32 = 1;
const STREAM_ID_DISPLAY_COL: u32 = 2;
const LANGUAGE_COL: u32 = 3;
const CODEC_COL: u32 = 4;
const COMMENT_COL: u32 = 5;

const VIDEO_WIDTH_COL: u32 = 6;
const VIDEO_HEIGHT_COL: u32 = 7;

const AUDIO_RATE_COL: u32 = 6;
const AUDIO_CHANNELS_COL: u32 = 7;

const TEXT_FORMAT_COL: u32 = 6;

pub struct StreamsController {
    pub(super) page: gtk::Grid,

    pub(super) video_treeview: gtk::TreeView,
    pub(super) video_store: gtk::ListStore,
    pub(super) video_selected: Option<Arc<str>>,

    pub(super) audio_treeview: gtk::TreeView,
    pub(super) audio_store: gtk::ListStore,
    pub(super) audio_selected: Option<Arc<str>>,

    pub(super) text_treeview: gtk::TreeView,
    pub(super) text_store: gtk::ListStore,
    pub(super) text_selected: Option<Arc<str>>,
}

impl UIController for StreamsController {
    fn new_media(&mut self, pipeline: &PlaybackPipeline) {
        {
            let mut info = pipeline.info.write().unwrap();

            // Video streams
            let mut sorted_ids = info
                .streams
                .video
                .keys()
                .map(|key| Arc::clone(key))
                .collect::<Vec<Arc<str>>>();
            sorted_ids.sort();
            for stream_id in sorted_ids {
                let stream = info.streams.get_video_mut(stream_id).unwrap();
                stream.must_export = true;
                let iter = self.add_stream(&self.video_store, stream);
                let caps_structure = stream.caps.get_structure(0).unwrap();
                if let Ok(Some(width)) = caps_structure.get::<i32>("width") {
                    self.video_store
                        .set_value(&iter, VIDEO_WIDTH_COL, &gtk::Value::from(&width));
                }
                if let Ok(Some(height)) = caps_structure.get::<i32>("height") {
                    self.video_store
                        .set_value(&iter, VIDEO_HEIGHT_COL, &gtk::Value::from(&height));
                }
            }

            // Audio streams
            let mut sorted_ids = info
                .streams
                .audio
                .keys()
                .map(|key| Arc::clone(key))
                .collect::<Vec<Arc<str>>>();
            sorted_ids.sort();
            for stream_id in sorted_ids {
                let stream = info.streams.get_audio_mut(stream_id).unwrap();
                stream.must_export = true;
                let iter = self.add_stream(&self.audio_store, stream);
                let caps_structure = stream.caps.get_structure(0).unwrap();
                if let Ok(Some(rate)) = caps_structure.get::<i32>("rate") {
                    self.audio_store
                        .set_value(&iter, AUDIO_RATE_COL, &gtk::Value::from(&rate));
                }
                if let Ok(Some(channels)) = caps_structure.get::<i32>("channels") {
                    self.audio_store.set_value(
                        &iter,
                        AUDIO_CHANNELS_COL,
                        &gtk::Value::from(&channels),
                    );
                }
            }

            // Text streams
            let mut sorted_ids = info
                .streams
                .text
                .keys()
                .map(|key| Arc::clone(key))
                .collect::<Vec<Arc<str>>>();
            sorted_ids.sort();
            for stream_id in sorted_ids {
                let stream = info.streams.get_text_mut(stream_id).unwrap();
                let iter = self.add_stream(&self.text_store, stream);
                // FIXME: discard text stream export for now as it hangs the export
                // (see https://github.com/fengalin/media-toc/issues/136)
                stream.must_export = false;
                self.text_store
                    .set_value(&iter, EXPORT_FLAG_COL, &gtk::Value::from(&false));
                let caps_structure = stream.caps.get_structure(0).unwrap();
                if let Ok(Some(format)) = caps_structure.get::<&str>("format") {
                    self.text_store
                        .set_value(&iter, TEXT_FORMAT_COL, &gtk::Value::from(&format));
                }
            }
        }

        self.video_selected = self.video_store.get_iter_first().map(|ref iter| {
            self.video_treeview.get_selection().select_iter(iter);
            self.get_stream_at(&self.video_store, iter)
        });

        self.audio_selected = self.audio_store.get_iter_first().map(|ref iter| {
            self.audio_treeview.get_selection().select_iter(iter);
            self.get_stream_at(&self.audio_store, iter)
        });

        self.text_selected = self.text_store.get_iter_first().map(|ref iter| {
            self.text_treeview.get_selection().select_iter(iter);
            self.get_stream_at(&self.text_store, iter)
        });
    }

    fn cleanup(&mut self) {
        self.video_store.clear();
        self.video_selected = None;
        self.audio_store.clear();
        self.audio_selected = None;
        self.text_store.clear();
        self.text_selected = None;
    }

    fn grab_focus(&self) {
        // grab focus asynchronoulsy because it triggers the `cursor_changed` signal
        // which needs to check if the stream has changed
        let audio_treeview = self.audio_treeview.clone();
        spawn!(async move {
            audio_treeview.grab_focus();
        });
    }
}

impl StreamsController {
    pub fn new(builder: &gtk::Builder) -> Self {
        let mut ctrl = StreamsController {
            page: builder.get_object("streams-grid").unwrap(),

            video_treeview: builder.get_object("video_streams-treeview").unwrap(),
            video_store: builder.get_object("video_streams-liststore").unwrap(),
            video_selected: None,

            audio_treeview: builder.get_object("audio_streams-treeview").unwrap(),
            audio_store: builder.get_object("audio_streams-liststore").unwrap(),
            audio_selected: None,

            text_treeview: builder.get_object("text_streams-treeview").unwrap(),
            text_store: builder.get_object("text_streams-liststore").unwrap(),
            text_selected: None,
        };

        ctrl.cleanup();
        ctrl.init_treeviews();

        ctrl
    }

    pub fn get_selected_streams(&self) -> Vec<Arc<str>> {
        let mut streams: Vec<Arc<str>> = Vec::new();
        if let Some(stream) = self.video_selected.as_ref() {
            streams.push(Arc::clone(stream));
        }
        if let Some(stream) = self.audio_selected.as_ref() {
            streams.push(Arc::clone(stream));
        }
        if let Some(stream) = self.text_selected.as_ref() {
            streams.push(Arc::clone(stream));
        }

        streams
    }

    fn add_stream(&self, store: &gtk::ListStore, stream: &Stream) -> gtk::TreeIter {
        let id_parts: Vec<&str> = stream.id.split('/').collect();
        let stream_id_display = if id_parts.len() == 2 {
            id_parts[1].to_owned()
        } else {
            gettext("unknown")
        };

        let iter = store.insert_with_values(
            None,
            &[EXPORT_FLAG_COL, STREAM_ID_COL, STREAM_ID_DISPLAY_COL],
            &[&true, &stream.id.as_ref(), &stream_id_display],
        );

        let lang = stream
            .tags
            .get_index::<gst::tags::LanguageName>(0)
            .or_else(|| stream.tags.get_index::<gst::tags::LanguageCode>(0))
            .and_then(glib::TypedValue::get)
            .unwrap_or("-");
        store.set_value(&iter, LANGUAGE_COL, &gtk::Value::from(lang));

        if let Some(comment) = stream
            .tags
            .get_index::<gst::tags::Comment>(0)
            .and_then(glib::TypedValue::get)
        {
            store.set_value(&iter, COMMENT_COL, &gtk::Value::from(comment));
        }

        store.set_value(&iter, CODEC_COL, &gtk::Value::from(&stream.codec_printable));

        iter
    }

    pub fn get_stream_at(&self, store: &gtk::ListStore, iter: &gtk::TreeIter) -> Arc<str> {
        store
            .get_value(iter, STREAM_ID_COL as i32)
            .get::<String>()
            .unwrap()
            .unwrap()
            .into()
    }

    fn init_treeviews(&self) {
        self.video_treeview.set_model(Some(&self.video_store));

        let export_flag_lbl = gettext("Export?");
        let stream_id_lbl = gettext("Stream id");
        let language_lbl = gettext("Language");
        let codec_lbl = gettext("Codec");
        let comment_lbl = gettext("Comment");

        // Video
        self.add_check_column(&self.video_treeview, &export_flag_lbl, EXPORT_FLAG_COL);
        self.add_text_column(
            &self.video_treeview,
            &stream_id_lbl,
            ALIGN_LEFT,
            STREAM_ID_DISPLAY_COL,
            Some(200),
        );
        self.add_text_column(
            &self.video_treeview,
            &language_lbl,
            ALIGN_CENTER,
            LANGUAGE_COL,
            None,
        );
        self.add_text_column(
            &self.video_treeview,
            &codec_lbl,
            ALIGN_LEFT,
            CODEC_COL,
            None,
        );
        self.add_text_column(
            &self.video_treeview,
            &gettext("Width"),
            ALIGN_RIGHT,
            VIDEO_WIDTH_COL,
            None,
        );
        self.add_text_column(
            &self.video_treeview,
            &gettext("Height"),
            ALIGN_RIGHT,
            VIDEO_HEIGHT_COL,
            None,
        );
        self.add_text_column(
            &self.video_treeview,
            &comment_lbl,
            ALIGN_LEFT,
            COMMENT_COL,
            None,
        );

        // Audio
        self.audio_treeview.set_model(Some(&self.audio_store));
        self.add_check_column(&self.audio_treeview, &export_flag_lbl, EXPORT_FLAG_COL);
        self.add_text_column(
            &self.audio_treeview,
            &stream_id_lbl,
            ALIGN_LEFT,
            STREAM_ID_DISPLAY_COL,
            Some(200),
        );
        self.add_text_column(
            &self.audio_treeview,
            &language_lbl,
            ALIGN_CENTER,
            LANGUAGE_COL,
            None,
        );
        self.add_text_column(
            &self.audio_treeview,
            &codec_lbl,
            ALIGN_LEFT,
            CODEC_COL,
            None,
        );
        self.add_text_column(
            &self.audio_treeview,
            &gettext("Rate"),
            ALIGN_RIGHT,
            AUDIO_RATE_COL,
            None,
        );
        self.add_text_column(
            &self.audio_treeview,
            &gettext("Channels"),
            ALIGN_RIGHT,
            AUDIO_CHANNELS_COL,
            None,
        );
        self.add_text_column(
            &self.audio_treeview,
            &comment_lbl,
            ALIGN_LEFT,
            COMMENT_COL,
            None,
        );

        // Text
        self.text_treeview.set_model(Some(&self.text_store));
        let renderer =
            self.add_check_column(&self.text_treeview, &export_flag_lbl, EXPORT_FLAG_COL);
        // FIXME: discard text stream export for now as it hangs the export
        // (see https://github.com/fengalin/media-toc/issues/136)
        renderer.set_activatable(false);

        self.add_text_column(
            &self.text_treeview,
            &stream_id_lbl,
            ALIGN_LEFT,
            STREAM_ID_DISPLAY_COL,
            Some(200),
        );
        self.add_text_column(
            &self.text_treeview,
            &language_lbl,
            ALIGN_CENTER,
            LANGUAGE_COL,
            None,
        );
        self.add_text_column(&self.text_treeview, &codec_lbl, ALIGN_LEFT, CODEC_COL, None);
        self.add_text_column(
            &self.text_treeview,
            &gettext("Format"),
            ALIGN_LEFT,
            TEXT_FORMAT_COL,
            None,
        );
        self.add_text_column(
            &self.text_treeview,
            &comment_lbl,
            ALIGN_LEFT,
            COMMENT_COL,
            None,
        );
    }

    fn add_text_column(
        &self,
        treeview: &gtk::TreeView,
        title: &str,
        alignment: f32,
        col_id: u32,
        width: Option<i32>,
    ) {
        let col = gtk::TreeViewColumn::new();
        col.set_title(title);

        let renderer = gtk::CellRendererText::new();
        renderer.set_alignment(alignment, 0.5f32);
        col.pack_start(&renderer, true);
        col.add_attribute(&renderer, "text", col_id as i32);

        if let Some(width) = width {
            renderer.set_fixed_size(width, -1);
        }

        treeview.append_column(&col);
    }

    fn add_check_column(
        &self,
        treeview: &gtk::TreeView,
        title: &str,
        col_id: u32,
    ) -> gtk::CellRendererToggle {
        let col = gtk::TreeViewColumn::new();
        col.set_title(title);

        let renderer = gtk::CellRendererToggle::new();
        renderer.set_radio(false);
        renderer.set_activatable(true);
        col.pack_start(&renderer, true);
        col.add_attribute(&renderer, "active", col_id as i32);

        treeview.append_column(&col);
        renderer
    }
}
<|endoftext|>