<commit_before>use capnp::message;
use hyper::{Client, Url};
use rand;
use rustc_serialize::json;
use time;
use time::{Duration, Timespec};

use ::io::memstream::MemStream;
use ::cluster::common::{BuilderInfo, RPC_BUILDER_LIST};
use ::cluster::builder::{CompileRequest, CompileResponse};
use ::compiler::{CommandInfo, CompilationTask, CompileStep, Compiler, OutputInfo, PreprocessResult, Toolchain};

use std::fs;
use std::fs::File;
use std::io::{BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::{Arc, RwLock};
use std::net::{SocketAddr, TcpStream};

pub struct RemoteCompiler<C: Compiler> {
    shared: Arc<RwLock<RemoteShared>>,
    local: C,
}

struct RemoteShared {
    base_url: Option<Url>,
    cooldown: Timespec,
    builders: Arc<Vec<BuilderInfo>>,
}

struct RemoteToolchain {
    shared: Arc<RwLock<RemoteShared>>,
    local: Arc<Toolchain>,
}

impl<C: Compiler> RemoteCompiler<C> {
    pub fn new(base_url: &Option<Url>, compiler: C) -> Self {
        RemoteCompiler {
            shared: Arc::new(RwLock::new(RemoteShared {
                cooldown: Timespec { sec: 0, nsec: 0 },
                builders: Arc::new(Vec::new()),
                base_url: base_url.as_ref().map(|u| u.clone()),
            })),
            local: compiler,
        }
    }
}

impl RemoteShared {
    fn receive_builders(&self) -> Result<Vec<BuilderInfo>, Error> {
        match &self.base_url {
            &Some(ref base_url) => {
                let client = Client::new();
                client.get(base_url.join(RPC_BUILDER_LIST).unwrap())
                    .send()
                    .map_err(|e| Error::new(ErrorKind::Other, e))
                    .and_then(|mut response| {
                        let mut payload = String::new();
                        response.read_to_string(&mut payload).map(|_| payload)
                    })
                    .and_then(|payload| json::decode(&payload).map_err(|e| Error::new(ErrorKind::InvalidData, e)))
            }
            &None => Ok(Vec::new()),
        }
    }
}

impl<C: Compiler> Compiler for RemoteCompiler<C> {
    // Discovery local toolchains.
    fn discovery_toolchains(&self) -> Vec<Arc<Toolchain>> {
        self.local.discovery_toolchains()
    }

    // Resolve toolchain for command execution.
    fn resolve_toolchain(&self, command: &CommandInfo) -> Option<Arc<Toolchain>> {
        self.local
            .resolve_toolchain(command)
            .map(|local| -> Arc<Toolchain> {
                Arc::new(RemoteToolchain {
                    shared: self.shared.clone(),
                    local: local,
                })
            })
    }
}

impl RemoteToolchain {
    fn compile_remote(&self, task: &CompileStep) -> Result<CompileResponse, Error> {
        let name = try!(self.identifier().ok_or(Error::new(ErrorKind::Other, "Can't get toolchain name")));
        let addr = try!(self.remote_endpoint(&name)
            .ok_or(Error::new(ErrorKind::Other, "Can't find helper for toolchain")));

        assert!(task.input_precompiled.is_none());
        assert!(task.output_precompiled.is_none());

        // Connect to builder.
        let mut ostream = try!(TcpStream::connect(addr));
        let mut istream = BufReader::new(ostream.try_clone().unwrap());

        // Send compilation request.
        let request = CompileRequest {
            toolchain: name.clone(),
            args: task.args.clone(),
            preprocessed: (&task.preprocessed).into(),
            precompiled: None,
        };
        try!(request.stream_write(&mut ostream, &mut message::Builder::new_default()));
        drop(request);

        // Receive compilation result.
        CompileResponse::stream_read(&mut istream, ::capnp::message::ReaderOptions::new())
            .map_err(|e| Error::new(ErrorKind::InvalidData, e))
            .and_then(|result| {
                match result {
                    CompileResponse::Success(ref output, ref content) => {
                        try!(write_output(&task.output_object, output.success(), content));
                    }
                    _ => {}
                }
                Ok(result)
            })
    }

    fn builders(&self) -> Arc<Vec<BuilderInfo>> {
        let now = time::get_time();
        {
            let holder = self.shared.read().unwrap();
            if holder.cooldown >= now {
                return holder.builders.clone();
            }
        }
        {
            let mut holder = self.shared.write().unwrap();
            if holder.cooldown >= now {
                return holder.builders.clone();
            }
            match holder.receive_builders() {
                Ok(builders) => {
                    holder.builders = Arc::new(builders);
                    holder.cooldown = now + Duration::seconds(5);
                }
                Err(e) => {
                    holder.cooldown = now + Duration::seconds(1);
                    warn!("Can't receive toolchains from coordinator: {}", e);
                }
            }
            return holder.builders.clone();
        }
    }
    // Resolve toolchain for command execution.
    fn remote_endpoint(&self, toolchain_name: &str) -> Option<SocketAddr> {
        let name = toolchain_name.to_string();
        let all_builders = self.builders();
        get_random_builder(&all_builders, |b| b.toolchains.contains(&name))
            .and_then(|builder| SocketAddr::from_str(&builder.endpoint).ok())
    }
}

impl Toolchain for RemoteToolchain {
    fn identifier(&self) -> Option<String> {
        self.local.identifier()
    }

    // Parse compiler arguments.
    fn create_task(&self, command: CommandInfo, args: &[String]) -> Result<Option<CompilationTask>, String> {
        self.local.create_task(command, args)
    }

    // Preprocessing source file.
    fn preprocess_step(&self, task: &CompilationTask) -> Result<PreprocessResult, Error> {
        self.local.preprocess_step(task)
    }

    // Compile preprocessed file.
    fn compile_prepare_step(&self, task: CompilationTask, preprocessed: MemStream) -> Result<CompileStep, Error> {
        self.local.compile_prepare_step(task, preprocessed)
    }

    fn compile_step(&self, task: CompileStep) -> Result<OutputInfo, Error> {
        match self.compile_remote(&task) {
            Ok(response) => {
                match response {
                    CompileResponse::Success(output, _) => Ok(output),
                    CompileResponse::Err(err) => Err(err),
                }
            }
            Err(e) => {
                trace!("Fallback to local build: {}", e);
                self.local.compile_step(task)
            }
        }
    }
}

fn write_output(path: &Option<PathBuf>, success: bool, output: &[u8]) -> Result<(), Error> {
    match path {
        &Some(ref path) => {
            match success {
                true => {
                    File::create(path)
                        .and_then(|mut f| f.write(&output))
                        .or_else(|e| {
                            drop(fs::remove_file(path));
                            Err(e)
                        })
                        .map(|_| ())
                }
                false => fs::remove_file(path),
            }
        }
        &None => Ok(()),
    }
}

fn get_random_builder<F: Fn(&BuilderInfo) -> bool>(builders: &Vec<BuilderInfo>, filter: F) -> Option<&BuilderInfo> {
    let filtered: Vec<&BuilderInfo> = builders.iter().filter(|b| filter(b)).collect();
    if filtered.len() > 0 {
        Some(filtered[rand::random::<usize>() % filtered.len()].clone())
    } else {
        None
    }
}
<commit_msg>Make precompiled header compilation local only<commit_after>use capnp::message;
use hyper::{Client, Url};
use rand;
use rustc_serialize::json;
use time;
use time::{Duration, Timespec};

use ::io::memstream::MemStream;
use ::cluster::common::{BuilderInfo, RPC_BUILDER_LIST};
use ::cluster::builder::{CompileRequest, CompileResponse};
use ::compiler::{CommandInfo, CompilationTask, CompileStep, Compiler, OutputInfo, PreprocessResult, Toolchain};

use std::fs;
use std::fs::File;
use std::io::{BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::{Arc, RwLock};
use std::net::{SocketAddr, TcpStream};

pub struct RemoteCompiler<C: Compiler> {
    shared: Arc<RwLock<RemoteShared>>,
    local: C,
}

struct RemoteShared {
    base_url: Option<Url>,
    cooldown: Timespec,
    builders: Arc<Vec<BuilderInfo>>,
}

struct RemoteToolchain {
    shared: Arc<RwLock<RemoteShared>>,
    local: Arc<Toolchain>,
}

impl<C: Compiler> RemoteCompiler<C> {
    pub fn new(base_url: &Option<Url>, compiler: C) -> Self {
        RemoteCompiler {
            shared: Arc::new(RwLock::new(RemoteShared {
                cooldown: Timespec { sec: 0, nsec: 0 },
                builders: Arc::new(Vec::new()),
                base_url: base_url.as_ref().map(|u| u.clone()),
            })),
            local: compiler,
        }
    }
}

impl RemoteShared {
    fn receive_builders(&self) -> Result<Vec<BuilderInfo>, Error> {
        match &self.base_url {
            &Some(ref base_url) => {
                let client = Client::new();
                client.get(base_url.join(RPC_BUILDER_LIST).unwrap())
                    .send()
                    .map_err(|e| Error::new(ErrorKind::Other, e))
                    .and_then(|mut response| {
                        let mut payload = String::new();
                        response.read_to_string(&mut payload).map(|_| payload)
                    })
                    .and_then(|payload| json::decode(&payload).map_err(|e| Error::new(ErrorKind::InvalidData, e)))
            }
            &None => Ok(Vec::new()),
        }
    }
}

impl<C: Compiler> Compiler for RemoteCompiler<C> {
    // Discovery local toolchains.
    fn discovery_toolchains(&self) -> Vec<Arc<Toolchain>> {
        self.local.discovery_toolchains()
    }

    // Resolve toolchain for command execution.
    fn resolve_toolchain(&self, command: &CommandInfo) -> Option<Arc<Toolchain>> {
        self.local
            .resolve_toolchain(command)
            .map(|local| -> Arc<Toolchain> {
                Arc::new(RemoteToolchain {
                    shared: self.shared.clone(),
                    local: local,
                })
            })
    }
}

impl RemoteToolchain {
    fn compile_remote(&self, task: &CompileStep) -> Result<CompileResponse, Error> {
        let name = try!(self.identifier().ok_or(Error::new(ErrorKind::Other, "Can't get toolchain name")));
        let addr = try!(self.remote_endpoint(&name)
            .ok_or(Error::new(ErrorKind::Other, "Can't find helper for toolchain")));
        if task.output_precompiled.is_some() {
            return Err(Error::new(ErrorKind::Other,
                                  "Remote precompiled header generation is not supported"));
        }

        assert!(task.input_precompiled.is_none());

        // Connect to builder.
        let mut ostream = try!(TcpStream::connect(addr));
        let mut istream = BufReader::new(ostream.try_clone().unwrap());

        // Send compilation request.
        let request = CompileRequest {
            toolchain: name.clone(),
            args: task.args.clone(),
            preprocessed: (&task.preprocessed).into(),
            precompiled: None,
        };
        try!(request.stream_write(&mut ostream, &mut message::Builder::new_default()));
        drop(request);

        // Receive compilation result.
        CompileResponse::stream_read(&mut istream, ::capnp::message::ReaderOptions::new())
            .map_err(|e| Error::new(ErrorKind::InvalidData, e))
            .and_then(|result| {
                match result {
                    CompileResponse::Success(ref output, ref content) => {
                        try!(write_output(&task.output_object, output.success(), content));
                    }
                    _ => {}
                }
                Ok(result)
            })
    }

    fn builders(&self) -> Arc<Vec<BuilderInfo>> {
        let now = time::get_time();
        {
            let holder = self.shared.read().unwrap();
            if holder.cooldown >= now {
                return holder.builders.clone();
            }
        }
        {
            let mut holder = self.shared.write().unwrap();
            if holder.cooldown >= now {
                return holder.builders.clone();
            }
            match holder.receive_builders() {
                Ok(builders) => {
                    holder.builders = Arc::new(builders);
                    holder.cooldown = now + Duration::seconds(5);
                }
                Err(e) => {
                    holder.cooldown = now + Duration::seconds(1);
                    warn!("Can't receive toolchains from coordinator: {}", e);
                }
            }
            return holder.builders.clone();
        }
    }
    // Resolve toolchain for command execution.
    fn remote_endpoint(&self, toolchain_name: &str) -> Option<SocketAddr> {
        let name = toolchain_name.to_string();
        let all_builders = self.builders();
        get_random_builder(&all_builders, |b| b.toolchains.contains(&name))
            .and_then(|builder| SocketAddr::from_str(&builder.endpoint).ok())
    }
}

impl Toolchain for RemoteToolchain {
    fn identifier(&self) -> Option<String> {
        self.local.identifier()
    }

    // Parse compiler arguments.
    fn create_task(&self, command: CommandInfo, args: &[String]) -> Result<Option<CompilationTask>, String> {
        self.local.create_task(command, args)
    }

    // Preprocessing source file.
    fn preprocess_step(&self, task: &CompilationTask) -> Result<PreprocessResult, Error> {
        self.local.preprocess_step(task)
    }

    // Compile preprocessed file.
    fn compile_prepare_step(&self, task: CompilationTask, preprocessed: MemStream) -> Result<CompileStep, Error> {
        self.local.compile_prepare_step(task, preprocessed)
    }

    fn compile_step(&self, task: CompileStep) -> Result<OutputInfo, Error> {
        match self.compile_remote(&task) {
            Ok(response) => {
                match response {
                    CompileResponse::Success(output, _) => Ok(output),
                    CompileResponse::Err(err) => Err(err),
                }
            }
            Err(e) => {
                trace!("Fallback to local build: {}", e);
                self.local.compile_step(task)
            }
        }
    }
}

fn write_output(path: &Option<PathBuf>, success: bool, output: &[u8]) -> Result<(), Error> {
    match path {
        &Some(ref path) => {
            match success {
                true => {
                    File::create(path)
                        .and_then(|mut f| f.write(&output))
                        .or_else(|e| {
                            drop(fs::remove_file(path));
                            Err(e)
                        })
                        .map(|_| ())
                }
                false => fs::remove_file(path),
            }
        }
        &None => Ok(()),
    }
}

fn get_random_builder<F: Fn(&BuilderInfo) -> bool>(builders: &Vec<BuilderInfo>, filter: F) -> Option<&BuilderInfo> {
    let filtered: Vec<&BuilderInfo> = builders.iter().filter(|b| filter(b)).collect();
    if filtered.len() > 0 {
        Some(filtered[rand::random::<usize>() % filtered.len()].clone())
    } else {
        None
    }
}
<|endoftext|>


<commit_before>//! Checks for if expressions that contain only an if expression.
//!
//! For example, the lint would catch:
//!
//! ```
//! if x {
//!     if y {
//!         println!("Hello world");
//!     }
//! }
//! ```
//!
//! This lint is **warn** by default

use rustc::plugin::Registry;
use rustc::lint::*;
use rustc::middle::def::*;
use syntax::ast::*;
use syntax::ptr::P;
use syntax::codemap::{Span, Spanned, ExpnInfo};
use syntax::print::pprust::{block_to_string, expr_to_string};
use utils::{in_macro, span_help_and_lint};

declare_lint! {
    pub COLLAPSIBLE_IF,
    Warn,
    "Warn on if expressions that can be collapsed"
}

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

impl LintPass for CollapsibleIf {
    fn get_lints(&self) -> LintArray {
        lint_array!(COLLAPSIBLE_IF)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        cx.sess().codemap().with_expn_info(expr.span.expn_id,
            |info| check_expr_expd(cx, expr, info))
    }
}

fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) {
    if in_macro(cx, info) { return; }

    if let ExprIf(ref check, ref then, None) = e.node {
        if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), ..}) =
            single_stmt_of_block(then) {
                span_help_and_lint(cx, COLLAPSIBLE_IF, e.span,
                    "this if statement can be collapsed",
                    &format!("try\nif {} && {} {}",
                             check_to_string(check), check_to_string(check_inner),
                             block_to_string(&*content)));
            }
    }
}

fn requires_brackets(e: &Expr) -> bool {
    match e.node {
        ExprBinary(Spanned {node: n, ..}, _, _) if n == BiEq => false,
        _ => true
    }
}

fn check_to_string(e: &Expr) -> String {
    if requires_brackets(e) {
        format!("({})", expr_to_string(e))
    } else {
        format!("{}", expr_to_string(e))
    }
}

fn single_stmt_of_block(block: &Block) -> Option<&Expr> {
    if block.stmts.len() == 1 && block.expr.is_none() {
        if let StmtExpr(ref expr, _) = block.stmts[0].node {
            single_stmt_of_expr(expr)
        } else { None }
    } else {
        if block.stmts.is_empty() {
            if let Some(ref p) = block.expr { Some(&*p) } else { None }
        } else { None }
    }
}

fn single_stmt_of_expr(expr: &Expr) -> Option<&Expr> {
    if let ExprBlock(ref block) = expr.node {
        single_stmt_of_block(block)
    } else { Some(expr) }
}
<commit_msg>Use snippet, pprust methods expand AST<commit_after>//! Checks for if expressions that contain only an if expression.
//!
//! For example, the lint would catch:
//!
//! ```
//! if x {
//!     if y {
//!         println!("Hello world");
//!     }
//! }
//! ```
//!
//! This lint is **warn** by default

use rustc::plugin::Registry;
use rustc::lint::*;
use rustc::middle::def::*;
use syntax::ast::*;
use syntax::ptr::P;
use syntax::codemap::{Span, Spanned, ExpnInfo};
use utils::{in_macro, span_help_and_lint, snippet};

declare_lint! {
    pub COLLAPSIBLE_IF,
    Warn,
    "Warn on if expressions that can be collapsed"
}

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

impl LintPass for CollapsibleIf {
    fn get_lints(&self) -> LintArray {
        lint_array!(COLLAPSIBLE_IF)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        cx.sess().codemap().with_expn_info(expr.span.expn_id,
            |info| check_expr_expd(cx, expr, info))
    }
}

fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) {
    if in_macro(cx, info) { return; }

    if let ExprIf(ref check, ref then, None) = e.node {
        if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), ..}) =
            single_stmt_of_block(then) {
                span_help_and_lint(cx, COLLAPSIBLE_IF, e.span,
                    "this if statement can be collapsed",
                    &format!("try\nif {} && {} {}",
                             check_to_string(cx, check), check_to_string(cx, check_inner),
                             snippet(cx, content.span, "..")));
            }
    }
}

fn requires_brackets(e: &Expr) -> bool {
    match e.node {
        ExprBinary(Spanned {node: n, ..}, _, _) if n == BiEq => false,
        _ => true
    }
}

fn check_to_string(cx: &Context, e: &Expr) -> String {
    if requires_brackets(e) {
        format!("({})", snippet(cx, e.span, ".."))
    } else {
        format!("{}", snippet(cx, e.span, ".."))
    }
}

fn single_stmt_of_block(block: &Block) -> Option<&Expr> {
    if block.stmts.len() == 1 && block.expr.is_none() {
        if let StmtExpr(ref expr, _) = block.stmts[0].node {
            single_stmt_of_expr(expr)
        } else { None }
    } else {
        if block.stmts.is_empty() {
            if let Some(ref p) = block.expr { Some(&*p) } else { None }
        } else { None }
    }
}

fn single_stmt_of_expr(expr: &Expr) -> Option<&Expr> {
    if let ExprBlock(ref block) = expr.node {
        single_stmt_of_block(block)
    } else { Some(expr) }
}
<|endoftext|>


<commit_before>// Copyright (c) 2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use super::*;
use crate::test_encode_decode::{compare_plane, DecodeResult, TestDecoder};
use crate::util::{CastFromPrimitive, Pixel};
use std::collections::VecDeque;
use std::marker::PhantomData;
use std::{mem::MaybeUninit, ptr, slice};

use dav1d_sys::*;

pub(crate) struct Dav1dDecoder<T: Pixel> {
  dec: *mut Dav1dContext,
  pixel: PhantomData<T>,
}

impl<T: Pixel> TestDecoder<T> for Dav1dDecoder<T> {
  fn setup_decoder(_w: usize, _h: usize) -> Self {
    unsafe {
      let mut settings = MaybeUninit::init().assume_init();
      let mut dec: Dav1dDecoder<T> = MaybeUninit::init().assume_init();

      dav1d_default_settings(&mut settings);

      let ret = dav1d_open(&mut dec.dec, &settings);

      if ret != 0 {
        panic!("Cannot instantiate the decoder {}", ret);
      }

      dec
    }
  }

  fn decode_packet(
    &mut self, packet: &[u8], rec_fifo: &mut VecDeque<Frame<T>>, w: usize,
    h: usize, bit_depth: usize,
  ) -> DecodeResult {
    let mut corrupted_count = 0;
    unsafe {
      let mut data: Dav1dData = mem::zeroed();
      let ptr = dav1d_data_create(&mut data, packet.len());
      ptr::copy_nonoverlapping(packet.as_ptr(), ptr, packet.len());
      let ret = dav1d_send_data(self.dec, &mut data);
      println!("Decoded. -> {}", ret);
      if ret != 0 {
        corrupted_count += 1;
      }

      if ret == 0 {
        loop {
          let mut pic: Dav1dPicture = mem::zeroed();
          println!("Retrieving frame");
          let ret = dav1d_get_picture(self.dec, &mut pic);
          println!("Retrieved.");
          if ret == -(EAGAIN as i32) {
            return DecodeResult::Done;
          }
          if ret != 0 {
            panic!("Decode fail");
          }

          let rec = rec_fifo.pop_front().unwrap();
          compare_pic(&pic, &rec, bit_depth, w, h);
        }
      }
    }
    if corrupted_count > 0 {
      DecodeResult::Corrupted(corrupted_count)
    } else {
      DecodeResult::NotDone
    }
  }
}

impl<T: Pixel> Drop for Dav1dDecoder<T> {
  fn drop(&mut self) {
    unsafe { dav1d_close(&mut self.dec) };
  }
}

fn compare_pic<T: Pixel>(
  pic: &Dav1dPicture, frame: &Frame<T>, bit_depth: usize, width: usize,
  height: usize,
) {
  use crate::frame::Plane;

  let cmp_plane = |data, stride, frame_plane: &Plane<T>| {
    let w = width >> frame_plane.cfg.xdec;
    let h = height >> frame_plane.cfg.ydec;
    let rec_stride = frame_plane.cfg.stride;

    if bit_depth > 8 {
      let stride = stride / 2;
      let dec = unsafe {
        let data = data as *const u16;
        let size = stride * h;

        slice::from_raw_parts(data, size)
      };

      let rec: Vec<u16> =
        frame_plane.data_origin().iter().map(|&v| u16::cast_from(v)).collect();

      compare_plane::<u16>(&rec[..], rec_stride, dec, stride, w, h);
    } else {
      let dec = unsafe {
        let data = data as *const u8;
        let size = stride * h;

        slice::from_raw_parts(data, size)
      };

      let rec: Vec<u8> =
        frame_plane.data_origin().iter().map(|&v| u8::cast_from(v)).collect();

      compare_plane::<u8>(&rec[..], rec_stride, dec, stride, w, h);
    }
  };

  let lstride = pic.stride[0] as usize;
  let cstride = pic.stride[1] as usize;

  cmp_plane(pic.data[0], lstride, &frame.planes[0]);
  cmp_plane(pic.data[1], cstride, &frame.planes[1]);
  cmp_plane(pic.data[2], cstride, &frame.planes[2]);
}
<commit_msg>Fix dav1d test building<commit_after>// Copyright (c) 2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use super::*;
use crate::test_encode_decode::{compare_plane, DecodeResult, TestDecoder};
use crate::util::{CastFromPrimitive, Pixel};
use std::collections::VecDeque;
use std::marker::PhantomData;
use std::{
  mem::{self, MaybeUninit},
  ptr, slice,
};

use dav1d_sys::*;

pub(crate) struct Dav1dDecoder<T: Pixel> {
  dec: *mut Dav1dContext,
  pixel: PhantomData<T>,
}

impl<T: Pixel> TestDecoder<T> for Dav1dDecoder<T> {
  fn setup_decoder(_w: usize, _h: usize) -> Self {
    unsafe {
      let mut settings = MaybeUninit::uninit().assume_init();
      let mut dec: Dav1dDecoder<T> = MaybeUninit::uninit().assume_init();

      dav1d_default_settings(&mut settings);

      let ret = dav1d_open(&mut dec.dec, &settings);

      if ret != 0 {
        panic!("Cannot instantiate the decoder {}", ret);
      }

      dec
    }
  }

  fn decode_packet(
    &mut self, packet: &[u8], rec_fifo: &mut VecDeque<Frame<T>>, w: usize,
    h: usize, bit_depth: usize,
  ) -> DecodeResult {
    let mut corrupted_count = 0;
    unsafe {
      let mut data: Dav1dData = mem::zeroed();
      let ptr = dav1d_data_create(&mut data, packet.len());
      ptr::copy_nonoverlapping(packet.as_ptr(), ptr, packet.len());
      let ret = dav1d_send_data(self.dec, &mut data);
      println!("Decoded. -> {}", ret);
      if ret != 0 {
        corrupted_count += 1;
      }

      if ret == 0 {
        loop {
          let mut pic: Dav1dPicture = mem::zeroed();
          println!("Retrieving frame");
          let ret = dav1d_get_picture(self.dec, &mut pic);
          println!("Retrieved.");
          if ret == -(EAGAIN as i32) {
            return DecodeResult::Done;
          }
          if ret != 0 {
            panic!("Decode fail");
          }

          let rec = rec_fifo.pop_front().unwrap();
          compare_pic(&pic, &rec, bit_depth, w, h);
        }
      }
    }
    if corrupted_count > 0 {
      DecodeResult::Corrupted(corrupted_count)
    } else {
      DecodeResult::NotDone
    }
  }
}

impl<T: Pixel> Drop for Dav1dDecoder<T> {
  fn drop(&mut self) {
    unsafe { dav1d_close(&mut self.dec) };
  }
}

fn compare_pic<T: Pixel>(
  pic: &Dav1dPicture, frame: &Frame<T>, bit_depth: usize, width: usize,
  height: usize,
) {
  use crate::frame::Plane;

  let cmp_plane = |data, stride, frame_plane: &Plane<T>| {
    let w = width >> frame_plane.cfg.xdec;
    let h = height >> frame_plane.cfg.ydec;
    let rec_stride = frame_plane.cfg.stride;

    if bit_depth > 8 {
      let stride = stride / 2;
      let dec = unsafe {
        let data = data as *const u16;
        let size = stride * h;

        slice::from_raw_parts(data, size)
      };

      let rec: Vec<u16> =
        frame_plane.data_origin().iter().map(|&v| u16::cast_from(v)).collect();

      compare_plane::<u16>(&rec[..], rec_stride, dec, stride, w, h);
    } else {
      let dec = unsafe {
        let data = data as *const u8;
        let size = stride * h;

        slice::from_raw_parts(data, size)
      };

      let rec: Vec<u8> =
        frame_plane.data_origin().iter().map(|&v| u8::cast_from(v)).collect();

      compare_plane::<u8>(&rec[..], rec_stride, dec, stride, w, h);
    }
  };

  let lstride = pic.stride[0] as usize;
  let cstride = pic.stride[1] as usize;

  cmp_plane(pic.data[0], lstride, &frame.planes[0]);
  cmp_plane(pic.data[1], cstride, &frame.planes[1]);
  cmp_plane(pic.data[2], cstride, &frame.planes[2]);
}
<|endoftext|>


<commit_before>use error::*;
use super::Command;

use constant::*;
use lib::fs::*;
use lib::io::*;
use lib::setting::*;
use std::collections::BTreeSet;
use std::path::Path;

pub struct Ignore {
    pub command: Option<String>,
    pub paths  : Vec<String>,
}

impl Command for Ignore {
    fn validation(&self) -> bool { true }

    fn usage(&self) -> Usage {
        return Usage::new(UsageKind::Ignore);
    }

    fn main(&self) -> Result<(), CliError> {
        match self.command {
            Some(ref c) => match c.as_ref() {
                "add"     => self.add(),
                "remove"  => self.remove(),
                "current" => Self::ignore_current_files(),
                "clear"   => Self::clear_ignore_file(),
                _         => Err(From::from(self.usage())),
            },
            None => Err(From::from(self.usage())),
        }
    }
}

impl Ignore {
    fn add(&self) -> Result<(), CliError> {
        let paths = &self.paths;

        if paths.len() == 0 {
            return Err(From::from(self.usage()));
        }

        print_with_tag(0, Tag::Execution, format!("Confirm files to be added to \"{}\"", IGNORE_FILE_NAME));

        let ignores_to_be_added = paths
            .iter()
            .map(append_prefix_if_need)
            .filter(|p| Path::new(p).is_file())
            .collect::<BTreeSet<String>>();

        for file in &ignores_to_be_added {
            print_with_tag(1, Tag::Info, format!("\"{}\" will be ignored", file));
        }

        let original_ignores = try!(read_ignore_file());

        let new_ignores = original_ignores
            .union(&ignores_to_be_added)
            .fold(String::new(), |c, ref f| c + f + "\n");

        print_with_tag(0, Tag::Execution, format!("Recreate \"{}\" file", IGNORE_FILE_NAME));

        try!(create_ignore_file(new_ignores));

        Ok(())
    }

    fn remove(&self) -> Result<(), CliError> {
        let paths = &self.paths;

        if paths.len() == 0 {
            return Err(From::from(self.usage()));
        }

        let ignores_to_be_removed = paths
            .iter()
            .map(append_prefix_if_need)
            .collect::<BTreeSet<String>>();

        for file in &ignores_to_be_removed {
            print_with_tag(1, Tag::Info, format!("\"{}\" will not be ignored", file));
        }

        let original_ignores = try!(read_ignore_file());

        let new_ignores = original_ignores
            .difference(&ignores_to_be_removed)
            .fold(String::new(), |c, ref f| c + f + "\n");

        print_with_tag(0, Tag::Execution, format!("Recreate \"{}\" file", IGNORE_FILE_NAME));

        try!(create_ignore_file(new_ignores));

        Ok(())
    }

    fn ignore_current_files() -> Result<(), CliError> {
        println!("do current command");

        Ok(())
    }

    fn clear_ignore_file() -> Result<(), CliError> {
        println!("do clear command");

        Ok(())
    }
}
<commit_msg>[Remedy] Output the message<commit_after>use error::*;
use super::Command;

use constant::*;
use lib::fs::*;
use lib::io::*;
use lib::setting::*;
use std::collections::BTreeSet;
use std::path::Path;

pub struct Ignore {
    pub command: Option<String>,
    pub paths  : Vec<String>,
}

impl Command for Ignore {
    fn validation(&self) -> bool { true }

    fn usage(&self) -> Usage {
        return Usage::new(UsageKind::Ignore);
    }

    fn main(&self) -> Result<(), CliError> {
        match self.command {
            Some(ref c) => match c.as_ref() {
                "add"     => self.add(),
                "remove"  => self.remove(),
                "current" => Self::ignore_current_files(),
                "clear"   => Self::clear_ignore_file(),
                _         => Err(From::from(self.usage())),
            },
            None => Err(From::from(self.usage())),
        }
    }
}

impl Ignore {
    fn add(&self) -> Result<(), CliError> {
        let paths = &self.paths;

        if paths.len() == 0 {
            return Err(From::from(self.usage()));
        }

        print_with_tag(0, Tag::Execution, format!("Confirm files to be added to \"{}\"", IGNORE_FILE_NAME));

        let ignores_to_be_added = paths
            .iter()
            .map(append_prefix_if_need)
            .filter(|p| Path::new(p).is_file())
            .collect::<BTreeSet<String>>();

        for file in &ignores_to_be_added {
            print_with_tag(1, Tag::Info, format!("\"{}\" will be ignored", file));
        }

        let original_ignores = try!(read_ignore_file());

        let new_ignores = original_ignores
            .union(&ignores_to_be_added)
            .fold(String::new(), |c, ref f| c + f + "\n");

        print_with_tag(0, Tag::Execution, format!("Recreate \"{}\" file", IGNORE_FILE_NAME));

        try!(create_ignore_file(new_ignores));

        Ok(())
    }

    fn remove(&self) -> Result<(), CliError> {
        let paths = &self.paths;

        if paths.len() == 0 {
            return Err(From::from(self.usage()));
        }

        print_with_tag(0, Tag::Execution, format!("Confirm files to be removed from \"{}\"", IGNORE_FILE_NAME));

        let ignores_to_be_removed = paths
            .iter()
            .map(append_prefix_if_need)
            .collect::<BTreeSet<String>>();

        for file in &ignores_to_be_removed {
            print_with_tag(1, Tag::Info, format!("\"{}\" will not be ignored", file));
        }

        let original_ignores = try!(read_ignore_file());

        let new_ignores = original_ignores
            .difference(&ignores_to_be_removed)
            .fold(String::new(), |c, ref f| c + f + "\n");

        print_with_tag(0, Tag::Execution, format!("Recreate \"{}\" file", IGNORE_FILE_NAME));

        try!(create_ignore_file(new_ignores));

        Ok(())
    }

    fn ignore_current_files() -> Result<(), CliError> {
        println!("do current command");

        Ok(())
    }

    fn clear_ignore_file() -> Result<(), CliError> {
        println!("do clear command");

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


<commit_before>use alloc::boxed::*;

use core::ptr;

use common::memory::*;
use common::paging::*;
use common::scheduler::*;
use common::vec::*;

use syscall::call::sys_exit;

pub const CONTEXT_STACK_SIZE: usize = 1024*1024;

pub static mut contexts_ptr: *mut Box<Vec<Context>> = 0 as *mut Box<Vec<Context>>;
pub static mut context_i: usize = 0;

pub unsafe extern "cdecl" fn context_box(box_fn_ptr: usize){
    let box_fn = ptr::read(box_fn_ptr as *mut Box<FnBox()>);
    unalloc(box_fn_ptr);
    box_fn();
}

pub unsafe extern "cdecl" fn context_exit() -> !{
    loop {
        sys_exit();
    }
}

pub struct Context {
    pub stack: usize,
    pub stack_ptr: u32,
    pub fx: usize,
    pub physical_address: usize,
    pub virtual_address: usize,
    pub virtual_size: usize

}

impl Context {
    pub unsafe fn root() -> Context {
        let ret = Context {
            stack: 0,
            stack_ptr: 0,
            fx: alloc(512),
            physical_address: 0,
            virtual_address: 0,
            virtual_size: 0
        };

        for i in 0..512 {
            ptr::write((ret.fx + i) as *mut u8, 0);
        }

        return ret;
    }

    pub unsafe fn new(call: usize, args: &Vec<usize>) -> Context {
        let stack = alloc(CONTEXT_STACK_SIZE);

        let mut ret = Context {
            stack: stack,
            stack_ptr: (stack + CONTEXT_STACK_SIZE) as u32,
            fx: alloc(512),
            physical_address: 0,
            virtual_address: 0,
            virtual_size: 0
        };

        let ebp = ret.stack_ptr;

        for arg in args.iter() {
            ret.push(*arg as u32);
        }

        ret.push(context_exit as u32); //If the function call returns, we will exit
        ret.push(call as u32); //We will ret into this function call

        ret.push(0); //ESI is a param used in the switch function

        ret.push(1 << 9); //Flags

        let esp = ret.stack_ptr;

        ret.push(0); //EAX
        ret.push(0); //ECX
        ret.push(0); //EDX
        ret.push(0); //EBX
        ret.push(esp); //ESP (ignored)
        ret.push(ebp); //EBP
        ret.push(0); //ESI
        ret.push(0); //EDI

        for i in 0..512 {
            ptr::write((ret.fx + i) as *mut u8, 0);
        }

        return ret;
    }

    pub fn spawn(box_fn: Box<FnBox()>) {
        unsafe{
            let box_fn_ptr: *mut Box<FnBox()> = alloc_type();
            ptr::write(box_fn_ptr, box_fn);

            let mut context_box_args: Vec<usize> = Vec::new();
            context_box_args.push(box_fn_ptr as usize);

            let reenable = start_no_ints();
            if contexts_ptr as usize > 0 {
                (*contexts_ptr).push(Context::new(context_box as usize, &context_box_args));
            }
            end_no_ints(reenable);
        }
    }

    pub unsafe fn push(&mut self, data: u32){
        self.stack_ptr -= 4;
        *(self.stack_ptr as *mut u32) = data;
    }

    pub unsafe fn map(&mut self){
        for i in 0..(self.virtual_size + 4095)/4096 {
            set_page(self.virtual_address + i*4096, self.physical_address + i*4096);
        }
    }

    pub unsafe fn unmap(&mut self){
        for i in 0..(self.virtual_size + 4095)/4096 {
            identity_page(self.virtual_address + i*4096);
        }
    }

    pub unsafe fn remap(&mut self, other: &mut Context){
        self.unmap();
        other.map();
    }

    //Warning: This function MUST be inspected in disassembly for correct push/pop
    //It should have exactly one extra push/pop of ESI
    #[cold]
    #[inline(never)]
    pub unsafe fn switch(&mut self, other: &mut Context){
        asm!("pushfd
            pushad
            mov [esi], esp"
            :
            : "{esi}"(&mut self.stack_ptr)
            : "memory"
            : "intel", "volatile");
        /*
        asm!("fxsave [esi]"
            :
            : "{esi}"(self.fx)
            : "memory"
            : "intel", "volatile");
        asm!("fxrstor [esi]"
            :
            : "{esi}"(other.fx)
            : "memory"
            : "intel", "volatile");
        */
        asm!("mov esp, [esi]
            popad
            popfd"
            :
            : "{esi}"(&mut other.stack_ptr)
            : "memory"
            : "intel", "volatile");
    }
}

impl Drop for Context {
    fn drop(&mut self){
        if self.stack > 0 {
            unsafe {
                unalloc(self.stack);
            }
        }

        if self.fx > 0 {
            unsafe {
                unalloc(self.fx);
            }
        }
    }
}
<commit_msg>FXsave/FXrstor<commit_after>use alloc::boxed::*;

use core::ptr;

use common::memory::*;
use common::paging::*;
use common::scheduler::*;
use common::vec::*;

use syscall::call::sys_exit;

pub const CONTEXT_STACK_SIZE: usize = 1024*1024;

pub static mut contexts_ptr: *mut Box<Vec<Context>> = 0 as *mut Box<Vec<Context>>;
pub static mut context_i: usize = 0;

pub unsafe extern "cdecl" fn context_box(box_fn_ptr: usize){
    let box_fn = ptr::read(box_fn_ptr as *mut Box<FnBox()>);
    unalloc(box_fn_ptr);
    box_fn();
}

pub unsafe extern "cdecl" fn context_exit() -> !{
    loop {
        sys_exit();
    }
}

pub struct Context {
    pub stack: usize,
    pub stack_ptr: u32,
    pub fx: usize,
    pub physical_address: usize,
    pub virtual_address: usize,
    pub virtual_size: usize

}

impl Context {
    pub unsafe fn root() -> Context {
        let ret = Context {
            stack: 0,
            stack_ptr: 0,
            fx: alloc(512),
            physical_address: 0,
            virtual_address: 0,
            virtual_size: 0
        };

        for i in 0..512 {
            ptr::write((ret.fx + i) as *mut u8, 0);
        }

        return ret;
    }

    pub unsafe fn new(call: usize, args: &Vec<usize>) -> Context {
        let stack = alloc(CONTEXT_STACK_SIZE);

        let mut ret = Context {
            stack: stack,
            stack_ptr: (stack + CONTEXT_STACK_SIZE) as u32,
            fx: alloc(512),
            physical_address: 0,
            virtual_address: 0,
            virtual_size: 0
        };

        let ebp = ret.stack_ptr;

        for arg in args.iter() {
            ret.push(*arg as u32);
        }

        ret.push(context_exit as u32); //If the function call returns, we will exit
        ret.push(call as u32); //We will ret into this function call

        ret.push(0); //ESI is a param used in the switch function

        ret.push(1 << 9); //Flags

        let esp = ret.stack_ptr;

        ret.push(0); //EAX
        ret.push(0); //ECX
        ret.push(0); //EDX
        ret.push(0); //EBX
        ret.push(esp); //ESP (ignored)
        ret.push(ebp); //EBP
        ret.push(0); //ESI
        ret.push(0); //EDI

        for i in 0..512 {
            ptr::write((ret.fx + i) as *mut u8, 0);
        }

        return ret;
    }

    pub fn spawn(box_fn: Box<FnBox()>) {
        unsafe{
            let box_fn_ptr: *mut Box<FnBox()> = alloc_type();
            ptr::write(box_fn_ptr, box_fn);

            let mut context_box_args: Vec<usize> = Vec::new();
            context_box_args.push(box_fn_ptr as usize);

            let reenable = start_no_ints();
            if contexts_ptr as usize > 0 {
                (*contexts_ptr).push(Context::new(context_box as usize, &context_box_args));
            }
            end_no_ints(reenable);
        }
    }

    pub unsafe fn push(&mut self, data: u32){
        self.stack_ptr -= 4;
        *(self.stack_ptr as *mut u32) = data;
    }

    pub unsafe fn map(&mut self){
        for i in 0..(self.virtual_size + 4095)/4096 {
            set_page(self.virtual_address + i*4096, self.physical_address + i*4096);
        }
    }

    pub unsafe fn unmap(&mut self){
        for i in 0..(self.virtual_size + 4095)/4096 {
            identity_page(self.virtual_address + i*4096);
        }
    }

    pub unsafe fn remap(&mut self, other: &mut Context){
        self.unmap();
        other.map();
    }

    //Warning: This function MUST be inspected in disassembly for correct push/pop
    //It should have exactly one extra push/pop of ESI
    #[cold]
    #[inline(never)]
    pub unsafe fn switch(&mut self, other: &mut Context){
        asm!("pushfd
            pushad
            mov [esi], esp"
            :
            : "{esi}"(&mut self.stack_ptr)
            : "memory"
            : "intel", "volatile");

        asm!("fxsave [esi]"
            :
            : "{esi}"(self.fx)
            : "memory"
            : "intel", "volatile");

        asm!("fxrstor [esi]"
            :
            : "{esi}"(other.fx)
            : "memory"
            : "intel", "volatile");

        asm!("mov esp, [esi]
            popad
            popfd"
            :
            : "{esi}"(&mut other.stack_ptr)
            : "memory"
            : "intel", "volatile");
    }
}

impl Drop for Context {
    fn drop(&mut self){
        if self.stack > 0 {
            unsafe {
                unalloc(self.stack);
            }
        }

        if self.fx > 0 {
            unsafe {
                unalloc(self.fx);
            }
        }
    }
}
<|endoftext|>


<commit_before>/******************************************************************************
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0.  If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is: RustyMem
 * The Initial Developer of the Original Code is: William Wong (williamw520@gmail.com)
 * Portions created by William Wong are Copyright (C) 2013 William Wong, All Rights Reserved.
 *
 ******************************************************************************/

use std::rt::io::net::ip::IpAddr;
use std::rt::io::net::ip::Ipv4Addr;
use std::rt::io::net::ip::SocketAddr;

use super::strutil;

/// Parse the "host:port" string, with support for default_port.
pub fn to_host_port(host_port_str: &str, default_port : u16) -> (~str, u16) {
    let tokens = strutil::clean_split(host_port_str, ':');
    match tokens.len() {
        0   => fail!( fmt!("Fail to %?", host_port_str) ),
        1   => (tokens[0].to_owned(), default_port),
        _   => (tokens[0].to_owned(), strutil::to_num(tokens[1], default_port))
    }
}

/// Structure for holding, parsing, and formating hostname and port net address.
pub struct HostAddr {
    /// The hostname or ip address
    host:       ~str,

    /// The port number
    port:       Option<u16>,
}

impl HostAddr {

    pub fn new() -> HostAddr {
        return HostAddr {
            host: "".to_owned(),
            port: None
        };
    }

    /// Create one from host:port string
    pub fn with_host_port(host_port_str: &str, default_port : u16) -> HostAddr {
        let (host, port) = to_host_port(host_port_str, default_port);
        return HostAddr {
            host: host,
            port: Some(port)
        };
    }

    pub fn get_host(&self) -> ~str {
        self.host.clone()
    }

    pub fn get_port(&self) -> u16 {
        match self.port {
            Some(port) => port,
            None => 0
        }
    }

    pub fn get_ip_v4(&self) -> IpAddr {
        let parts = strutil::clean_split(self.host, '.').map(|s| strutil::to_num(*s, 0u8));
        return Ipv4Addr(parts[0], parts[1], parts[2], parts[3]);
    }

    pub fn get_sock_addr(&self) -> SocketAddr {
        return SocketAddr {
                ip: self.get_ip_v4(),
                port: self.get_port()
        };
    }

}

impl ToStr for HostAddr {
    fn to_str(&self) -> ~str {
        match self.port {
            Some(port) => fmt!("%s:%s", self.host, port.to_str()),
            None => self.host.clone(),
        }
    }
}

#[test]
fn test_to_host_port()  {

    println( fmt!("%?", to_host_port("localhost: 9000", 1234)) );
    println( fmt!("%?", to_host_port("localhost:9000", 1234)) );
    println( fmt!("%?", to_host_port(" localhost:9000", 1234)) );
    println( fmt!("%?", to_host_port(" localhost : 9000 ", 1234)) );
    println( fmt!("%?", to_host_port("localhost : 9000 ", 1234)) );
    println( fmt!("%?", to_host_port("localhost ", 1111)) );
    println( fmt!("%?", to_host_port(" localhost ", 2222)) );
    println( fmt!("%?", to_host_port(" localhost: ", 3333)) );
    println( fmt!("%?", to_host_port(" localhost:abc ", 4444)) );

}

<commit_msg>remove netutil<commit_after><|endoftext|>


<commit_before>/* The Wizards' Wallet
 * Written in 2014 by
 *   Andrew Poelstra <apoelstra@wpsoftware.net>
 *
 * To the extent possible under law, the author(s) have dedicated all
 * copyright and related and neighboring rights to this software to
 * the public domain worldwide. This software is distributed without
 * any warranty.
 *
 * You should have received a copy of the CC0 Public Domain Dedication
 * along with this software.
 * If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
 */

//! # RPC Server
//!
//! Functions and data to handle RPC calls

use std::io::IoResult;
use serialize::json;

use bitcoin::network::serialize::Serializable;
use bitcoin::util::hash::Sha256dHash;
use jsonrpc;
use jsonrpc::error::{standard_error, InvalidParams, MethodNotFound};
use phf::PhfOrderedMap;

use bitcoind::IdleState;

pub type JsonResult = jsonrpc::JsonResult<json::Json>;

/// A single RPC command
pub struct RpcCall {
  name: &'static str,
  desc: &'static str,
  usage: &'static str,
  call: fn(&RpcCall, &mut IdleState, Vec<json::Json>) -> JsonResult
}

// Forget you saw this macro...just forget it.
macro_rules! rpc_calls(
  ( $( #[doc=$doc:tt]
       #[usage=$usage:tt]
       pub fn $name:ident($($param:tt: $paramty:ty),+) $code:expr),+ ) => (
    $(
      // `tt` token trees can only be passed to a macro. On the other hand,
      // there is no other type which will accept a doccomment as a token.
      // So we accept a tt and hand it to the macro_rules! macro ;)
      //
      // Notice that we are using the same name as the outer macro...this
      // means that the macro can only be called once, since we effectively
      // overwrite it here.
      macro_rules! rpc_calls( () => (
        // I don't really want these to be public, but they don't show up
        // in the output of `cargo doc` otherwise.
        #[doc=$doc]
        pub fn $name($($param: $paramty),+) -> JsonResult { $code }
      ))
      rpc_calls!()
    )+
    // Let's do it again!
    macro_rules! rpc_calls( () => (
      static RPC_CALLS: PhfOrderedMap<&'static str, RpcCall> = phf_ordered_map! {
        $(stringify!($name) => RpcCall {
            name: stringify!($name),
            desc: $doc,
            usage: $usage,
            call: $name
          }
        ),+
      };
    ))
    rpc_calls!()
    // Erase the dummy macro, to avoid confusing errors in case somebody
    // tries to use it outside of this macro.
    macro_rules! rpc_calls(
      () => (Sorry, you can only call rpc_calls! once.)
    )
  )
)

// Main RPC call list
rpc_calls!{
  #[doc="Fetches a list of commands"]
  #[usage=""]
  pub fn help(_: &RpcCall, _: &mut IdleState, _: Vec<json::Json>) {
    use std::collections::TreeMap;

    let mut ret = TreeMap::new();
    for call in RPC_CALLS.values() {
      let mut obj = TreeMap::new();
      obj.insert("description".to_string(), json::String(call.desc.to_string()));
      obj.insert("usage".to_string(), json::String(call.usage.to_string()));
      ret.insert(call.name.to_string(), json::Object(obj));
    }
    Ok(json::Object(ret))
  },

  #[doc="Gets the current number of unspent outputs on the blockchain."]
  #[usage=""]
  pub fn getutxocount(_: &RpcCall, idle_state: &mut IdleState, _: Vec<json::Json>) {
    Ok(json::Number(idle_state.utxo_set.read().n_utxos() as f64))
  },

  #[doc="Gets the length of the longest chain."]
  #[usage="[start hash]"]
  pub fn getblockcount(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      0 => {
        let blockchain = idle_state.blockchain.read();
        // Subtract 1 from the hash since the genesis counts as block 0
        Ok(json::Number(blockchain.iter(blockchain.genesis_hash()).count() as f64 - 1.0))
      }
      1 => {
        use serialize::hex::FromHex;

        let blockchain = idle_state.blockchain.read();
        let hex_hash = try!(jsonrpc::decode::json_decode_string(&params[0]));
        match hex_hash.as_slice().from_hex() {
          Ok(hash) => {
            // We reverse the iterator since the user will give us a big-endian string,
            // while everything internal is little endian.
            let hash: IoResult<Sha256dHash> = Serializable::deserialize(hash.iter().rev().map(|n| *n));
            match hash {
              // Subtract 1 from the hash since the genesis counts as block 0
              Ok(hash) => Ok(json::Number(blockchain.iter(hash).count() as f64 - 1.0)),
              Err(_) => Err(standard_error(InvalidParams,
                                           Some(json::String(format!("Hash must be 64-character hex string, not {}", hex_hash)))))
            }
          }
          Err(_) => Err(standard_error(InvalidParams,
                                       Some(json::String(format!("Hash must be 64-character hex string, not {}", hex_hash)))))
        }
      }
      _ => usage_error(rpc)
    }
  }
}

/// Generates a `usage` error message
fn usage_error(rpc: &RpcCall) -> JsonResult {
  Err(standard_error(InvalidParams,
                     Some(json::String(format!("Usage: {} {}", rpc.name, rpc.usage)))))
}

/// Handles a JSON-RPC request, returning a result to be given back to the peer
pub fn handle_rpc(request: jsonrpc::Request, idle_state: &mut IdleState) -> JsonResult {
  let method = request.method.as_slice();
  match RPC_CALLS.find_equiv(&method) {
    Some(rpc) => (rpc.call)(rpc, idle_state, request.params),
    None => Err(standard_error(MethodNotFound,
                               Some(json::String(request.method.clone()))))
  }
}

<commit_msg>Add a `getblock` RPC<commit_after>/* The Wizards' Wallet
 * Written in 2014 by
 *   Andrew Poelstra <apoelstra@wpsoftware.net>
 *
 * To the extent possible under law, the author(s) have dedicated all
 * copyright and related and neighboring rights to this software to
 * the public domain worldwide. This software is distributed without
 * any warranty.
 *
 * You should have received a copy of the CC0 Public Domain Dedication
 * along with this software.
 * If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
 */

//! # RPC Server
//!
//! Functions and data to handle RPC calls

use std::collections::TreeMap;
use serialize::json;
use serialize::json::ToJson;

use bitcoin::network::serialize::Serializable;
use bitcoin::util::hash::Sha256dHash;
use jsonrpc;
use jsonrpc::error::{standard_error, Error, InvalidParams, MethodNotFound};
use phf::PhfOrderedMap;

use bitcoind::IdleState;

pub type JsonResult = jsonrpc::JsonResult<json::Json>;

/// A single RPC command
pub struct RpcCall {
  name: &'static str,
  desc: &'static str,
  usage: &'static str,
  call: fn(&RpcCall, &mut IdleState, Vec<json::Json>) -> JsonResult
}

// Forget you saw this macro...just forget it.
macro_rules! rpc_calls(
  ( $( #[doc=$doc:tt]
       #[usage=$usage:tt]
       pub fn $name:ident($($param:tt: $paramty:ty),+) $code:expr),+ ) => (
    $(
      // `tt` token trees can only be passed to a macro. On the other hand,
      // there is no other type which will accept a doccomment as a token.
      // So we accept a tt and hand it to the macro_rules! macro ;)
      //
      // Notice that we are using the same name as the outer macro...this
      // means that the macro can only be called once, since we effectively
      // overwrite it here.
      macro_rules! rpc_calls( () => (
        // I don't really want these to be public, but they don't show up
        // in the output of `cargo doc` otherwise.
        #[doc=$doc]
        pub fn $name($($param: $paramty),+) -> JsonResult { $code }
      ))
      rpc_calls!()
    )+
    // Let's do it again!
    macro_rules! rpc_calls( () => (
      static RPC_CALLS: PhfOrderedMap<&'static str, RpcCall> = phf_ordered_map! {
        $(stringify!($name) => RpcCall {
            name: stringify!($name),
            desc: $doc,
            usage: $usage,
            call: $name
          }
        ),+
      };
    ))
    rpc_calls!()
    // Erase the dummy macro, to avoid confusing errors in case somebody
    // tries to use it outside of this macro.
    macro_rules! rpc_calls(
      () => (Sorry, you can only call rpc_calls! once.)
    )
  )
)

// Main RPC call list
rpc_calls!{
  #[doc="Fetches a list of commands"]
  #[usage=""]
  pub fn help(_: &RpcCall, _: &mut IdleState, _: Vec<json::Json>) {
    let mut ret = TreeMap::new();
    for call in RPC_CALLS.values() {
      let mut obj = TreeMap::new();
      obj.insert("description".to_string(), json::String(call.desc.to_string()));
      obj.insert("usage".to_string(), json::String(call.usage.to_string()));
      ret.insert(call.name.to_string(), json::Object(obj));
    }
    Ok(json::Object(ret))
  },

  #[doc="Gets a specific block from the blockchain"]
  #[usage="<hash>"]
  pub fn getblock(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      1 => {
        use serialize::hex::FromHex;

        let blockchain = idle_state.blockchain.read();
        let hex_hash = try!(jsonrpc::decode::json_decode_string(&params[0]));
        let hash_err = standard_error(InvalidParams,
                                      Some(json::String(format!("Hash must be 64-character \
                                                                 hex string, not {}", hex_hash ))));
	let hash = try!(hex_hash.as_slice().from_hex().map_err(|_| hash_err.clone()));

        // We reverse the iterator since the user will give us a big-endian string,
        // while everything internal is little endian.
        let hash: Sha256dHash = try!(Serializable::deserialize(hash.iter().rev().map(|n| *n)).map_err(|_| hash_err.clone()));
        match blockchain.get_block(hash) {
          Some(node) => {
            let mut ret = TreeMap::new();
            ret.insert("header".to_string(), node.block.header.to_json());
            ret.insert("has_txdata".to_string(), json::Boolean(node.has_txdata));
            if node.has_txdata {
              ret.insert("transactions".to_string(), node.block.txdata.to_json());
            }
            Ok(json::Object(ret))
          }
          None => Err(bitcoin_json_error(BlockNotFound, Some(json::String(hex_hash)))),
        }
      }
      _ => usage_error(rpc)
    }
  },

  #[doc="Gets the current number of unspent outputs on the blockchain."]
  #[usage=""]
  pub fn getutxocount(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      0 => Ok(json::Number(idle_state.utxo_set.read().n_utxos() as f64)),
      _ => usage_error(rpc)
    }
  },

  #[doc="Gets the length of the longest chain, starting from the given hash or genesis."]
  #[usage="[start hash]"]
  pub fn getblockcount(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      0 => {
        let blockchain = idle_state.blockchain.read();
        // Subtract 1 from the hash since the genesis counts as block 0
        Ok(json::Number(blockchain.iter(blockchain.genesis_hash()).count() as f64 - 1.0))
      }
      1 => {
        use serialize::hex::FromHex;

        let blockchain = idle_state.blockchain.read();
        let hex_hash = try!(jsonrpc::decode::json_decode_string(&params[0]));
        let hash_err = standard_error(InvalidParams,
                                      Some(json::String(format!("Hash must be 64-character \
                                                                 hex string, not {}", hex_hash ))));

        let hash = try!(hex_hash.as_slice().from_hex().map_err(|_| hash_err.clone()));
        // We reverse the iterator since the user will give us a big-endian string,
        // while everything internal is little endian.
        let hash: Sha256dHash = try!(Serializable::deserialize(hash.iter().rev().map(|n| *n)).map_err(|_| hash_err.clone()));
        // Subtract 1 from the hash since the genesis counts as block 0
        match blockchain.iter(hash).count() {
          0 => Err(bitcoin_json_error(BlockNotFound, Some(json::String(hex_hash)))),
          n => Ok(json::Number(n as f64 - 1.0)),
        }
      }
      _ => usage_error(rpc)
    }
  }
}

enum BitcoinJsonError {
  BlockNotFound
}

/// Create a standard error responses
fn bitcoin_json_error(code: BitcoinJsonError, data: Option<json::Json>) -> Error {
  match code {
    BlockNotFound => Error {
      code: -1,
      message: "Block not found".to_string(),
      data: data
    }
  }
}

/// Generates a `usage` error message
fn usage_error(rpc: &RpcCall) -> JsonResult {
  Err(standard_error(InvalidParams,
                     Some(json::String(format!("Usage: {} {}", rpc.name, rpc.usage)))))
}

/// Handles a JSON-RPC request, returning a result to be given back to the peer
pub fn handle_rpc(request: jsonrpc::Request, idle_state: &mut IdleState) -> JsonResult {
  let method = request.method.as_slice();
  match RPC_CALLS.find_equiv(&method) {
    Some(rpc) => (rpc.call)(rpc, idle_state, request.params),
    None => Err(standard_error(MethodNotFound,
                               Some(json::String(request.method.clone()))))
  }
}

<|endoftext|>


<commit_before>// Copyright (C) 2017, 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use crate::firmware::{
    self,
    installation_set::{self, Set},
};
use chrono::{DateTime, NaiveDateTime, Utc};
use derive_more::{Deref, DerefMut, Display, Error, From};
use sdk::api::info::runtime_settings as api;
use slog_scope::{debug, warn};
use std::{fs, io, path::Path};

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug, Display, Error, From)]
pub enum Error {
    Io(io::Error),
    SerdeJson(serde_json::Error),
    FirmwareError(firmware::Error),

    #[display(fmt = "invalid runtime settings destination")]
    InvalidDestination,
}

#[derive(Clone, Debug, Deref, DerefMut, PartialEq)]
pub struct RuntimeSettings(pub api::RuntimeSettings);

impl Default for RuntimeSettings {
    fn default() -> Self {
        RuntimeSettings(api::RuntimeSettings {
            polling: api::RuntimePolling {
                last: DateTime::from_utc(NaiveDateTime::from_timestamp(0, 0), Utc),
                retries: 0,
                now: false,
                server_address: api::ServerAddress::Default,
            },
            update: api::RuntimeUpdate { upgrade_to_installation: None, applied_package_uid: None },
            path: std::path::PathBuf::new(),
            persistent: false,
        })
    }
}

impl RuntimeSettings {
    pub fn load(path: &Path) -> Result<Self> {
        let mut this = if path.exists() {
            debug!("loading runtime settings from {:?}", path);
            match fs::read_to_string(path).map_err(Error::from).and_then(|ref s| Self::parse(s)) {
                Ok(v) => v,
                Err(e) => {
                    warn!("failed to load current runtime settings: {}", e);
                    let _ = fs::rename(
                        path,
                        path.with_file_name(format!(
                            "{}.old",
                            path.file_name().unwrap().to_str().unwrap()
                        )),
                    );
                    debug!("using default runtime settings");
                    Self::default()
                }
            }
        } else {
            debug!("runtime settings file {:?} does not exists, using default settings", path);
            Self::default()
        };

        this.path = path.to_path_buf();
        Ok(this)
    }

    fn parse(content: &str) -> Result<Self> {
        Ok(RuntimeSettings(serde_json::from_str::<api::RuntimeSettings>(content)?))
    }

    fn save(&self) -> Result<()> {
        if !self.persistent {
            debug!("skipping runtime settings save, using non-persistent");
            return Ok(());
        }

        let parent = self.path.parent().ok_or(Error::InvalidDestination)?;
        if !parent.exists() {
            debug!("creating runtime settings to store state");
            fs::create_dir_all(parent)?;
        }

        fs::write(&self.path, self.serialize()?)?;
        debug!("saved runtime settings to {:?}", &self.path);

        Ok(())
    }

    fn serialize(&self) -> Result<String> {
        Ok(serde_json::to_string(&self.0)?)
    }

    pub(crate) fn get_inactive_installation_set(&self) -> Result<Set> {
        // If the `upgrade_to_installation` is defined, the current inactive
        // installation_set has already been swapped.
        if let Some(s) = self.update.upgrade_to_installation {
            return Ok(Set(s));
        }

        Ok(installation_set::inactive()?)
    }

    pub(crate) fn enable_persistency(&mut self) {
        self.persistent = true;
    }

    pub(crate) fn is_polling_forced(&self) -> bool {
        self.polling.now
    }

    pub(crate) fn disable_force_poll(&mut self) -> Result<()> {
        debug!("disabling foce poll");
        self.polling.now = false;
        self.save()
    }

    pub(crate) fn retries(&self) -> usize {
        self.polling.retries
    }

    pub(crate) fn inc_retries(&mut self) {
        self.polling.retries += 1;
    }

    pub(crate) fn clear_retries(&mut self) {
        self.polling.retries = 0;
    }

    pub(crate) fn last_polling(&self) -> DateTime<Utc> {
        self.polling.last
    }

    pub(crate) fn set_last_polling(&mut self, last_polling: DateTime<Utc>) -> Result<()> {
        debug!("updating last polling time");
        self.polling.last = last_polling;
        self.save()
    }

    pub(crate) fn applied_package_uid(&self) -> Option<String> {
        self.update.applied_package_uid.clone()
    }

    pub(crate) fn set_applied_package_uid(&mut self, applied_package_uid: &str) -> Result<()> {
        debug!("marking package {} as installed", applied_package_uid);
        self.update.applied_package_uid = Some(applied_package_uid.to_string());
        self.save()
    }

    pub(crate) fn set_upgrading_to(&mut self, new_install_set: Set) -> Result<()> {
        debug!("setting upgrading to {}", new_install_set);
        self.update.upgrade_to_installation = Some(new_install_set.0);
        self.save()
    }

    pub(crate) fn custom_server_address(&self) -> Option<&str> {
        match &self.polling.server_address {
            api::ServerAddress::Custom(s) => Some(s),
            api::ServerAddress::Default => None,
        }
    }

    pub(crate) fn set_custom_server_address(&mut self, server_address: &str) {
        self.polling.server_address = api::ServerAddress::Custom(server_address.to_owned());
    }

    /// Reset settings that are only need through a single installation
    pub(crate) fn reset_transient_settings(&mut self) {
        // Server address is reset so it doesn't keep probing the last custom server
        // requested
        self.polling.server_address = api::ServerAddress::Default;
    }

    pub(crate) fn reset_installation_settings(&mut self) -> Result<()> {
        debug!("reseting installation settings");
        self.update.upgrade_to_installation = None;
        self.update.applied_package_uid = None;

        // Ensure we do a probe as soon as possible so full update
        // cycle can be finished.
        self.polling.now = true;

        self.save()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use pretty_assertions::assert_eq;

    #[test]
    fn default() {
        let settings = RuntimeSettings::default();
        let expected = RuntimeSettings(api::RuntimeSettings {
            polling: api::RuntimePolling {
                last: DateTime::from_utc(NaiveDateTime::from_timestamp(0, 0), Utc),
                retries: 0,
                now: false,
                server_address: api::ServerAddress::Default,
            },
            update: api::RuntimeUpdate { upgrade_to_installation: None, applied_package_uid: None },
            path: std::path::PathBuf::new(),
            persistent: false,
        });

        assert_eq!(Some(settings), Some(expected));
    }

    #[test]
    fn load_and_save() {
        use std::fs;
        use tempfile::NamedTempFile;

        let tempfile = NamedTempFile::new().unwrap();
        let settings_file = tempfile.path();
        fs::remove_file(&settings_file).unwrap();

        let mut settings = RuntimeSettings::load(settings_file).unwrap();
        settings.reset_installation_settings().unwrap();

        let new_settings = RuntimeSettings::load(settings_file).unwrap();

        assert_eq!(settings.update, new_settings.update);
    }

    #[test]
    fn load_bad_formated_file() {
        use std::fs;
        use tempfile::NamedTempFile;

        let tempfile = NamedTempFile::new().unwrap();
        let settings_file = tempfile.path();
        fs::write(&settings_file, "foo").unwrap();

        let load_result = RuntimeSettings::load(settings_file);
        assert!(load_result.is_ok(), "We should fail when reading a unformated formatted file");

        let old_file = settings_file.with_file_name(format!(
            "{}.old",
            settings_file.file_name().unwrap().to_str().unwrap()
        ));
        let old_content = fs::read_to_string(&old_file).unwrap();
        assert_eq!(
            old_content, "foo",
            "Old file should still be accessible as a .old file in the same directory"
        );
        fs::remove_file(old_file).unwrap();
    }
}
<commit_msg>updatehub: runtime_settings: Rename variant name in Error<commit_after>// Copyright (C) 2017, 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use crate::firmware::{
    self,
    installation_set::{self, Set},
};
use chrono::{DateTime, NaiveDateTime, Utc};
use derive_more::{Deref, DerefMut, Display, Error, From};
use sdk::api::info::runtime_settings as api;
use slog_scope::{debug, warn};
use std::{fs, io, path::Path};

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug, Display, Error, From)]
pub enum Error {
    Io(io::Error),
    SerdeJson(serde_json::Error),
    Firmware(firmware::Error),

    #[display(fmt = "invalid runtime settings destination")]
    InvalidDestination,
}

#[derive(Clone, Debug, Deref, DerefMut, PartialEq)]
pub struct RuntimeSettings(pub api::RuntimeSettings);

impl Default for RuntimeSettings {
    fn default() -> Self {
        RuntimeSettings(api::RuntimeSettings {
            polling: api::RuntimePolling {
                last: DateTime::from_utc(NaiveDateTime::from_timestamp(0, 0), Utc),
                retries: 0,
                now: false,
                server_address: api::ServerAddress::Default,
            },
            update: api::RuntimeUpdate { upgrade_to_installation: None, applied_package_uid: None },
            path: std::path::PathBuf::new(),
            persistent: false,
        })
    }
}

impl RuntimeSettings {
    pub fn load(path: &Path) -> Result<Self> {
        let mut this = if path.exists() {
            debug!("loading runtime settings from {:?}", path);
            match fs::read_to_string(path).map_err(Error::from).and_then(|ref s| Self::parse(s)) {
                Ok(v) => v,
                Err(e) => {
                    warn!("failed to load current runtime settings: {}", e);
                    let _ = fs::rename(
                        path,
                        path.with_file_name(format!(
                            "{}.old",
                            path.file_name().unwrap().to_str().unwrap()
                        )),
                    );
                    debug!("using default runtime settings");
                    Self::default()
                }
            }
        } else {
            debug!("runtime settings file {:?} does not exists, using default settings", path);
            Self::default()
        };

        this.path = path.to_path_buf();
        Ok(this)
    }

    fn parse(content: &str) -> Result<Self> {
        Ok(RuntimeSettings(serde_json::from_str::<api::RuntimeSettings>(content)?))
    }

    fn save(&self) -> Result<()> {
        if !self.persistent {
            debug!("skipping runtime settings save, using non-persistent");
            return Ok(());
        }

        let parent = self.path.parent().ok_or(Error::InvalidDestination)?;
        if !parent.exists() {
            debug!("creating runtime settings to store state");
            fs::create_dir_all(parent)?;
        }

        fs::write(&self.path, self.serialize()?)?;
        debug!("saved runtime settings to {:?}", &self.path);

        Ok(())
    }

    fn serialize(&self) -> Result<String> {
        Ok(serde_json::to_string(&self.0)?)
    }

    pub(crate) fn get_inactive_installation_set(&self) -> Result<Set> {
        // If the `upgrade_to_installation` is defined, the current inactive
        // installation_set has already been swapped.
        if let Some(s) = self.update.upgrade_to_installation {
            return Ok(Set(s));
        }

        Ok(installation_set::inactive()?)
    }

    pub(crate) fn enable_persistency(&mut self) {
        self.persistent = true;
    }

    pub(crate) fn is_polling_forced(&self) -> bool {
        self.polling.now
    }

    pub(crate) fn disable_force_poll(&mut self) -> Result<()> {
        debug!("disabling foce poll");
        self.polling.now = false;
        self.save()
    }

    pub(crate) fn retries(&self) -> usize {
        self.polling.retries
    }

    pub(crate) fn inc_retries(&mut self) {
        self.polling.retries += 1;
    }

    pub(crate) fn clear_retries(&mut self) {
        self.polling.retries = 0;
    }

    pub(crate) fn last_polling(&self) -> DateTime<Utc> {
        self.polling.last
    }

    pub(crate) fn set_last_polling(&mut self, last_polling: DateTime<Utc>) -> Result<()> {
        debug!("updating last polling time");
        self.polling.last = last_polling;
        self.save()
    }

    pub(crate) fn applied_package_uid(&self) -> Option<String> {
        self.update.applied_package_uid.clone()
    }

    pub(crate) fn set_applied_package_uid(&mut self, applied_package_uid: &str) -> Result<()> {
        debug!("marking package {} as installed", applied_package_uid);
        self.update.applied_package_uid = Some(applied_package_uid.to_string());
        self.save()
    }

    pub(crate) fn set_upgrading_to(&mut self, new_install_set: Set) -> Result<()> {
        debug!("setting upgrading to {}", new_install_set);
        self.update.upgrade_to_installation = Some(new_install_set.0);
        self.save()
    }

    pub(crate) fn custom_server_address(&self) -> Option<&str> {
        match &self.polling.server_address {
            api::ServerAddress::Custom(s) => Some(s),
            api::ServerAddress::Default => None,
        }
    }

    pub(crate) fn set_custom_server_address(&mut self, server_address: &str) {
        self.polling.server_address = api::ServerAddress::Custom(server_address.to_owned());
    }

    /// Reset settings that are only need through a single installation
    pub(crate) fn reset_transient_settings(&mut self) {
        // Server address is reset so it doesn't keep probing the last custom server
        // requested
        self.polling.server_address = api::ServerAddress::Default;
    }

    pub(crate) fn reset_installation_settings(&mut self) -> Result<()> {
        debug!("reseting installation settings");
        self.update.upgrade_to_installation = None;
        self.update.applied_package_uid = None;

        // Ensure we do a probe as soon as possible so full update
        // cycle can be finished.
        self.polling.now = true;

        self.save()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use pretty_assertions::assert_eq;

    #[test]
    fn default() {
        let settings = RuntimeSettings::default();
        let expected = RuntimeSettings(api::RuntimeSettings {
            polling: api::RuntimePolling {
                last: DateTime::from_utc(NaiveDateTime::from_timestamp(0, 0), Utc),
                retries: 0,
                now: false,
                server_address: api::ServerAddress::Default,
            },
            update: api::RuntimeUpdate { upgrade_to_installation: None, applied_package_uid: None },
            path: std::path::PathBuf::new(),
            persistent: false,
        });

        assert_eq!(Some(settings), Some(expected));
    }

    #[test]
    fn load_and_save() {
        use std::fs;
        use tempfile::NamedTempFile;

        let tempfile = NamedTempFile::new().unwrap();
        let settings_file = tempfile.path();
        fs::remove_file(&settings_file).unwrap();

        let mut settings = RuntimeSettings::load(settings_file).unwrap();
        settings.reset_installation_settings().unwrap();

        let new_settings = RuntimeSettings::load(settings_file).unwrap();

        assert_eq!(settings.update, new_settings.update);
    }

    #[test]
    fn load_bad_formated_file() {
        use std::fs;
        use tempfile::NamedTempFile;

        let tempfile = NamedTempFile::new().unwrap();
        let settings_file = tempfile.path();
        fs::write(&settings_file, "foo").unwrap();

        let load_result = RuntimeSettings::load(settings_file);
        assert!(load_result.is_ok(), "We should fail when reading a unformated formatted file");

        let old_file = settings_file.with_file_name(format!(
            "{}.old",
            settings_file.file_name().unwrap().to_str().unwrap()
        ));
        let old_content = fs::read_to_string(&old_file).unwrap();
        assert_eq!(
            old_content, "foo",
            "Old file should still be accessible as a .old file in the same directory"
        );
        fs::remove_file(old_file).unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 Guillaume Desmottes <guillaume.desmottes@collabora.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use glib::subclass;
use glib::subclass::prelude::*;
use gst::subclass::prelude::*;
use gst_video::prelude::VideoDecoderExtManual;
use gst_video::prelude::*;
use gst_video::subclass::prelude::*;
use image::GenericImageView;
use std::sync::Mutex;

use crate::constants::{CDG_HEIGHT, CDG_WIDTH};

struct CdgDec {
    cdg_inter: Mutex<cdg_renderer::CdgInterpreter>,
    output_info: Mutex<Option<gst_video::VideoInfo>>,
}

lazy_static! {
    static ref CAT: gst::DebugCategory =
        gst::DebugCategory::new("cdgdec", gst::DebugColorFlags::empty(), Some("CDG decoder"),);
}

impl ObjectSubclass for CdgDec {
    const NAME: &'static str = "CdgDec";
    type ParentType = gst_video::VideoDecoder;
    type Instance = gst::subclass::ElementInstanceStruct<Self>;
    type Class = subclass::simple::ClassStruct<Self>;

    glib_object_subclass!();

    fn new() -> Self {
        Self {
            cdg_inter: Mutex::new(cdg_renderer::CdgInterpreter::new()),
            output_info: Mutex::new(None),
        }
    }

    fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
        klass.set_metadata(
            "CDG decoder",
            "Decoder/Video",
            "CDG decoder",
            "Guillaume Desmottes <guillaume.desmottes@collabora.com>",
        );

        let sink_caps = gst::Caps::new_simple("video/x-cdg", &[("parsed", &true)]);
        let sink_pad_template = gst::PadTemplate::new(
            "sink",
            gst::PadDirection::Sink,
            gst::PadPresence::Always,
            &sink_caps,
        )
        .unwrap();
        klass.add_pad_template(sink_pad_template);

        let src_caps = gst::Caps::new_simple(
            "video/x-raw",
            &[
                ("format", &gst_video::VideoFormat::Rgba.to_str()),
                ("width", &(CDG_WIDTH as i32)),
                ("height", &(CDG_HEIGHT as i32)),
                ("framerate", &gst::Fraction::new(0, 1)),
            ],
        );
        let src_pad_template = gst::PadTemplate::new(
            "src",
            gst::PadDirection::Src,
            gst::PadPresence::Always,
            &src_caps,
        )
        .unwrap();
        klass.add_pad_template(src_pad_template);
    }
}

impl ObjectImpl for CdgDec {
    glib_object_impl!();
}

impl ElementImpl for CdgDec {}

impl VideoDecoderImpl for CdgDec {
    fn start(&self, element: &gst_video::VideoDecoder) -> Result<(), gst::ErrorMessage> {
        let mut out_info = self.output_info.lock().unwrap();
        *out_info = None;

        self.parent_start(element)
    }

    fn stop(&self, element: &gst_video::VideoDecoder) -> Result<(), gst::ErrorMessage> {
        {
            let mut cdg_inter = self.cdg_inter.lock().unwrap();
            cdg_inter.reset(true);
        }
        self.parent_stop(element)
    }

    fn handle_frame(
        &self,
        element: &gst_video::VideoDecoder,
        mut frame: gst_video::VideoCodecFrame,
    ) -> Result<gst::FlowSuccess, gst::FlowError> {
        {
            let mut out_info = self.output_info.lock().unwrap();
            if out_info.is_none() {
                let output_state = element.set_output_state(
                    gst_video::VideoFormat::Rgba,
                    CDG_WIDTH,
                    CDG_HEIGHT,
                    None,
                )?;

                element.negotiate(output_state)?;

                let out_state = element.get_output_state().unwrap();
                *out_info = Some(out_state.get_info());
            }
        }

        let cmd = {
            let input = frame.get_input_buffer().unwrap();
            let map = input.map_readable().map_err(|_| {
                gst_element_error!(
                    element,
                    gst::CoreError::Failed,
                    ["Failed to map input buffer readable"]
                );
                gst::FlowError::Error
            })?;
            let data = map.as_slice();

            cdg::decode_subchannel_cmd(&data)
        };

        let cmd = match cmd {
            Some(cmd) => cmd,
            None => {
                // Not a CDG command
                element.release_frame(frame);
                return Ok(gst::FlowSuccess::Ok);
            }
        };

        let mut cdg_inter = self.cdg_inter.lock().unwrap();
        cdg_inter.handle_cmd(cmd);

        element.allocate_output_frame(&mut frame, None)?;
        {
            let output = frame.get_output_buffer_mut().unwrap();
            let info = self.output_info.lock().unwrap();

            let mut out_frame =
                gst_video::VideoFrameRef::from_buffer_ref_writable(output, info.as_ref().unwrap())
                    .map_err(|_| {
                        gst_element_error!(
                            element,
                            gst::CoreError::Failed,
                            ["Failed to map output buffer writable"]
                        );
                        gst::FlowError::Error
                    })?;

            let out_stride = out_frame.plane_stride()[0] as usize;

            for (y, line) in out_frame
                .plane_data_mut(0)
                .unwrap()
                .chunks_exact_mut(out_stride)
                .take(CDG_HEIGHT as usize)
                .enumerate()
            {
                for (x, pixel) in line
                    .chunks_exact_mut(4)
                    .take(CDG_WIDTH as usize)
                    .enumerate()
                {
                    let p = cdg_inter.get_pixel(x as u32, y as u32);
                    pixel.copy_from_slice(&p.0);
                }
            }
        }

        gst_debug!(CAT, obj: element, "Finish frame pts={}", frame.get_pts());

        element.finish_frame(frame)
    }

    fn decide_allocation(
        &self,
        element: &gst_video::VideoDecoder,
        query: &mut gst::QueryRef,
    ) -> Result<(), gst::ErrorMessage> {
        if let gst::query::QueryView::Allocation(allocation) = query.view() {
            if allocation
                .find_allocation_meta::<gst_video::VideoMeta>()
                .is_some()
            {
                let pools = allocation.get_allocation_pools();
                if let Some((ref pool, _, _, _)) = pools.first() {
                    if let Some(pool) = pool {
                        let mut config = pool.get_config();
                        config.add_option(&gst_video::BUFFER_POOL_OPTION_VIDEO_META);
                        pool.set_config(config).map_err(|e| {
                            gst::gst_error_msg!(gst::CoreError::Negotiation, [&e.message])
                        })?;
                    }
                }
            }
        }

        self.parent_decide_allocation(element, query)
    }

    fn flush(&self, element: &gst_video::VideoDecoder) -> bool {
        gst_debug!(CAT, obj: element, "flushing, reset CDG interpreter");

        let mut cdg_inter = self.cdg_inter.lock().unwrap();
        cdg_inter.reset(false);
        true
    }
}

pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
    gst::Element::register(
        Some(plugin),
        "cdgdec",
        gst::Rank::Primary,
        CdgDec::get_type(),
    )
}
<commit_msg>video/cdgdec: Box CdgInterpreter state to prevent GObject private size to become too big<commit_after>// Copyright (C) 2019 Guillaume Desmottes <guillaume.desmottes@collabora.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use glib::subclass;
use glib::subclass::prelude::*;
use gst::subclass::prelude::*;
use gst_video::prelude::VideoDecoderExtManual;
use gst_video::prelude::*;
use gst_video::subclass::prelude::*;
use image::GenericImageView;
use std::sync::Mutex;

use crate::constants::{CDG_HEIGHT, CDG_WIDTH};

struct CdgDec {
    cdg_inter: Mutex<Box<cdg_renderer::CdgInterpreter>>,
    output_info: Mutex<Option<gst_video::VideoInfo>>,
}

lazy_static! {
    static ref CAT: gst::DebugCategory =
        gst::DebugCategory::new("cdgdec", gst::DebugColorFlags::empty(), Some("CDG decoder"),);
}

impl ObjectSubclass for CdgDec {
    const NAME: &'static str = "CdgDec";
    type ParentType = gst_video::VideoDecoder;
    type Instance = gst::subclass::ElementInstanceStruct<Self>;
    type Class = subclass::simple::ClassStruct<Self>;

    glib_object_subclass!();

    fn new() -> Self {
        Self {
            cdg_inter: Mutex::new(Box::new(cdg_renderer::CdgInterpreter::new())),
            output_info: Mutex::new(None),
        }
    }

    fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
        klass.set_metadata(
            "CDG decoder",
            "Decoder/Video",
            "CDG decoder",
            "Guillaume Desmottes <guillaume.desmottes@collabora.com>",
        );

        let sink_caps = gst::Caps::new_simple("video/x-cdg", &[("parsed", &true)]);
        let sink_pad_template = gst::PadTemplate::new(
            "sink",
            gst::PadDirection::Sink,
            gst::PadPresence::Always,
            &sink_caps,
        )
        .unwrap();
        klass.add_pad_template(sink_pad_template);

        let src_caps = gst::Caps::new_simple(
            "video/x-raw",
            &[
                ("format", &gst_video::VideoFormat::Rgba.to_str()),
                ("width", &(CDG_WIDTH as i32)),
                ("height", &(CDG_HEIGHT as i32)),
                ("framerate", &gst::Fraction::new(0, 1)),
            ],
        );
        let src_pad_template = gst::PadTemplate::new(
            "src",
            gst::PadDirection::Src,
            gst::PadPresence::Always,
            &src_caps,
        )
        .unwrap();
        klass.add_pad_template(src_pad_template);
    }
}

impl ObjectImpl for CdgDec {
    glib_object_impl!();
}

impl ElementImpl for CdgDec {}

impl VideoDecoderImpl for CdgDec {
    fn start(&self, element: &gst_video::VideoDecoder) -> Result<(), gst::ErrorMessage> {
        let mut out_info = self.output_info.lock().unwrap();
        *out_info = None;

        self.parent_start(element)
    }

    fn stop(&self, element: &gst_video::VideoDecoder) -> Result<(), gst::ErrorMessage> {
        {
            let mut cdg_inter = self.cdg_inter.lock().unwrap();
            cdg_inter.reset(true);
        }
        self.parent_stop(element)
    }

    fn handle_frame(
        &self,
        element: &gst_video::VideoDecoder,
        mut frame: gst_video::VideoCodecFrame,
    ) -> Result<gst::FlowSuccess, gst::FlowError> {
        {
            let mut out_info = self.output_info.lock().unwrap();
            if out_info.is_none() {
                let output_state = element.set_output_state(
                    gst_video::VideoFormat::Rgba,
                    CDG_WIDTH,
                    CDG_HEIGHT,
                    None,
                )?;

                element.negotiate(output_state)?;

                let out_state = element.get_output_state().unwrap();
                *out_info = Some(out_state.get_info());
            }
        }

        let cmd = {
            let input = frame.get_input_buffer().unwrap();
            let map = input.map_readable().map_err(|_| {
                gst_element_error!(
                    element,
                    gst::CoreError::Failed,
                    ["Failed to map input buffer readable"]
                );
                gst::FlowError::Error
            })?;
            let data = map.as_slice();

            cdg::decode_subchannel_cmd(&data)
        };

        let cmd = match cmd {
            Some(cmd) => cmd,
            None => {
                // Not a CDG command
                element.release_frame(frame);
                return Ok(gst::FlowSuccess::Ok);
            }
        };

        let mut cdg_inter = self.cdg_inter.lock().unwrap();
        cdg_inter.handle_cmd(cmd);

        element.allocate_output_frame(&mut frame, None)?;
        {
            let output = frame.get_output_buffer_mut().unwrap();
            let info = self.output_info.lock().unwrap();

            let mut out_frame =
                gst_video::VideoFrameRef::from_buffer_ref_writable(output, info.as_ref().unwrap())
                    .map_err(|_| {
                        gst_element_error!(
                            element,
                            gst::CoreError::Failed,
                            ["Failed to map output buffer writable"]
                        );
                        gst::FlowError::Error
                    })?;

            let out_stride = out_frame.plane_stride()[0] as usize;

            for (y, line) in out_frame
                .plane_data_mut(0)
                .unwrap()
                .chunks_exact_mut(out_stride)
                .take(CDG_HEIGHT as usize)
                .enumerate()
            {
                for (x, pixel) in line
                    .chunks_exact_mut(4)
                    .take(CDG_WIDTH as usize)
                    .enumerate()
                {
                    let p = cdg_inter.get_pixel(x as u32, y as u32);
                    pixel.copy_from_slice(&p.0);
                }
            }
        }

        gst_debug!(CAT, obj: element, "Finish frame pts={}", frame.get_pts());

        element.finish_frame(frame)
    }

    fn decide_allocation(
        &self,
        element: &gst_video::VideoDecoder,
        query: &mut gst::QueryRef,
    ) -> Result<(), gst::ErrorMessage> {
        if let gst::query::QueryView::Allocation(allocation) = query.view() {
            if allocation
                .find_allocation_meta::<gst_video::VideoMeta>()
                .is_some()
            {
                let pools = allocation.get_allocation_pools();
                if let Some((ref pool, _, _, _)) = pools.first() {
                    if let Some(pool) = pool {
                        let mut config = pool.get_config();
                        config.add_option(&gst_video::BUFFER_POOL_OPTION_VIDEO_META);
                        pool.set_config(config).map_err(|e| {
                            gst::gst_error_msg!(gst::CoreError::Negotiation, [&e.message])
                        })?;
                    }
                }
            }
        }

        self.parent_decide_allocation(element, query)
    }

    fn flush(&self, element: &gst_video::VideoDecoder) -> bool {
        gst_debug!(CAT, obj: element, "flushing, reset CDG interpreter");

        let mut cdg_inter = self.cdg_inter.lock().unwrap();
        cdg_inter.reset(false);
        true
    }
}

pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
    gst::Element::register(
        Some(plugin),
        "cdgdec",
        gst::Rank::Primary,
        CdgDec::get_type(),
    )
}
<|endoftext|>


<commit_before>//! The SpaceAPI server struct.

use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::{Arc, Mutex};

use iron::Iron;
use router::Router;
use redis::{IntoConnectionInfo, ConnectionInfo};

mod handlers;

use ::api;

use ::sensors;
use ::modifiers;
use ::errors::SpaceapiServerError;

/// A Space API server instance.
///
/// You can create a new instance using the ``new`` constructor method by
/// passing it the host, the port, the ``Status`` object and a redis connection info object.
///
/// The ``SpaceapiServer`` includes a web server through
/// [Hyper](http://hyper.rs/hyper/hyper/server/index.html). Simply call the ``serve`` method.
pub struct SpaceapiServer {
    socket_addr: SocketAddr,
    status: api::Status,
    redis_connection_info: ConnectionInfo,
    sensor_specs: sensors::SafeSensorSpecs,
    status_modifiers: Vec<Box<modifiers::StatusModifier>>,
}

impl SpaceapiServer {

    pub fn new<U, T>(socket_addr: U,
                     status: api::Status,
                     redis_connection_info: T,
                     status_modifiers: Vec<Box<modifiers::StatusModifier>>)
        -> Result<SpaceapiServer, SpaceapiServerError>
        where U: ToSocketAddrs, T: IntoConnectionInfo {
            let mut socket_addr_iter = try!(socket_addr.to_socket_addrs());
            let socket_addr = try!(socket_addr_iter.next()
                                   .ok_or(SpaceapiServerError::Message("Invalid socket address".into())));
            Ok(SpaceapiServer {
                socket_addr: socket_addr,
                status: status,
                redis_connection_info: try!(redis_connection_info.into_connection_info()),
                sensor_specs: Arc::new(Mutex::new(vec![])),
                status_modifiers: status_modifiers,
            })
        }

    /// Create and return a Router instance.
    fn route(self) -> Router {
        let mut router = Router::new();

        router.get("/", handlers::ReadHandler::new(
            self.status.clone(), self.redis_connection_info.clone(),
            self.sensor_specs.clone(), self.status_modifiers));

        router.put("/sensors/:sensor/", handlers::UpdateHandler::new(
            self.redis_connection_info.clone(), self.sensor_specs.clone()));

        router
    }

    /// Start a HTTP server listening on ``self.host:self.port``.
    ///
    /// The call returns an `HttpResult<Listening>` object, see
    /// http://ironframework.io/doc/hyper/server/struct.Listening.html
    /// for more information.
    pub fn serve(self) -> ::HttpResult<::Listening> {
        let socket_addr = self.socket_addr;
        let router = self.route();

        println!("Starting HTTP server on http://{}...", socket_addr);
        Iron::new(router).http(socket_addr)
    }

    /// Register a new sensor.
    ///
    /// The first argument is a ``api::SensorTemplate`` instance containing all static data.
    /// The second argument specifies how to get the actual sensor value from Redis.
    /// And the third argument specifies the data type of the value.
    pub fn register_sensor(&mut self, template: Box<api::SensorTemplate>, data_key: String) {
        let sensor_specs_ref = self.sensor_specs.clone();
        sensor_specs_ref.lock().unwrap().push(
            sensors::SensorSpec { template: template, data_key: data_key}
        );
    }

}
<commit_msg>Log redis connection info when starting server (#39)<commit_after>//! The SpaceAPI server struct.

use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::{Arc, Mutex};

use iron::Iron;
use router::Router;
use redis::{IntoConnectionInfo, ConnectionInfo};

mod handlers;

use ::api;

use ::sensors;
use ::modifiers;
use ::errors::SpaceapiServerError;

/// A Space API server instance.
///
/// You can create a new instance using the ``new`` constructor method by
/// passing it the host, the port, the ``Status`` object and a redis connection info object.
///
/// The ``SpaceapiServer`` includes a web server through
/// [Hyper](http://hyper.rs/hyper/hyper/server/index.html). Simply call the ``serve`` method.
pub struct SpaceapiServer {
    socket_addr: SocketAddr,
    status: api::Status,
    redis_connection_info: ConnectionInfo,
    sensor_specs: sensors::SafeSensorSpecs,
    status_modifiers: Vec<Box<modifiers::StatusModifier>>,
}

impl SpaceapiServer {

    pub fn new<U, T>(socket_addr: U,
                     status: api::Status,
                     redis_connection_info: T,
                     status_modifiers: Vec<Box<modifiers::StatusModifier>>)
        -> Result<SpaceapiServer, SpaceapiServerError>
        where U: ToSocketAddrs, T: IntoConnectionInfo {
            let mut socket_addr_iter = try!(socket_addr.to_socket_addrs());
            let socket_addr = try!(socket_addr_iter.next()
                                   .ok_or(SpaceapiServerError::Message("Invalid socket address".into())));
            Ok(SpaceapiServer {
                socket_addr: socket_addr,
                status: status,
                redis_connection_info: try!(redis_connection_info.into_connection_info()),
                sensor_specs: Arc::new(Mutex::new(vec![])),
                status_modifiers: status_modifiers,
            })
        }

    /// Create and return a Router instance.
    fn route(self) -> Router {
        let mut router = Router::new();

        router.get("/", handlers::ReadHandler::new(
            self.status.clone(), self.redis_connection_info.clone(),
            self.sensor_specs.clone(), self.status_modifiers));

        router.put("/sensors/:sensor/", handlers::UpdateHandler::new(
            self.redis_connection_info.clone(), self.sensor_specs.clone()));

        router
    }

    /// Start a HTTP server listening on ``self.host:self.port``.
    ///
    /// The call returns an `HttpResult<Listening>` object, see
    /// http://ironframework.io/doc/hyper/server/struct.Listening.html
    /// for more information.
    pub fn serve(self) -> ::HttpResult<::Listening> {
        // Log some useful debug information
        debug!("Redis connection info: {:?}", &self.redis_connection_info);

        // Launch server process
        let socket_addr = self.socket_addr;
        let router = self.route();
        println!("Starting HTTP server on http://{}...", socket_addr);
        Iron::new(router).http(socket_addr)
    }

    /// Register a new sensor.
    ///
    /// The first argument is a ``api::SensorTemplate`` instance containing all static data.
    /// The second argument specifies how to get the actual sensor value from Redis.
    /// And the third argument specifies the data type of the value.
    pub fn register_sensor(&mut self, template: Box<api::SensorTemplate>, data_key: String) {
        let sensor_specs_ref = self.sensor_specs.clone();
        sensor_specs_ref.lock().unwrap().push(
            sensors::SensorSpec { template: template, data_key: data_key}
        );
    }

}
<|endoftext|>