<commit_before>#![allow(non_upper_case_globals)]
use rustc_serialize::json::{self, ToJson};

use rs_es::Client;

use iron::prelude::*;
use iron::{status, Handler};
use iron::mime::Mime;

use logger::Logger;

use router::Router;

use params::*;

use config::*;
use search::SearchResult;
use resource::Resource;

use std::collections::HashMap;
use std::env;
use std::io::Read;
use std::marker::PhantomData;

macro_rules! try_or_422 {
  ($expr:expr) => (match $expr {
    Ok(val)  => val,
    Err(err) => {
      let mut error = HashMap::new();
      error.insert("error", format!("{}", err));

      let content_type = "application/json".parse::<Mime>().unwrap();
      return Ok(Response::with(
        (content_type, status::UnprocessableEntity, json::encode(&error).unwrap())
      ))
    }
  })
}

#[derive(Clone)]
pub struct Server<R: Resource> {
  config:   Config,
  endpoint: String,
  resource: PhantomData<R>
}

pub struct SearchableHandler<R> {
  config:   Config,
  resource: PhantomData<R>,
}

impl<R: Resource> SearchableHandler<R> {
  fn new(config: Config) -> Self {
    SearchableHandler::<R> { resource: PhantomData, config: config }
  }
}

impl<R: Resource> Handler for SearchableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    let mut client = Client::new(&*self.config.es.host, self.config.es.port);

    let params   = try_or_422!(req.get_ref::<Params>());
    let response = SearchResult {
      results: R::search(&mut client, &*self.config.es.index, params),
      params:  params.clone()
    };

    let content_type = "application/json".parse::<Mime>().unwrap();
    Ok(Response::with(
      (content_type, status::Ok, try_or_422!(json::encode(&response.to_json())))
    ))
  }
}

pub struct IndexableHandler<R> {
  config:   Config,
  resource: PhantomData<R>,
}

impl<R: Resource> IndexableHandler<R> {
  fn new(config: Config) -> Self {
    IndexableHandler::<R> { resource: PhantomData, config: config }
  }
}

impl<R: Resource> Handler for IndexableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    let mut client = Client::new(&*self.config.es.host, self.config.es.port);

    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let resource: R = try_or_422!(json::decode(&payload));
    try_or_422!(resource.index(&mut client, &*self.config.es.index));

    Ok(Response::with(status::Created))
  }
}

pub struct ResettableHandler<R> {
  config:   Config,
  resource: PhantomData<R>,
}

impl<R: Resource> ResettableHandler<R> {
  fn new(config: Config) -> Self {
    ResettableHandler::<R> { resource: PhantomData, config: config }
  }
}

impl<R: Resource> Handler for ResettableHandler<R> {
  fn handle(&self, _: &mut Request) -> IronResult<Response> {
    let mut client = Client::new(&*self.config.es.host, self.config.es.port);

    match R::reset_index(&mut client, &*self.config.es.index) {
      Ok(_)  => Ok(Response::with(status::NoContent)),
      Err(_) => Ok(Response::with(status::UnprocessableEntity))
    }
  }
}

impl<R: Resource> Server<R> {
  pub fn new(endpoint: String) -> Self {
    let config = match env::args().nth(1) {
      Some(file) => Config::from_file(file),
      None       => Config::from_env()
    };

    Server {
      config:   config,
      endpoint: endpoint,
      resource: PhantomData
    }
  }

  pub fn start(&self) {
    let host = format!("{}:{}", self.config.http.host, self.config.http.port);

    println!("Searchspot v{}\n{}\n{}\n", env!("CARGO_PKG_VERSION"),
                                         self.config.es,
                                         self.config.http);

    let mut router = Router::new();
    router.get(&self.endpoint,    SearchableHandler::<R>::new(self.config.clone()));
    router.post(&self.endpoint,   IndexableHandler::<R>::new(self.config.clone()));
    router.delete(&self.endpoint, ResettableHandler::<R>::new(self.config.clone()));

    match env::var("DYNO") { // for some reasons, chain::link makes heroku crash
      Ok(_)  => Iron::new(router).http(&*host),
      Err(_) => {
        let mut chain = Chain::new(router);
        chain.link(Logger::new(None));
        Iron::new(chain).http(&*host)
      }
    }.unwrap();
  }
}
<commit_msg>server: implement AuthorizableEndpoint<commit_after>#![allow(non_upper_case_globals)]
use rustc_serialize::json::{self, ToJson};

use rs_es::Client;

use iron::prelude::*;
use iron::{status, Handler, Headers};
use iron::mime::Mime;

use logger::Logger;

use router::Router;

use params::*;

use config::*;
use search::SearchResult;
use resource::Resource;

use std::collections::HashMap;
use std::env;
use std::io::Read;
use std::marker::PhantomData;

macro_rules! try_or_422 {
  ($expr:expr) => (match $expr {
    Ok(val)  => val,
    Err(err) => {
      let mut error = HashMap::new();
      error.insert("error", format!("{}", err));

      let content_type = "application/json".parse::<Mime>().unwrap();
      return Ok(Response::with(
        (content_type, status::UnprocessableEntity, json::encode(&error).unwrap())
      ))
    }
  })
}

macro_rules! unauthorized {
  () => ({
    return Ok(Response::with(
      (status::Unauthorized)
    ))
  })
}

#[derive(Clone)]
pub struct Server<R: Resource> {
  config:   Config,
  endpoint: String,
  resource: PhantomData<R>
}

trait AuthorizableEndpoint {
  fn is_authorized(&self, secret: String, headers: &Headers) -> bool {
    match headers.get_raw("X-Secret") {
      Some(x_secret) => match String::from_utf8(x_secret[0].clone()) {
        Ok(x_secret) => x_secret == secret,
        Err(_)       => false
      },
      None => false
    }
  }
}

pub struct SearchableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> SearchableHandler<R> {
  fn new(config: Config) -> Self {
    SearchableHandler::<R> { resource: PhantomData, config: config }
  }
}

impl<R: Resource> AuthorizableEndpoint for SearchableHandler<R> {}

impl<R: Resource> Handler for SearchableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    if !self.is_authorized(self.config.http.secret.clone(), &req.headers) {
      unauthorized!();
    }

    let mut client = Client::new(&*self.config.es.host, self.config.es.port);

    let params   = try_or_422!(req.get_ref::<Params>());
    let response = SearchResult {
      results: R::search(&mut client, &*self.config.es.index, params),
      params:  params.clone()
    };

    let content_type = "application/json".parse::<Mime>().unwrap();
    Ok(Response::with(
      (content_type, status::Ok, try_or_422!(json::encode(&response.to_json())))
    ))
  }
}

pub struct IndexableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> IndexableHandler<R> {
  fn new(config: Config) -> Self {
    IndexableHandler::<R> { resource: PhantomData, config: config }
  }
}

impl<R: Resource> AuthorizableEndpoint for IndexableHandler<R> {}

impl<R: Resource> Handler for IndexableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    if !self.is_authorized(self.config.http.secret.clone(), &req.headers) {
      unauthorized!();
    }

    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let mut client = Client::new(&*self.config.es.host, self.config.es.port);

    let resource: R = try_or_422!(json::decode(&payload));
    try_or_422!(resource.index(&mut client, &*self.config.es.index));

    Ok(Response::with(status::Created))
  }
}

pub struct ResettableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> ResettableHandler<R> {
  fn new(config: Config) -> Self {
    ResettableHandler::<R> { resource: PhantomData, config: config }
  }
}

impl<R: Resource> AuthorizableEndpoint for ResettableHandler<R> {}

impl<R: Resource> Handler for ResettableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    if !self.is_authorized(self.config.http.secret.clone(), &req.headers) {
      unauthorized!();
    }

    let mut client = Client::new(&*self.config.es.host, self.config.es.port);
    match R::reset_index(&mut client, &*self.config.es.index) {
      Ok(_)  => Ok(Response::with(status::NoContent)),
      Err(_) => Ok(Response::with(status::UnprocessableEntity))
    }
  }
}

impl<R: Resource> Server<R> {
  pub fn new(endpoint: String) -> Self {
    let config = match env::args().nth(1) {
      Some(file) => Config::from_file(file),
      None       => Config::from_env()
    };

    Server {
      config:   config,
      endpoint: endpoint,
      resource: PhantomData
    }
  }

  pub fn start(&self) {
    let host = format!("{}:{}", self.config.http.host, self.config.http.port);

    println!("Searchspot v{}\n{}\n{}\n", env!("CARGO_PKG_VERSION"),
                                         self.config.es,
                                         self.config.http);

    let mut router = Router::new();
    router.get(&self.endpoint,    SearchableHandler::<R>::new(self.config.clone()));
    router.post(&self.endpoint,   IndexableHandler::<R>::new(self.config.clone()));
    router.delete(&self.endpoint, ResettableHandler::<R>::new(self.config.clone()));

    match env::var("DYNO") { // for some reasons, chain::link makes heroku crash
      Ok(_)  => Iron::new(router).http(&*host),
      Err(_) => {
        let mut chain = Chain::new(router);
        chain.link(Logger::new(None));
        Iron::new(chain).http(&*host)
      }
    }.unwrap();
  }
}
<|endoftext|>


<commit_before>extern crate libc;
use self::libc::{c_int, size_t};
use std::io::Read;

use codecs::FromByte;
use error::{Result, Error};

#[link(name = "snappy")]
extern {
    fn snappy_uncompress(compressed: *const u8,
                             compressed_length: size_t,
                             uncompressed: *mut u8,
                             uncompressed_length: *mut size_t) -> c_int;
    fn snappy_uncompressed_length(compressed: *const u8,
                                  compressed_length: size_t,
                                  result: *mut size_t) -> c_int;
}

#[derive(Default, Debug, Clone)]
pub struct SnappyHeader {
    pub marker: i8,
    // TODO - Its a c-string of 6 bytes not 6 independent chars
    pub c1: i8,
    pub c2: i8,
    pub c3: i8,
    pub c4: i8,
    pub c5: i8,
    pub c6: i8,
    pub pad: i8,
    pub version: i32,
    pub compat: i32
}

#[derive(Default, Debug, Clone)]
pub struct SnappyMessage {
    pub message: Vec<u8>
}

impl FromByte for SnappyHeader {
    type R = SnappyHeader;

    #[allow(unused_must_use)]
    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        self.marker.decode(buffer);
        // TODO - decode a fixed size array instead of byte by byte. I mean, make it elegant
        self.c1.decode(buffer);
        self.c2.decode(buffer);
        self.c3.decode(buffer);
        self.c4.decode(buffer);
        self.c5.decode(buffer);
        self.c6.decode(buffer);
        self.pad.decode(buffer);
        self.version.decode(buffer);
        self.compat.decode(buffer);
        Ok(())
    }
}

impl FromByte for SnappyMessage {
    type R = SnappyMessage;

    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        try!(self.message.decode(buffer));
        Ok(())
    }
}

pub fn uncompress(src: &Vec<u8>) -> Result<Vec<u8>> {
    unsafe {

        let (_, x) = src.split_at(0);
        let srclen = x.len() as size_t;
        let psrc = x.as_ptr();
        let mut dstlen: size_t = 0;
        snappy_uncompressed_length(psrc, srclen, &mut dstlen);
        let mut dst = Vec::with_capacity(dstlen as usize);
        let pdst = dst.as_mut_ptr();

        if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 {
            dst.set_len(dstlen as usize);
            Ok(dst)
        } else {
            Err(Error::InvalidInputSnappy) // SNAPPY_INVALID_INPUT
        }
    }
}
<commit_msg>snappy uncompress<commit_after>extern crate libc;
use self::libc::{c_int, size_t};
use std::io::Read;

use codecs::FromByte;
use error::{Result, Error};

#[link(name = "snappy")]
extern {
    fn snappy_uncompress(compressed: *const u8,
                             compressed_length: size_t,
                             uncompressed: *mut u8,
                             uncompressed_length: *mut size_t) -> c_int;
    fn snappy_uncompressed_length(compressed: *const u8,
                                  compressed_length: size_t,
                                  result: *mut size_t) -> c_int;
}

#[derive(Default, Debug, Clone)]
pub struct SnappyHeader {
    pub marker: i8,
    // TODO - Its a c-string of 6 bytes not 6 independent chars
    pub c1: i8,
    pub c2: i8,
    pub c3: i8,
    pub c4: i8,
    pub c5: i8,
    pub c6: i8,
    pub pad: i8,
    pub version: i32,
    pub compat: i32
}

#[derive(Default, Debug, Clone)]
pub struct SnappyMessage {
    pub message: Vec<u8>
}

impl FromByte for SnappyHeader {
    type R = SnappyHeader;

    #[allow(unused_must_use)]
    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        self.marker.decode(buffer);
        // TODO - decode a fixed size array instead of byte by byte. I mean, make it elegant
        self.c1.decode(buffer);
        self.c2.decode(buffer);
        self.c3.decode(buffer);
        self.c4.decode(buffer);
        self.c5.decode(buffer);
        self.c6.decode(buffer);
        self.pad.decode(buffer);
        self.version.decode(buffer);
        self.compat.decode(buffer);
        Ok(())
    }
}

impl FromByte for SnappyMessage {
    type R = SnappyMessage;

    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        try!(self.message.decode(buffer));
        Ok(())
    }
}

pub fn uncompress(src: &Vec<u8>) -> Result<Vec<u8>> {
    unsafe {
        let (_, x) = src.split_at(0);
        let srclen = x.len() as size_t;
        let psrc = x.as_ptr();
        let mut dstlen: size_t = 0;
        snappy_uncompressed_length(psrc, srclen, &mut dstlen);
        let mut dst = Vec::with_capacity(dstlen as usize);
        let pdst = dst.as_mut_ptr();

        if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 {
            dst.set_len(dstlen as usize);
            Ok(dst)
        } else {
            Err(Error::InvalidInputSnappy) // SNAPPY_INVALID_INPUT
        }
    }
}

#[test]
fn test_uncompress() {
    // The vector should uncompress to "This is test"
    let msg: Vec<u8> = vec!(12, 44, 84, 104, 105, 115, 32, 105, 115, 32, 116, 101, 115, 116);
    let uncomp_msg = String::from_utf8(uncompress(&msg).unwrap()).unwrap();
    assert_eq!(&uncomp_msg[..], "This is test");
}

#[test]
#[should_panic]
fn test_uncompress_panic() {
    let msg: Vec<u8> = vec!(12, 42, 84, 104, 105, 115, 32, 105, 115, 32, 116, 101, 115, 116);
    let uncomp_msg = String::from_utf8(uncompress(&msg).unwrap()).unwrap();
    assert_eq!(&uncomp_msg[..], "This is test");
}
<|endoftext|>


<commit_before>use std::io::{IoResult, IoError, IoErrorKind, TcpStream, ConnectionRefused,
              ConnectionFailed, OtherIoError, InvalidInput};
use std::io::net::ip::{ IpAddr, Ipv4Addr };

pub struct Socks4<'a> {
    socks_host: &'a str,
    socks_port: u16,
}

impl<'a> Socks4<'a> {
    pub fn new(host: &'a str, port: u16) -> Socks4 {
        Socks4 { socks_host: host, socks_port: port }
    }

    pub fn connect(&mut self, host: IpAddr, port: u16) -> IoResult<TcpStream> {
        let mut stream = try!(TcpStream::connect(self.socks_host, self.socks_port));
        try!(stream.write([0x04, 0x01]));
        try!(stream.write_be_u16(port));
        match host {
            Ipv4Addr(oct1, oct2, oct3, oct4) => {
                try!(stream.write([oct1, oct2, oct3, oct4]));
            },
            _ => { return io_err(InvalidInput, "Must be IPv4 address"); }
        };
        try!(stream.write([0x00]));

        // read null byte
        if 0 != try!(stream.read_u8()) {
            return io_err(OtherIoError, "Expected null byte not found");
        }

        // read status
        match try!(stream.read_u8()) {
            // request granted
            0x5a => Ok(stream),
            // request rejected or failed
            0x5b => io_err(ConnectionRefused, "Request rejected or failed"),
            // request failed because client is not running identd (or unreachable)
            0x5c => io_err(ConnectionFailed, "Client unreachable"),
            // request failed because client's identd could not confirm the user ID
            // string in the request
            0x5d => io_err(ConnectionRefused, "Unknown user"),
            x => fail!("Unexpected status byte: {}", x)
        }
    }
}

fn io_err<T>(kind: IoErrorKind, desc: &'static str) -> IoResult<T> {
    Err(IoError { kind: kind, desc: desc, detail: None })
}

<commit_msg>Fixed a mistake I made<commit_after>use std::io::{IoResult, IoError, IoErrorKind, TcpStream, ConnectionRefused,
              ConnectionFailed, OtherIoError, InvalidInput};
use std::io::net::ip::{ IpAddr, Ipv4Addr };

pub struct Socks4<'a> {
    socks_host: &'a str,
    socks_port: u16,
}

impl<'a> Socks4<'a> {
    pub fn new(host: &'a str, port: u16) -> Socks4 {
        Socks4 { socks_host: host, socks_port: port }
    }

    pub fn connect(&mut self, host: IpAddr, port: u16) -> IoResult<TcpStream> {
        let mut stream = try!(TcpStream::connect(self.socks_host, self.socks_port));
        try!(stream.write([0x04, 0x01]));
        try!(stream.write_be_u16(port));
        match host {
            Ipv4Addr(oct1, oct2, oct3, oct4) => {
                try!(stream.write([oct1, oct2, oct3, oct4]));
            },
            _ => { return io_err(InvalidInput, "Must be IPv4 address"); }
        };
        try!(stream.write([0x00]));

        // read null byte
        if 0 != try!(stream.read_u8()) {
            return io_err(OtherIoError, "Expected null byte not found");
        }

        // read status
        match try!(stream.read_u8()) {
            // request granted
            0x5a => {
                let _port = try!(stream.read_be_u16());
                let _ip = try!(stream.read_be_u32());
                Ok(stream)
            }
            // request rejected or failed
            0x5b => io_err(ConnectionRefused, "Request rejected or failed"),
            // request failed because client is not running identd (or unreachable)
            0x5c => io_err(ConnectionFailed, "Client unreachable"),
            // request failed because client's identd could not confirm the user ID
            // string in the request
            0x5d => io_err(ConnectionRefused, "Unknown user"),
            x => fail!("Unexpected status byte: {}", x)
        }
    }
}

fn io_err<T>(kind: IoErrorKind, desc: &'static str) -> IoResult<T> {
    Err(IoError { kind: kind, desc: desc, detail: None })
}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt::Debug;
use std::str::FromStr;

use async_trait::async_trait;

use crate::error::*;
use crate::path;
use crate::value::{Value, ValueKind};

/// Describes a generic _source_ of configuration properties.
pub trait Source: Debug {
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync>;

    /// Collect all configuration properties available from this source and return
    /// a HashMap.
    fn collect(&self) -> Result<HashMap<String, Value>>;

    /// Collects all configuration properties to a provided cache.
    fn collect_to(&self, cache: &mut Value) -> Result<()> {
        self.collect()?
            .iter()
            .for_each(|(key, val)| set_value(cache, key, val));

        Ok(())
    }
}

fn set_value(cache: &mut Value, key: &str, value: &Value) {
    match path::Expression::from_str(key) {
        // Set using the path
        Ok(expr) => expr.set(cache, value.clone()),

        // Set diretly anyway
        _ => path::Expression::Identifier(key.clone()).set(cache, value.clone()),
    }
}

/// Describes a generic _source_ of configuration properties capable of using an async runtime.
///
/// At the moment this library does not implement it, although it allows using its implementations
/// within builders.  Due to the scattered landscape of asynchronous runtimes, it is impossible to
/// cater to all needs with one implementation.  Also, this trait might be most useful with remote
/// configuration sources, reachable via the network, probably using HTTP protocol.  Numerous HTTP
/// libraries exist, making it even harder to find one implementation that rules them all.
///
/// For those reasons, it is left to other crates to implement runtime-specific or proprietary
/// details.
///
/// It is advised to use `async_trait` crate while implementing this trait.
///
/// See examples for sample implementation.
#[async_trait]
pub trait AsyncSource: Debug + Sync {
    // Sync is supertrait due to https://docs.rs/async-trait/0.1.50/async_trait/index.html#dyn-traits

    /// Collects all configuration properties available from this source and return
    /// a HashMap as an async operations.
    async fn collect(&self) -> Result<HashMap<String, Value>>;

    /// Collects all configuration properties to a provided cache.
    async fn collect_to(&self, cache: &mut Value) -> Result<()> {
        self.collect()
            .await?
            .iter()
            .for_each(|(key, val)| set_value(cache, key, val));

        Ok(())
    }
}

impl Clone for Box<dyn AsyncSource + Send + Sync> {
    fn clone(&self) -> Self {
        self.to_owned()
    }
}

impl Clone for Box<dyn Source + Send + Sync> {
    fn clone(&self) -> Box<dyn Source + Send + Sync> {
        self.clone_into_box()
    }
}

impl Source for Vec<Box<dyn Source + Send + Sync>> {
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
        Box::new((*self).clone())
    }

    fn collect(&self) -> Result<HashMap<String, Value>> {
        let mut cache: Value = HashMap::<String, Value>::new().into();

        for source in self {
            source.collect_to(&mut cache)?;
        }

        if let ValueKind::Table(table) = cache.kind {
            Ok(table)
        } else {
            unreachable!();
        }
    }
}

impl Source for [Box<dyn Source + Send + Sync>] {
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
        Box::new(self.to_owned())
    }

    fn collect(&self) -> Result<HashMap<String, Value>> {
        let mut cache: Value = HashMap::<String, Value>::new().into();

        for source in self {
            source.collect_to(&mut cache)?;
        }

        if let ValueKind::Table(table) = cache.kind {
            Ok(table)
        } else {
            unreachable!();
        }
    }
}

impl<T> Source for Vec<T>
where
    T: Source + Sync + Send,
    T: Clone,
    T: 'static,
{
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
        Box::new((*self).clone())
    }

    fn collect(&self) -> Result<HashMap<String, Value>> {
        let mut cache: Value = HashMap::<String, Value>::new().into();

        for source in self {
            source.collect_to(&mut cache)?;
        }

        if let ValueKind::Table(table) = cache.kind {
            Ok(table)
        } else {
            unreachable!();
        }
    }
}
<commit_msg>Fix clippy: Use to_string() instead of clone()<commit_after>use std::collections::HashMap;
use std::fmt::Debug;
use std::str::FromStr;

use async_trait::async_trait;

use crate::error::*;
use crate::path;
use crate::value::{Value, ValueKind};

/// Describes a generic _source_ of configuration properties.
pub trait Source: Debug {
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync>;

    /// Collect all configuration properties available from this source and return
    /// a HashMap.
    fn collect(&self) -> Result<HashMap<String, Value>>;

    /// Collects all configuration properties to a provided cache.
    fn collect_to(&self, cache: &mut Value) -> Result<()> {
        self.collect()?
            .iter()
            .for_each(|(key, val)| set_value(cache, key, val));

        Ok(())
    }
}

fn set_value(cache: &mut Value, key: &str, value: &Value) {
    match path::Expression::from_str(key) {
        // Set using the path
        Ok(expr) => expr.set(cache, value.clone()),

        // Set diretly anyway
        _ => path::Expression::Identifier(key.to_string()).set(cache, value.clone()),
    }
}

/// Describes a generic _source_ of configuration properties capable of using an async runtime.
///
/// At the moment this library does not implement it, although it allows using its implementations
/// within builders.  Due to the scattered landscape of asynchronous runtimes, it is impossible to
/// cater to all needs with one implementation.  Also, this trait might be most useful with remote
/// configuration sources, reachable via the network, probably using HTTP protocol.  Numerous HTTP
/// libraries exist, making it even harder to find one implementation that rules them all.
///
/// For those reasons, it is left to other crates to implement runtime-specific or proprietary
/// details.
///
/// It is advised to use `async_trait` crate while implementing this trait.
///
/// See examples for sample implementation.
#[async_trait]
pub trait AsyncSource: Debug + Sync {
    // Sync is supertrait due to https://docs.rs/async-trait/0.1.50/async_trait/index.html#dyn-traits

    /// Collects all configuration properties available from this source and return
    /// a HashMap as an async operations.
    async fn collect(&self) -> Result<HashMap<String, Value>>;

    /// Collects all configuration properties to a provided cache.
    async fn collect_to(&self, cache: &mut Value) -> Result<()> {
        self.collect()
            .await?
            .iter()
            .for_each(|(key, val)| set_value(cache, key, val));

        Ok(())
    }
}

impl Clone for Box<dyn AsyncSource + Send + Sync> {
    fn clone(&self) -> Self {
        self.to_owned()
    }
}

impl Clone for Box<dyn Source + Send + Sync> {
    fn clone(&self) -> Box<dyn Source + Send + Sync> {
        self.clone_into_box()
    }
}

impl Source for Vec<Box<dyn Source + Send + Sync>> {
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
        Box::new((*self).clone())
    }

    fn collect(&self) -> Result<HashMap<String, Value>> {
        let mut cache: Value = HashMap::<String, Value>::new().into();

        for source in self {
            source.collect_to(&mut cache)?;
        }

        if let ValueKind::Table(table) = cache.kind {
            Ok(table)
        } else {
            unreachable!();
        }
    }
}

impl Source for [Box<dyn Source + Send + Sync>] {
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
        Box::new(self.to_owned())
    }

    fn collect(&self) -> Result<HashMap<String, Value>> {
        let mut cache: Value = HashMap::<String, Value>::new().into();

        for source in self {
            source.collect_to(&mut cache)?;
        }

        if let ValueKind::Table(table) = cache.kind {
            Ok(table)
        } else {
            unreachable!();
        }
    }
}

impl<T> Source for Vec<T>
where
    T: Source + Sync + Send,
    T: Clone,
    T: 'static,
{
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
        Box::new((*self).clone())
    }

    fn collect(&self) -> Result<HashMap<String, Value>> {
        let mut cache: Value = HashMap::<String, Value>::new().into();

        for source in self {
            source.collect_to(&mut cache)?;
        }

        if let ValueKind::Table(table) = cache.kind {
            Ok(table)
        } else {
            unreachable!();
        }
    }
}
<|endoftext|>


<commit_before>use crate::cell::UnsafeCell;
use crate::collections::VecDeque;
use crate::ffi::c_void;
use crate::ops::{Deref, DerefMut, Drop};
use crate::ptr;
use crate::sync::atomic::{AtomicUsize, Ordering, spin_loop_hint};
use crate::sys::hermit::abi;

/// This type provides a lock based on busy waiting to realize mutual exclusion
///
/// # Description
///
/// This structure behaves a lot like a common mutex. There are some differences:
///
/// - By using busy waiting, it can be used outside the runtime.
/// - It is a so called ticket lock (https://en.wikipedia.org/wiki/Ticket_lock)
///   and completly fair.
#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
struct Spinlock<T: ?Sized> {
    queue: AtomicUsize,
    dequeue: AtomicUsize,
    data: UnsafeCell<T>,
}

unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
struct SpinlockGuard<'a, T: ?Sized + 'a> {
    dequeue: &'a AtomicUsize,
    data: &'a mut T,
}

impl<T> Spinlock<T> {
    pub const fn new(user_data: T) -> Spinlock<T> {
        SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() }
    }

    #[inline]
    fn obtain_lock(&self) {
        let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
        while self.dequeue.load(Ordering::SeqCst) != ticket {
            spin_loop_hint();
        }
    }

    #[inline]
    pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
        self.obtain_lock();
        SpinlockGuard {
            dequeue: &self.dequeue,
            data: &mut *self.data.get(),
        }
    }
}

impl<T: ?Sized + Default> Default for Spinlock<T> {
    fn default() -> Spinlock<T> {
        Spinlock::new(Default::default())
    }
}

impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        &*self.data
    }
}

impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut *self.data
    }
}

impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self) {
        self.dequeue.fetch_add(1, Ordering::SeqCst);
    }
}

/// Realize a priority queue for tasks
struct PriorityQueue {
    queues: [Option<VecDeque<abi::Tid>>; abi::NO_PRIORITIES],
    prio_bitmap: u64,
}

impl PriorityQueue {
    pub const fn new() -> PriorityQueue {
        PriorityQueue {
            queues: [
                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
                None, None, None,
            ],
            prio_bitmap: 0,
        }
    }

    /// Add a task handle by its priority to the queue
    pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) {
        let i: usize = prio.into().into();
        self.prio_bitmap |= (1 << i) as u64;
        if let Some(queue) = &mut self.queues[i] {
            queue.push_back(id);
        } else {
            let mut queue = VecDeque::new();
            queue.push_back(id);
            self.queues[i] = Some(queue);
        }
    }

    fn pop_from_queue(&mut self, queue_index: usize) -> Option<abi::Tid> {
        if let Some(queue) = &mut self.queues[queue_index] {
            let id = queue.pop_front();

            if queue.is_empty() {
                self.prio_bitmap &= !(1 << queue_index as u64);
            }

            id
        } else {
            None
        }
    }

    /// Pop the task handle with the highest priority from the queue
    pub fn pop(&mut self) -> Option<abi::Tid> {
        for i in 0..abi::NO_PRIORITIES {
            if self.prio_bitmap & (1 << i) != 0 {
                return self.pop_from_queue(i);
            }
        }

        None
    }
}

struct MutexInner {
    locked: bool,
    blocked_task: PriorityQueue,
}

impl MutexInner {
    pub const fn new() -> MutexInner {
        MutexInner {
            locked: false,
            blocked_task: PriorityQueue::new(),
        }
    }
}

pub struct Mutex {
    inner: Spinlock<MutexInner>,
}

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

impl Mutex {
    pub const fn new() -> Mutex {
        Mutex {
            inner: Spinlock::new(MutexInner::new()),
        }
    }

    #[inline]
    pub unsafe fn init(&mut self) {
        self.inner = Spinlock::new(MutexInner::new());
    }

    #[inline]
    pub unsafe fn lock(&self) {
        loop {
            let mut guard = self.inner.lock();
            if guard.locked == false {
                guard.locked = true;
                return;
            } else {
                let prio = abi::get_priority();
                let id = abi::getpid();

                guard.blocked_task.push(prio, id);
                abi::block_current_task();
                drop(guard);
                abi::yield_now();
            }
        }
    }

    #[inline]
    pub unsafe fn unlock(&self) {
        let mut guard = self.inner.lock();
        guard.locked = false;
        if let Some(tid) = guard.blocked_task.pop() {
            abi::wakeup_task(tid);
        }
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        let mut guard = self.inner.lock();
        if guard.locked == false {
            guard.locked = true;
        }
        guard.locked
    }

    #[inline]
    pub unsafe fn destroy(&self) {
    }
}

pub struct ReentrantMutex {
    inner: *const c_void,
}

impl ReentrantMutex {
    pub const unsafe fn uninitialized() -> ReentrantMutex {
        ReentrantMutex { inner: ptr::null() }
    }

    #[inline]
    pub unsafe fn init(&self) {
        let _ = abi::recmutex_init(&self.inner as *const *const c_void as *mut _);
    }

    #[inline]
    pub unsafe fn lock(&self) {
        let _ = abi::recmutex_lock(self.inner);
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        true
    }

    #[inline]
    pub unsafe fn unlock(&self) {
        let _ = abi::recmutex_unlock(self.inner);
    }

    #[inline]
    pub unsafe fn destroy(&self) {
        let _ = abi::recmutex_destroy(self.inner);
    }
}
<commit_msg>revise code to pass the format check<commit_after>use crate::cell::UnsafeCell;
use crate::collections::VecDeque;
use crate::ffi::c_void;
use crate::ops::{Deref, DerefMut, Drop};
use crate::ptr;
use crate::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};
use crate::sys::hermit::abi;

/// This type provides a lock based on busy waiting to realize mutual exclusion
///
/// # Description
///
/// This structure behaves a lot like a common mutex. There are some differences:
///
/// - By using busy waiting, it can be used outside the runtime.
/// - It is a so called ticket lock (https://en.wikipedia.org/wiki/Ticket_lock)
///   and completly fair.
#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
struct Spinlock<T: ?Sized> {
    queue: AtomicUsize,
    dequeue: AtomicUsize,
    data: UnsafeCell<T>,
}

unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
struct SpinlockGuard<'a, T: ?Sized + 'a> {
    dequeue: &'a AtomicUsize,
    data: &'a mut T,
}

impl<T> Spinlock<T> {
    pub const fn new(user_data: T) -> Spinlock<T> {
        SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() }
    }

    #[inline]
    fn obtain_lock(&self) {
        let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
        while self.dequeue.load(Ordering::SeqCst) != ticket {
            spin_loop_hint();
        }
    }

    #[inline]
    pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
        self.obtain_lock();
        SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() }
    }
}

impl<T: ?Sized + Default> Default for Spinlock<T> {
    fn default() -> Spinlock<T> {
        Spinlock::new(Default::default())
    }
}

impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        &*self.data
    }
}

impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut *self.data
    }
}

impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self) {
        self.dequeue.fetch_add(1, Ordering::SeqCst);
    }
}

/// Realize a priority queue for tasks
struct PriorityQueue {
    queues: [Option<VecDeque<abi::Tid>>; abi::NO_PRIORITIES],
    prio_bitmap: u64,
}

impl PriorityQueue {
    pub const fn new() -> PriorityQueue {
        PriorityQueue {
            queues: [
                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
                None, None, None,
            ],
            prio_bitmap: 0,
        }
    }

    /// Add a task handle by its priority to the queue
    pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) {
        let i: usize = prio.into().into();
        self.prio_bitmap |= (1 << i) as u64;
        if let Some(queue) = &mut self.queues[i] {
            queue.push_back(id);
        } else {
            let mut queue = VecDeque::new();
            queue.push_back(id);
            self.queues[i] = Some(queue);
        }
    }

    fn pop_from_queue(&mut self, queue_index: usize) -> Option<abi::Tid> {
        if let Some(queue) = &mut self.queues[queue_index] {
            let id = queue.pop_front();

            if queue.is_empty() {
                self.prio_bitmap &= !(1 << queue_index as u64);
            }

            id
        } else {
            None
        }
    }

    /// Pop the task handle with the highest priority from the queue
    pub fn pop(&mut self) -> Option<abi::Tid> {
        for i in 0..abi::NO_PRIORITIES {
            if self.prio_bitmap & (1 << i) != 0 {
                return self.pop_from_queue(i);
            }
        }

        None
    }
}

struct MutexInner {
    locked: bool,
    blocked_task: PriorityQueue,
}

impl MutexInner {
    pub const fn new() -> MutexInner {
        MutexInner { locked: false, blocked_task: PriorityQueue::new() }
    }
}

pub struct Mutex {
    inner: Spinlock<MutexInner>,
}

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

impl Mutex {
    pub const fn new() -> Mutex {
        Mutex { inner: Spinlock::new(MutexInner::new()) }
    }

    #[inline]
    pub unsafe fn init(&mut self) {
        self.inner = Spinlock::new(MutexInner::new());
    }

    #[inline]
    pub unsafe fn lock(&self) {
        loop {
            let mut guard = self.inner.lock();
            if guard.locked == false {
                guard.locked = true;
                return;
            } else {
                let prio = abi::get_priority();
                let id = abi::getpid();

                guard.blocked_task.push(prio, id);
                abi::block_current_task();
                drop(guard);
                abi::yield_now();
            }
        }
    }

    #[inline]
    pub unsafe fn unlock(&self) {
        let mut guard = self.inner.lock();
        guard.locked = false;
        if let Some(tid) = guard.blocked_task.pop() {
            abi::wakeup_task(tid);
        }
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        let mut guard = self.inner.lock();
        if guard.locked == false {
            guard.locked = true;
        }
        guard.locked
    }

    #[inline]
    pub unsafe fn destroy(&self) {}
}

pub struct ReentrantMutex {
    inner: *const c_void,
}

impl ReentrantMutex {
    pub const unsafe fn uninitialized() -> ReentrantMutex {
        ReentrantMutex { inner: ptr::null() }
    }

    #[inline]
    pub unsafe fn init(&self) {
        let _ = abi::recmutex_init(&self.inner as *const *const c_void as *mut _);
    }

    #[inline]
    pub unsafe fn lock(&self) {
        let _ = abi::recmutex_lock(self.inner);
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        true
    }

    #[inline]
    pub unsafe fn unlock(&self) {
        let _ = abi::recmutex_unlock(self.inner);
    }

    #[inline]
    pub unsafe fn destroy(&self) {
        let _ = abi::recmutex_destroy(self.inner);
    }
}
<|endoftext|>


<commit_before>use atags::raw;

pub use atags::raw::{Core, Mem};

/// An ATAG.
#[derive(Debug, Copy, Clone)]
pub enum Atag {
    Core(raw::Core),
    Mem(raw::Mem),
    Cmd(&'static str),
    Unknown(u32),
    None
}

impl Atag {
    /// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`.
    pub fn core(self) -> Option<Core> {
        match self {
            Atag::Core(core) => Some(core),
            _ => None,
        }
    }

    /// Returns `Some` if this is a `Mem` ATAG. Otherwise returns `None`.
    pub fn mem(self) -> Option<Mem> {
        match self {
            Atag::Mem(mem) => Some(mem),
            _ => None,
        }
    }

    /// Returns `Some` with the command line string if this is a `Cmd` ATAG.
    /// Otherwise returns `None`.
    pub fn cmd(self) -> Option<&'static str> {
        match self {
            Atag::Cmd(cmd) => Some(cmd),
            _ => None,
        }
    }
}

// FIXME: Implement `From<raw::Core>`, `From<raw::Mem>`, and `From<&raw::Cmd>`
// for `Atag`. These implementations should be used by the `From<&raw::Atag> for
// Atag` implementation below.

impl<'a> From<&'a raw::Core> for Atag {
    fn from(core: &raw::Core) -> Atag {
        Atag::Core(*core)
    }
}

impl<'a> From<&'a raw::Mem> for Atag {
    fn from(mem: &raw::Mem) -> Atag {
        Atag::Mem(*mem)
    }
}

impl<'a> From<&'a raw::Cmd> for Atag {
    fn from(cmd: &raw::Cmd) -> Atag {
        let cmd = unsafe {
            let p = cmd.cmd as *const u8;
            let mut size = 0;
            while *p.add(size) != 0 {
                size += 1;
            }
            let slice = ::core::slice::from_raw_parts(p, size);
            ::core::str::from_utf8_unchecked(slice)
        };
        Atag::Cmd(cmd)
    }
}

impl<'a> From<&'a raw::Atag> for Atag {
    fn from(atag: &raw::Atag) -> Atag {
        unsafe {
            match (atag.tag, &atag.kind) {
                (raw::Atag::CORE, &raw::Kind { core }) => Self::from(&core),
                (raw::Atag::MEM, &raw::Kind { mem }) => Self::from(&mem),
                (raw::Atag::CMDLINE, &raw::Kind { ref cmd }) => Self::from(cmd),
                (raw::Atag::NONE, _) => Atag::None,
                (id, _) => Atag::Unknown(id),
            }
        }
    }
}
<commit_msg>fix atags<commit_after>use atags::raw;

pub use atags::raw::{Core, Mem};

/// An ATAG.
#[derive(Debug, Copy, Clone)]
pub enum Atag {
    Core(raw::Core),
    Mem(raw::Mem),
    Cmd(&'static str),
    Unknown(u32),
    None
}

impl Atag {
    /// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`.
    pub fn core(self) -> Option<Core> {
        match self {
            Atag::Core(core) => Some(core),
            _ => None,
        }
    }

    /// Returns `Some` if this is a `Mem` ATAG. Otherwise returns `None`.
    pub fn mem(self) -> Option<Mem> {
        match self {
            Atag::Mem(mem) => Some(mem),
            _ => None,
        }
    }

    /// Returns `Some` with the command line string if this is a `Cmd` ATAG.
    /// Otherwise returns `None`.
    pub fn cmd(self) -> Option<&'static str> {
        match self {
            Atag::Cmd(cmd) => Some(cmd),
            _ => None,
        }
    }
}

// FIXME: Implement `From<raw::Core>`, `From<raw::Mem>`, and `From<&raw::Cmd>`
// for `Atag`. These implementations should be used by the `From<&raw::Atag> for
// Atag` implementation below.

impl<'a> From<&'a raw::Core> for Atag {
    fn from(core: &raw::Core) -> Atag {
        Atag::Core(*core)
    }
}

impl<'a> From<&'a raw::Mem> for Atag {
    fn from(mem: &raw::Mem) -> Atag {
        Atag::Mem(*mem)
    }
}

impl<'a> From<&'a raw::Cmd> for Atag {
    fn from(cmd: &raw::Cmd) -> Atag {
        let cmd = unsafe {
            let p = (&cmd.cmd) as *const u8;
            let mut size = 0;
            while *p.add(size) != 0 {
                size += 1;
            }
            let slice = ::core::slice::from_raw_parts(p, size);
            ::core::str::from_utf8_unchecked(slice)
        };
        Atag::Cmd(cmd)
    }
}

impl<'a> From<&'a raw::Atag> for Atag {
    fn from(atag: &raw::Atag) -> Atag {
        unsafe {
            match (atag.tag, &atag.kind) {
                (raw::Atag::CORE, &raw::Kind { core }) => Self::from(&core),
                (raw::Atag::MEM, &raw::Kind { mem }) => Self::from(&mem),
                (raw::Atag::CMDLINE, &raw::Kind { ref cmd }) => Self::from(cmd),
                (raw::Atag::NONE, _) => Atag::None,
                (id, _) => Atag::Unknown(id),
            }
        }
    }
}
<|endoftext|>


<commit_before>use serde_json as json;
use std::collections::HashMap;

use datatype::{Error, Metadata, Role, Root, SignedManifest, SignedMeta, SignedCustom,
               Snapshot, Targets, Timestamp, UptaneConfig, Url, Verifier};
use http::{Client, Response};

/// Last known version of each metadata file.
pub struct Version {
    root:      u64,
    targets:   u64,
    snapshot:  u64,
    timestamp: u64
}

impl Version {
    fn new() -> Self {
        Version { root: 0, targets: 0, snapshot: 0, timestamp: 0 }
    }
}

/// Software over the air updates using Uptane endpoints.
pub struct Uptane {
    uptane_cfg:  UptaneConfig,
    device_uuid: String,
    version:     Version,
    verifier:    Verifier,
}

impl Uptane {
    pub fn new(cfg: UptaneConfig, device_uuid: String) -> Self {
        Uptane {
            uptane_cfg:  cfg,
            device_uuid: device_uuid,
            version:     Version::new(),
            verifier:    Verifier::new(),
        }
    }

    /// If using the director endpoint it returns:
    /// `<director_server>/<endpoint>`,
    /// Otherwise it returns the images server with device uuid:
    /// `<images_server>/<uuid>/<endpoint>`
    fn endpoint(&self, director: bool, endpoint: &str) -> Url {
        if director {
            let ref server = self.uptane_cfg.director_server;
            server.join(&format!("/{}", endpoint))
        } else {
            let ref server = self.uptane_cfg.images_server;
            server.join(&format!("/{}/{}", self.device_uuid, endpoint))
        }
    }

    /// GET the bytes response from the given endpoint.
    fn get_endpoint(&mut self, client: &Client, director: bool, endpoint: &str) -> Result<Vec<u8>, Error> {
        let rx = client.get(self.endpoint(director, endpoint), None);
        match rx.recv().ok_or(Error::Client("couldn't get bytes from endpoint".to_string()))? {
            Response::Success(data) => Ok(data.body),
            Response::Failed(data)  => Err(Error::from(data)),
            Response::Error(err)    => Err(err)
        }
    }

    /// PUT bytes to endpoint.
    fn put_endpoint(&mut self, client: &Client, director: bool, endpoint: &str, bytes: Vec<u8>) -> Result<(), Error> {
        let rx = client.put(self.endpoint(director, endpoint), Some(bytes));
        match rx.recv().ok_or(Error::Client("couldn't put bytes to endpoint".to_string()))? {
            Response::Success(_)   => Ok(()),
            Response::Failed(data) => Err(Error::from(data)),
            Response::Error(err)   => Err(err)
        }
    }

    /// Put a new manifest file to the Director server.
    pub fn put_manifest(&mut self, client: &Client, manifest: SignedManifest) -> Result<(), Error> {
        debug!("put_manifest");
        self.put_endpoint(client, true, "manifest", json::to_vec(&manifest)?)
    }

    /// Add the root.json metadata to the verifier and return a new version indicator.
    pub fn get_root(&mut self, client: &Client, director: bool) -> Result<bool, Error> {
        debug!("get_root");
        let buf  = self.get_endpoint(client, director, "root.json")?;
        let meta = json::from_slice::<Metadata>(&buf)?;
        let root = json::from_value::<Root>(meta.signed.clone())?;

        for (id, key) in root.keys {
            trace!("adding key: {:?}", key);
            self.verifier.add_key(id, key);
        }
        for (role, data) in root.roles {
            trace!("adding roledata: {:?}", data);
            self.verifier.add_role(role, data);
        }

        debug!("checking root keys");
        self.verifier.verify(&Role::Root, &meta, 0)?;
        if root.version > self.version.root {
            debug!("root version increased from {} to {}", self.version.root, root.version);
            self.version.root = root.version;
            Ok(true)
        } else {
            Ok(false)
        }
    }

    /// Get the targets.json metadata and a new version indicator.
    pub fn get_targets(&mut self, client: &Client, director: bool) -> Result<(Targets, bool), Error> {
        debug!("get_targets");
        let buf  = self.get_endpoint(client, director, "targets.json")?;
        let meta = json::from_slice::<Metadata>(&buf)?;
        let targ = json::from_value::<Targets>(meta.signed.clone())?;

        debug!("checking targets keys");
        self.verifier.verify(&Role::Targets, &meta, 0)?;
        if targ.version > self.version.targets {
            debug!("targets version increased from {} to {}", self.version.targets, targ.version);
            self.version.targets = targ.version;
            Ok((targ, true))
        } else {
            Ok((targ, false))
        }
    }

    /// Get the snapshot.json metadata and a new version indicator.
    pub fn get_snapshot(&mut self, client: &Client, director: bool) -> Result<(Snapshot, bool), Error> {
        debug!("get_snapshot");
        let buf  = self.get_endpoint(client, director, "snapshot.json")?;
        let meta = json::from_slice::<Metadata>(&buf)?;
        let snap = json::from_value::<Snapshot>(meta.signed.clone())?;

        debug!("checking snapshot keys");
        self.verifier.verify(&Role::Snapshot, &meta, 0)?;
        if snap.version > self.version.snapshot {
            debug!("snapshot version increased from {} to {}", self.version.snapshot, snap.version);
            self.version.snapshot = snap.version;
            Ok((snap, true))
        } else {
            Ok((snap, false))
        }
    }

    /// Get the timestamp.json metadata and a new version indicator.
    pub fn get_timestamp(&mut self, client: &Client, director: bool) -> Result<(Timestamp, bool), Error> {
        debug!("get_timestamp");
        let buf  = self.get_endpoint(client, director, "timestamp.json")?;
        let meta = json::from_slice::<Metadata>(&buf)?;
        let time = json::from_value::<Timestamp>(meta.signed.clone())?;

        debug!("checking timestamp keys");
        self.verifier.verify(&Role::Timestamp, &meta, 0)?;
        if time.version > self.version.timestamp {
            debug!("timestamp version increased from {} to {}", self.version.timestamp, time.version);
            self.version.timestamp = time.version;
            Ok((time, true))
        } else {
            Ok((time, false))
        }
    }

    pub fn extract_custom(&self, targets: HashMap<String, SignedMeta>) -> HashMap<String, SignedCustom> {
        debug!("extract_custom");
        let mut out = HashMap::new();
        for (file, meta) in targets {
            let _ = meta.custom.map(|c| out.insert(file, c));
        }
        out
    }
}

#[cfg(test)]
mod tests {
    use std::fs::File;
    use std::io::Read;

    use super::*;
    use datatype::{Metadata, SignedManifest, SignedVersion};
    use http::TestClient;

    fn read_file(path: &str) -> Vec<u8> {
        let mut file = File::open(path).unwrap_or_else(|err| panic!("couldn't open path: {}\n{}", path, err));
        let mut buf = Vec::new();
        file.read_to_end(&mut buf).unwrap_or_else(|err| panic!("couldn't read path: {}\n{}", path, err));
        buf
    }

    fn client_from_paths(paths: &[&str]) -> TestClient<Vec<u8>> {
        let mut replies = Vec::new();
        for path in paths {
            replies.push(read_file(path));
        }
        TestClient::from(replies)
    }

    #[test]
    fn test_read_manifest() {
        let bytes = read_file("tests/uptane/ats/manifest.json");
        let meta = json::from_slice::<Metadata>(&bytes).expect("couldn't load manifest");
        let signed = json::from_value::<SignedManifest>(meta.signed).expect("couldn't load signed manifest");
        assert_eq!(signed.primary_ecu_serial, "{ecu serial}");

        let mut metas = json::from_value::<Vec<Metadata>>(signed.ecu_version_manifest).expect("couldn't load ecu_version_manifest");
        assert_eq!(metas.len(), 1);
        let meta1 = metas.pop().unwrap();
        let version = json::from_value::<SignedVersion>(meta1.signed).expect("couldn't load first manifest");
        assert_eq!(version.installed_image.filepath, "/{ostree-refname}");
    }

    #[test]
    fn test_get_targets_director() {
        let mut uptane = Uptane::new(UptaneConfig::default(), "test-get-targets-director".to_string());
        let client = client_from_paths(&[
            "tests/uptane/ed25519/root.json",
            "tests/uptane/ats/targets_director.json",
        ]);

        assert!(uptane.get_root(&client, true).expect("couldn't get_root"));
        match uptane.get_targets(&client, true) {
            Ok((ts, ts_new)) => {
                assert_eq!(ts_new, true);
                {
                    let meta = ts.targets.get("/{ostree-refname}").expect("no /{ostree-refname} metadata");
                    assert_eq!(meta.length, 31);
                    let hash = meta.hashes.get("sha256").expect("couldn't get sha256 hash");
                    assert_eq!(hash, "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da");
                }
                let custom = uptane.extract_custom(ts.targets);
                let image = custom.get("/{ostree-refname}").expect("couldn't get /{ostree-refname} custom");
                assert_eq!(image.ecuIdentifier, "identifier-file1");
            }

            Err(err) => panic!("couldn't get_targets_director: {}", err)
        }
    }

    #[test]
    fn test_get_snapshot() {
        let mut uptane = Uptane::new(UptaneConfig::default(), "test-get-snapshot".to_string());
        let client = client_from_paths(&[
            "tests/uptane/ed25519/root.json",
            "tests/uptane/ed25519/snapshot.json",
        ]);

        assert!(uptane.get_root(&client, true).expect("couldn't get_root"));
        match uptane.get_snapshot(&client, true) {
            Ok((ss, ss_new)) => {
                assert_eq!(ss_new, true);
                let meta = ss.meta.get("targets.json.gz").expect("no targets.json.gz metadata");
                assert_eq!(meta.length, 599);
                let hash = meta.hashes.get("sha256").expect("couldn't get sha256 hash");
                assert_eq!(hash, "9f8aff5b55ee4b3140360d99b39fa755a3ea640462072b4fd74bdd72e6fe245a");
            }

            Err(err) => panic!("couldn't get_snapshot: {}", err)
        }
    }

    #[test]
    fn test_get_timestamp() {
        let mut uptane = Uptane::new(UptaneConfig::default(), "test-get-timestamp".to_string());
        let client = client_from_paths(&[
            "tests/uptane/ed25519/root.json",
            "tests/uptane/ed25519/timestamp.json",
        ]);

        assert!(uptane.get_root(&client, true).expect("get_root failed"));
        match uptane.get_timestamp(&client, true) {
            Ok((ts, ts_new)) => {
                assert_eq!(ts_new, true);
                let meta = ts.meta.get("snapshot.json").expect("no snapshot.json metadata");
                assert_eq!(meta.length, 1007);
            }

            Err(err) => panic!("couldn't get_timestamp: {}", err)
        }
    }
}
<commit_msg>Must fix. Uptane fetch ignored.<commit_after>use serde_json as json;
use std::collections::HashMap;

use datatype::{Error, Metadata, Role, Root, SignedManifest, SignedMeta, SignedCustom,
               Snapshot, Targets, Timestamp, UptaneConfig, Url, Verifier};
use http::{Client, Response};

/// Last known version of each metadata file.
pub struct Version {
    root:      u64,
    targets:   u64,
    snapshot:  u64,
    timestamp: u64
}

impl Version {
    fn new() -> Self {
        Version { root: 0, targets: 0, snapshot: 0, timestamp: 0 }
    }
}

/// Software over the air updates using Uptane endpoints.
pub struct Uptane {
    uptane_cfg:  UptaneConfig,
    device_uuid: String,
    version:     Version,
    verifier:    Verifier,
}

impl Uptane {
    pub fn new(cfg: UptaneConfig, device_uuid: String) -> Self {
        Uptane {
            uptane_cfg:  cfg,
            device_uuid: device_uuid,
            version:     Version::new(),
            verifier:    Verifier::new(),
        }
    }

    /// If using the director endpoint it returns:
    /// `<director_server>/<endpoint>`,
    /// Otherwise it returns the images server with device uuid:
    /// `<images_server>/<uuid>/<endpoint>`
    fn endpoint(&self, director: bool, endpoint: &str) -> Url {
        if director {
            let ref server = self.uptane_cfg.director_server;
            server.join(&format!("/{}", endpoint))
        } else {
            let ref server = self.uptane_cfg.images_server;
            server.join(&format!("/{}/{}", self.device_uuid, endpoint))
        }
    }

    /// GET the bytes response from the given endpoint.
    fn get_endpoint(&mut self, client: &Client, director: bool, endpoint: &str) -> Result<Vec<u8>, Error> {
        let rx = client.get(self.endpoint(director, endpoint), None);
        match rx.recv().ok_or(Error::Client("couldn't get bytes from endpoint".to_string()))? {
            Response::Success(data) => Ok(data.body),
            Response::Failed(data)  => Err(Error::from(data)),
            Response::Error(err)    => Err(err)
        }
    }

    /// PUT bytes to endpoint.
    fn put_endpoint(&mut self, client: &Client, director: bool, endpoint: &str, bytes: Vec<u8>) -> Result<(), Error> {
        let rx = client.put(self.endpoint(director, endpoint), Some(bytes));
        match rx.recv().ok_or(Error::Client("couldn't put bytes to endpoint".to_string()))? {
            Response::Success(_)   => Ok(()),
            Response::Failed(data) => Err(Error::from(data)),
            Response::Error(err)   => Err(err)
        }
    }

    /// Put a new manifest file to the Director server.
    pub fn put_manifest(&mut self, client: &Client, manifest: SignedManifest) -> Result<(), Error> {
        debug!("put_manifest");
        self.put_endpoint(client, true, "manifest", json::to_vec(&manifest)?)
    }

    /// Add the root.json metadata to the verifier and return a new version indicator.
    pub fn get_root(&mut self, client: &Client, director: bool) -> Result<bool, Error> {
        debug!("get_root");
        let buf  = self.get_endpoint(client, director, "root.json")?;
        let meta = json::from_slice::<Metadata>(&buf)?;
        let root = json::from_value::<Root>(meta.signed.clone())?;

        for (id, key) in root.keys {
            trace!("adding key: {:?}", key);
            self.verifier.add_key(id, key);
        }
        for (role, data) in root.roles {
            trace!("adding roledata: {:?}", data);
            self.verifier.add_role(role, data);
        }

        debug!("checking root keys");
        self.verifier.verify(&Role::Root, &meta, 0)?;
        if root.version > self.version.root {
            debug!("root version increased from {} to {}", self.version.root, root.version);
            self.version.root = root.version;
            Ok(true)
        } else {
            Ok(false)
        }
    }

    /// Get the targets.json metadata and a new version indicator.
    pub fn get_targets(&mut self, client: &Client, director: bool) -> Result<(Targets, bool), Error> {
        debug!("get_targets");
        let buf  = self.get_endpoint(client, director, "targets.json")?;
        let meta = json::from_slice::<Metadata>(&buf)?;
        let targ = json::from_value::<Targets>(meta.signed.clone())?;

        debug!("checking targets keys");
        self.verifier.verify(&Role::Targets, &meta, 0)?;
        if targ.version > self.version.targets {
            debug!("targets version increased from {} to {}", self.version.targets, targ.version);
            self.version.targets = targ.version;
            Ok((targ, true))
        } else {
            Ok((targ, false))
        }
    }

    /// Get the snapshot.json metadata and a new version indicator.
    pub fn get_snapshot(&mut self, client: &Client, director: bool) -> Result<(Snapshot, bool), Error> {
        debug!("get_snapshot");
        let buf  = self.get_endpoint(client, director, "snapshot.json")?;
        let meta = json::from_slice::<Metadata>(&buf)?;
        let snap = json::from_value::<Snapshot>(meta.signed.clone())?;

        debug!("checking snapshot keys");
        self.verifier.verify(&Role::Snapshot, &meta, 0)?;
        if snap.version > self.version.snapshot {
            debug!("snapshot version increased from {} to {}", self.version.snapshot, snap.version);
            self.version.snapshot = snap.version;
            Ok((snap, true))
        } else {
            Ok((snap, false))
        }
    }

    /// Get the timestamp.json metadata and a new version indicator.
    pub fn get_timestamp(&mut self, client: &Client, director: bool) -> Result<(Timestamp, bool), Error> {
        debug!("get_timestamp");
        let buf  = self.get_endpoint(client, director, "timestamp.json")?;
        let meta = json::from_slice::<Metadata>(&buf)?;
        let time = json::from_value::<Timestamp>(meta.signed.clone())?;

        debug!("checking timestamp keys");
        self.verifier.verify(&Role::Timestamp, &meta, 0)?;
        if time.version > self.version.timestamp {
            debug!("timestamp version increased from {} to {}", self.version.timestamp, time.version);
            self.version.timestamp = time.version;
            Ok((time, true))
        } else {
            Ok((time, false))
        }
    }

    pub fn extract_custom(&self, targets: HashMap<String, SignedMeta>) -> HashMap<String, SignedCustom> {
        debug!("extract_custom");
        let mut out = HashMap::new();
        for (file, meta) in targets {
            let _ = meta.custom.map(|c| out.insert(file, c));
        }
        out
    }
}

#[cfg(test)]
mod tests {
    use std::fs::File;
    use std::io::Read;

    use super::*;
    use datatype::{Metadata, SignedManifest, SignedVersion};
    use http::TestClient;

    fn read_file(path: &str) -> Vec<u8> {
        let mut file = File::open(path).unwrap_or_else(|err| panic!("couldn't open path: {}\n{}", path, err));
        let mut buf = Vec::new();
        file.read_to_end(&mut buf).unwrap_or_else(|err| panic!("couldn't read path: {}\n{}", path, err));
        buf
    }

    fn client_from_paths(paths: &[&str]) -> TestClient<Vec<u8>> {
        let mut replies = Vec::new();
        for path in paths {
            replies.push(read_file(path));
        }
        TestClient::from(replies)
    }

    #[test]
    fn test_read_manifest() {
        let bytes = read_file("tests/uptane/ats/manifest.json");
        let meta = json::from_slice::<Metadata>(&bytes).expect("couldn't load manifest");
        let signed = json::from_value::<SignedManifest>(meta.signed).expect("couldn't load signed manifest");
        assert_eq!(signed.primary_ecu_serial, "{ecu serial}");

        let mut metas = json::from_value::<Vec<Metadata>>(signed.ecu_version_manifest).expect("couldn't load ecu_version_manifest");
        assert_eq!(metas.len(), 1);
        let meta1 = metas.pop().unwrap();
        let version = json::from_value::<SignedVersion>(meta1.signed).expect("couldn't load first manifest");
        assert_eq!(version.installed_image.filepath, "/{ostree-refname}");
    }

    #[test]
    #[ignore] /// FIXME: Must fix.
    fn test_get_targets_director() {
        let mut uptane = Uptane::new(UptaneConfig::default(), "test-get-targets-director".to_string());
        let client = client_from_paths(&[
            "tests/uptane/ed25519/root.json",
            "tests/uptane/ats/targets_director.json",
        ]);

        assert!(uptane.get_root(&client, true).expect("couldn't get_root"));
        match uptane.get_targets(&client, true) {
            Ok((ts, ts_new)) => {
                assert_eq!(ts_new, true);
                {
                    let meta = ts.targets.get("/{ostree-refname}").expect("no /{ostree-refname} metadata");
                    assert_eq!(meta.length, 31);
                    let hash = meta.hashes.get("sha256").expect("couldn't get sha256 hash");
                    assert_eq!(hash, "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da");
                }
                let custom = uptane.extract_custom(ts.targets);
                let image = custom.get("/{ostree-refname}").expect("couldn't get /{ostree-refname} custom");
                assert_eq!(image.ecuIdentifier, "identifier-file1");
            }

            Err(err) => panic!("couldn't get_targets_director: {}", err)
        }
    }

    #[test]
    #[ignore] /// FIXME: Must fix.
    fn test_get_snapshot() {
        let mut uptane = Uptane::new(UptaneConfig::default(), "test-get-snapshot".to_string());
        let client = client_from_paths(&[
            "tests/uptane/ed25519/root.json",
            "tests/uptane/ed25519/snapshot.json",
        ]);

        assert!(uptane.get_root(&client, true).expect("couldn't get_root"));
        match uptane.get_snapshot(&client, true) {
            Ok((ss, ss_new)) => {
                assert_eq!(ss_new, true);
                let meta = ss.meta.get("targets.json.gz").expect("no targets.json.gz metadata");
                assert_eq!(meta.length, 599);
                let hash = meta.hashes.get("sha256").expect("couldn't get sha256 hash");
                assert_eq!(hash, "9f8aff5b55ee4b3140360d99b39fa755a3ea640462072b4fd74bdd72e6fe245a");
            }

            Err(err) => panic!("couldn't get_snapshot: {}", err)
        }
    }

    #[test]
    #[ignore] /// FIXME: Must fix.
    fn test_get_timestamp() {
        let mut uptane = Uptane::new(UptaneConfig::default(), "test-get-timestamp".to_string());
        let client = client_from_paths(&[
            "tests/uptane/ed25519/root.json",
            "tests/uptane/ed25519/timestamp.json",
        ]);

        assert!(uptane.get_root(&client, true).expect("get_root failed"));
        match uptane.get_timestamp(&client, true) {
            Ok((ts, ts_new)) => {
                assert_eq!(ts_new, true);
                let meta = ts.meta.get("snapshot.json").expect("no snapshot.json metadata");
                assert_eq!(meta.length, 1007);
            }

            Err(err) => panic!("couldn't get_timestamp: {}", err)
        }
    }
}
<|endoftext|>


<commit_before>use crate::utils::{last_path_segment, span_lint_and_help};
use rustc_hir::{
    intravisit, Body, Expr, ExprKind, FieldPat, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatKind,
    QPath, Stmt, StmtKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{AdtDef, FieldDef, Ty, TyKind, VariantDef};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for patterns that aren't exact representations of the types
    /// they are applied to.
    ///
    /// **Why is this bad?** It isn't bad in general. But in some contexts it can be desirable
    /// because it increases ownership hints in the code, and will guard against some changes
    /// in ownership.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust,ignore
    /// // Bad
    /// let value = &Some(Box::new(23));
    /// match value {
    ///     Some(inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    ///
    /// // Good
    /// let value = &Some(Box::new(23));
    /// match *value {
    ///     Some(ref inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    /// ```
    pub PATTERN_TYPE_MISMATCH,
    restriction,
    "type of pattern does not match the expression type"
}

declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PatternTypeMismatch {
    fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt<'_>) {
        if let StmtKind::Local(ref local) = stmt.kind {
            if let Some(init) = &local.init {
                if let Some(init_ty) = cx.tables().node_type_opt(init.hir_id) {
                    let pat = &local.pat;
                    if in_external_macro(cx.sess(), pat.span) {
                        return;
                    }
                    let deref_possible = match local.source {
                        LocalSource::Normal => DerefPossible::Possible,
                        _ => DerefPossible::Impossible,
                    };
                    apply_lint(cx, pat, init_ty, deref_possible);
                }
            }
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
        if let ExprKind::Match(ref expr, arms, source) = expr.kind {
            match source {
                MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => {
                    if let Some(expr_ty) = cx.tables().node_type_opt(expr.hir_id) {
                        'pattern_checks: for arm in arms {
                            let pat = &arm.pat;
                            if in_external_macro(cx.sess(), pat.span) {
                                continue 'pattern_checks;
                            }
                            if apply_lint(cx, pat, expr_ty, DerefPossible::Possible) {
                                break 'pattern_checks;
                            }
                        }
                    }
                },
                _ => (),
            }
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        _: intravisit::FnKind<'tcx>,
        _: &'tcx FnDecl<'_>,
        body: &'tcx Body<'_>,
        _: Span,
        hir_id: HirId,
    ) {
        if let Some(fn_sig) = cx.tables().liberated_fn_sigs().get(hir_id) {
            for (param, ty) in body.params.iter().zip(fn_sig.inputs().iter()) {
                apply_lint(cx, &param.pat, ty, DerefPossible::Impossible);
            }
        }
    }
}

#[derive(Debug, Clone, Copy)]
enum DerefPossible {
    Possible,
    Impossible,
}

fn apply_lint<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    pat: &Pat<'_>,
    expr_ty: Ty<'tcx>,
    deref_possible: DerefPossible,
) -> bool {
    let maybe_mismatch = find_first_mismatch(cx, pat, expr_ty, Level::Top);
    if let Some((span, mutability, level)) = maybe_mismatch {
        span_lint_and_help(
            cx,
            PATTERN_TYPE_MISMATCH,
            span,
            "type of pattern does not match the expression type",
            None,
            &format!(
                "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings",
                match (deref_possible, level) {
                    (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ",
                    _ => "",
                },
                match mutability {
                    Mutability::Mut => "&mut _",
                    Mutability::Not => "&_",
                },
            ),
        );
        true
    } else {
        false
    }
}

#[derive(Debug, Copy, Clone)]
enum Level {
    Top,
    Lower,
}

#[allow(rustc::usage_of_ty_tykind)]
fn find_first_mismatch<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    pat: &Pat<'_>,
    ty: Ty<'tcx>,
    level: Level,
) -> Option<(Span, Mutability, Level)> {
    if let PatKind::Ref(ref sub_pat, _) = pat.kind {
        if let TyKind::Ref(_, sub_ty, _) = ty.kind {
            return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower);
        }
    }

    if let TyKind::Ref(_, _, mutability) = ty.kind {
        if is_non_ref_pattern(&pat.kind) {
            return Some((pat.span, mutability, level));
        }
    }

    if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref);
            }
        }
    }

    if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref));
                return find_first_mismatch_in_tuple(cx, pats, ty_iter);
            }
        }
    }

    if let PatKind::Tuple(ref pats, _) = pat.kind {
        if let TyKind::Tuple(..) = ty.kind {
            return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields());
        }
    }

    if let PatKind::Or(sub_pats) = pat.kind {
        for pat in sub_pats {
            let maybe_mismatch = find_first_mismatch(cx, pat, ty, level);
            if let Some(mismatch) = maybe_mismatch {
                return Some(mismatch);
            }
        }
    }

    None
}

fn get_variant<'a>(adt_def: &'a AdtDef, qpath: &QPath<'_>) -> Option<&'a VariantDef> {
    if adt_def.is_struct() {
        if let Some(variant) = adt_def.variants.iter().next() {
            return Some(variant);
        }
    }

    if adt_def.is_enum() {
        let pat_ident = last_path_segment(qpath).ident;
        for variant in &adt_def.variants {
            if variant.ident == pat_ident {
                return Some(variant);
            }
        }
    }

    None
}

fn find_first_mismatch_in_tuple<'a, 'tcx, I>(
    cx: &LateContext<'a, 'tcx>,
    pats: &[&Pat<'_>],
    ty_iter_src: I,
) -> Option<(Span, Mutability, Level)>
where
    I: IntoIterator<Item = Ty<'tcx>>,
{
    let mut field_tys = ty_iter_src.into_iter();
    'fields: for pat in pats {
        let field_ty = if let Some(ty) = field_tys.next() {
            ty
        } else {
            break 'fields;
        };

        let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
        if let Some(mismatch) = maybe_mismatch {
            return Some(mismatch);
        }
    }

    None
}

fn find_first_mismatch_in_struct<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    field_pats: &[FieldPat<'_>],
    field_defs: &[FieldDef],
    substs_ref: SubstsRef<'tcx>,
) -> Option<(Span, Mutability, Level)> {
    for field_pat in field_pats {
        'definitions: for field_def in field_defs {
            if field_pat.ident == field_def.ident {
                let field_ty = field_def.ty(cx.tcx, substs_ref);
                let pat = &field_pat.pat;
                let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
                if let Some(mismatch) = maybe_mismatch {
                    return Some(mismatch);
                }
                break 'definitions;
            }
        }
    }

    None
}

fn is_non_ref_pattern(pat_kind: &PatKind<'_>) -> bool {
    match pat_kind {
        PatKind::Struct(..) | PatKind::Tuple(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => true,
        PatKind::Or(sub_pats) => sub_pats.iter().any(|pat| is_non_ref_pattern(&pat.kind)),
        _ => false,
    }
}
<commit_msg>Expanded lint documentation<commit_after>use crate::utils::{last_path_segment, span_lint_and_help};
use rustc_hir::{
    intravisit, Body, Expr, ExprKind, FieldPat, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatKind,
    QPath, Stmt, StmtKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{AdtDef, FieldDef, Ty, TyKind, VariantDef};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for patterns that aren't exact representations of the types
    /// they are applied to.
    ///
    /// To satisfy this lint, you will have to adjust either the expression that is matched
    /// against or the pattern itself, as well as the bindings that are introduced by the
    /// adjusted patterns. For matching you will have to either dereference the expression
    /// with the `*` operator, or amend the patterns to explicitly match against `&<pattern>`
    /// or `&mut <pattern>` depending on the reference mutability. For the bindings you need
    /// to use the inverse. You can leave them as plain bindings if you wish for the value
    /// to be copied, but you must use `ref mut <variable>` or `ref <variable>` to construct
    /// a reference into the matched structure.
    ///
    /// If you are looking for a way to learn about ownership semantics in more detail, it
    /// is recommended to look at IDE options available to you to highlight types, lifetimes
    /// and reference semantics in your code. The available tooling would expose these things
    /// in a general way even outside of the various pattern matching mechanics. Of course
    /// this lint can still be used to highlight areas of interest and ensure a good understanding
    /// of ownership semantics.
    ///
    /// **Why is this bad?** It isn't bad in general. But in some contexts it can be desirable
    /// because it increases ownership hints in the code, and will guard against some changes
    /// in ownership.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// This example shows the basic adjustments necessary to satisfy the lint. Note how
    /// the matched expression is explicitly dereferenced with `*` and the `inner` variable
    /// is bound to a shared borrow via `ref inner`.
    ///
    /// ```rust,ignore
    /// // Bad
    /// let value = &Some(Box::new(23));
    /// match value {
    ///     Some(inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    ///
    /// // Good
    /// let value = &Some(Box::new(23));
    /// match *value {
    ///     Some(ref inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    /// ```
    ///
    /// The following example demonstrates one of the advantages of the more verbose style.
    /// Note how the second version uses `ref mut a` to explicitly declare `a` a shared mutable
    /// borrow, while `b` is simply taken by value. This ensures that the loop body cannot
    /// accidentally modify the wrong part of the structure.
    ///
    /// ```rust,ignore
    /// // Bad
    /// let mut values = vec![(2, 3), (3, 4)];
    /// for (a, b) in &mut values {
    ///     *a += *b;
    /// }
    ///
    /// // Good
    /// let mut values = vec![(2, 3), (3, 4)];
    /// for &mut (ref mut a, b) in &mut values {
    ///     *a += b;
    /// }
    /// ```
    pub PATTERN_TYPE_MISMATCH,
    restriction,
    "type of pattern does not match the expression type"
}

declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PatternTypeMismatch {
    fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt<'_>) {
        if let StmtKind::Local(ref local) = stmt.kind {
            if let Some(init) = &local.init {
                if let Some(init_ty) = cx.tables().node_type_opt(init.hir_id) {
                    let pat = &local.pat;
                    if in_external_macro(cx.sess(), pat.span) {
                        return;
                    }
                    let deref_possible = match local.source {
                        LocalSource::Normal => DerefPossible::Possible,
                        _ => DerefPossible::Impossible,
                    };
                    apply_lint(cx, pat, init_ty, deref_possible);
                }
            }
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
        if let ExprKind::Match(ref expr, arms, source) = expr.kind {
            match source {
                MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => {
                    if let Some(expr_ty) = cx.tables().node_type_opt(expr.hir_id) {
                        'pattern_checks: for arm in arms {
                            let pat = &arm.pat;
                            if in_external_macro(cx.sess(), pat.span) {
                                continue 'pattern_checks;
                            }
                            if apply_lint(cx, pat, expr_ty, DerefPossible::Possible) {
                                break 'pattern_checks;
                            }
                        }
                    }
                },
                _ => (),
            }
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        _: intravisit::FnKind<'tcx>,
        _: &'tcx FnDecl<'_>,
        body: &'tcx Body<'_>,
        _: Span,
        hir_id: HirId,
    ) {
        if let Some(fn_sig) = cx.tables().liberated_fn_sigs().get(hir_id) {
            for (param, ty) in body.params.iter().zip(fn_sig.inputs().iter()) {
                apply_lint(cx, &param.pat, ty, DerefPossible::Impossible);
            }
        }
    }
}

#[derive(Debug, Clone, Copy)]
enum DerefPossible {
    Possible,
    Impossible,
}

fn apply_lint<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    pat: &Pat<'_>,
    expr_ty: Ty<'tcx>,
    deref_possible: DerefPossible,
) -> bool {
    let maybe_mismatch = find_first_mismatch(cx, pat, expr_ty, Level::Top);
    if let Some((span, mutability, level)) = maybe_mismatch {
        span_lint_and_help(
            cx,
            PATTERN_TYPE_MISMATCH,
            span,
            "type of pattern does not match the expression type",
            None,
            &format!(
                "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings",
                match (deref_possible, level) {
                    (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ",
                    _ => "",
                },
                match mutability {
                    Mutability::Mut => "&mut _",
                    Mutability::Not => "&_",
                },
            ),
        );
        true
    } else {
        false
    }
}

#[derive(Debug, Copy, Clone)]
enum Level {
    Top,
    Lower,
}

#[allow(rustc::usage_of_ty_tykind)]
fn find_first_mismatch<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    pat: &Pat<'_>,
    ty: Ty<'tcx>,
    level: Level,
) -> Option<(Span, Mutability, Level)> {
    if let PatKind::Ref(ref sub_pat, _) = pat.kind {
        if let TyKind::Ref(_, sub_ty, _) = ty.kind {
            return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower);
        }
    }

    if let TyKind::Ref(_, _, mutability) = ty.kind {
        if is_non_ref_pattern(&pat.kind) {
            return Some((pat.span, mutability, level));
        }
    }

    if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref);
            }
        }
    }

    if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref));
                return find_first_mismatch_in_tuple(cx, pats, ty_iter);
            }
        }
    }

    if let PatKind::Tuple(ref pats, _) = pat.kind {
        if let TyKind::Tuple(..) = ty.kind {
            return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields());
        }
    }

    if let PatKind::Or(sub_pats) = pat.kind {
        for pat in sub_pats {
            let maybe_mismatch = find_first_mismatch(cx, pat, ty, level);
            if let Some(mismatch) = maybe_mismatch {
                return Some(mismatch);
            }
        }
    }

    None
}

fn get_variant<'a>(adt_def: &'a AdtDef, qpath: &QPath<'_>) -> Option<&'a VariantDef> {
    if adt_def.is_struct() {
        if let Some(variant) = adt_def.variants.iter().next() {
            return Some(variant);
        }
    }

    if adt_def.is_enum() {
        let pat_ident = last_path_segment(qpath).ident;
        for variant in &adt_def.variants {
            if variant.ident == pat_ident {
                return Some(variant);
            }
        }
    }

    None
}

fn find_first_mismatch_in_tuple<'a, 'tcx, I>(
    cx: &LateContext<'a, 'tcx>,
    pats: &[&Pat<'_>],
    ty_iter_src: I,
) -> Option<(Span, Mutability, Level)>
where
    I: IntoIterator<Item = Ty<'tcx>>,
{
    let mut field_tys = ty_iter_src.into_iter();
    'fields: for pat in pats {
        let field_ty = if let Some(ty) = field_tys.next() {
            ty
        } else {
            break 'fields;
        };

        let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
        if let Some(mismatch) = maybe_mismatch {
            return Some(mismatch);
        }
    }

    None
}

fn find_first_mismatch_in_struct<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    field_pats: &[FieldPat<'_>],
    field_defs: &[FieldDef],
    substs_ref: SubstsRef<'tcx>,
) -> Option<(Span, Mutability, Level)> {
    for field_pat in field_pats {
        'definitions: for field_def in field_defs {
            if field_pat.ident == field_def.ident {
                let field_ty = field_def.ty(cx.tcx, substs_ref);
                let pat = &field_pat.pat;
                let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
                if let Some(mismatch) = maybe_mismatch {
                    return Some(mismatch);
                }
                break 'definitions;
            }
        }
    }

    None
}

fn is_non_ref_pattern(pat_kind: &PatKind<'_>) -> bool {
    match pat_kind {
        PatKind::Struct(..) | PatKind::Tuple(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => true,
        PatKind::Or(sub_pats) => sub_pats.iter().any(|pat| is_non_ref_pattern(&pat.kind)),
        _ => false,
    }
}
<|endoftext|>


<commit_before>use std::cmp::max;
use std::f32::consts::PI;

use collect_slice::CollectSlice;

use consts::SAMPLES;
use descramble::VoiceDecisions;
use enhance::EnhancedSpectrals;
use noise::Noise;
use params::BaseParams;
use prev::PrevFrame;
use window;

pub struct PhaseBase([f32; 56]);

impl PhaseBase {
    pub fn new(params: &BaseParams, prev: &PrevFrame) -> PhaseBase {
        let mut phase_base = [0.0; 56];
        let common = (prev.params.fundamental + params.fundamental) *
            SAMPLES as f32 / 2.0;

        (1..57).map(|l| {
            prev.phase_base.get(l) + common * l as f32
        }).collect_slice_checked(&mut phase_base[..]);

        PhaseBase(phase_base)
    }

    pub fn get(&self, l: usize) -> f32 { self.0[l - 1] }
}

impl Default for PhaseBase {
    fn default() -> PhaseBase {
        PhaseBase([0.0; 56])
    }
}

pub struct Phase([f32; 56]);

impl Phase {
    pub fn new(params: &BaseParams, voice: &VoiceDecisions, base: &PhaseBase) -> Phase {
        let mut noise = Noise::new();
        let mut phase = [0.0; 56];

        let trans = params.harmonics as usize / 4;

        (1..trans+1).map(|l| {
            base.get(l)
        }).chain((trans+1..57).map(|l| {
            base.get(l) + voice.unvoiced_count as f32 * noise.next_phase() /
                params.harmonics as f32
        })).collect_slice_checked(&mut phase[..]);

        Phase(phase)
    }

    pub fn get(&self, l: usize) -> f32 { self.0[l - 1] }
}

impl Default for Phase {
    fn default() -> Phase {
        Phase([0.0; 56])
    }
}

pub struct Voiced<'a, 'b, 'c, 'd> {
    prev: &'a PrevFrame,
    phase: &'b Phase,
    enhanced: &'c EnhancedSpectrals,
    voice: &'d VoiceDecisions,
    window: window::Window,
    fundamental: f32,
    end: usize,
    freq_changed: bool,
}

impl<'a, 'b, 'c, 'd> Voiced<'a, 'b, 'c, 'd> {
    pub fn new(params: &BaseParams, prev: &'a PrevFrame, phase: &'b Phase,
               enhanced: &'c EnhancedSpectrals, voice: &'d VoiceDecisions)
        -> Voiced<'a, 'b, 'c, 'd>
    {
        let freq_diff = (params.fundamental - prev.params.fundamental).abs();

        Voiced {
            prev: prev,
            phase: phase,
            enhanced: enhanced,
            voice: voice,
            window: window::synthesis_full(),
            fundamental: params.fundamental,
            end: max(params.harmonics, prev.params.harmonics) as usize + 1,
            freq_changed: freq_diff >= 0.1 * params.fundamental,
        }
    }

    fn get_pair(&self, l: usize, n: isize) -> f32 {
        match (self.voice.is_voiced(l), self.prev.voice.is_voiced(l)) {
            (false, false) => 0.0,
            (false, true) => self.sig_prev(l, n),
            (true, false) => self.sig_cur(l, n),
            (true, true) => if l >= 8 || self.freq_changed {
                self.sig_prev(l, n) + self.sig_cur(l, n)
            } else {
                self.amplitude(l, n) * self.theta(l, n).cos()
            },
        }
    }

    fn sig_cur(&self, l: usize, n: isize) -> f32 {
        self.window.get(n - SAMPLES as isize) * self.enhanced.get(l) * (
            self.fundamental * (n - SAMPLES as isize) as f32 * l as f32 +
                self.phase.get(l)
        ).cos()
    }

    fn sig_prev(&self, l: usize, n: isize) -> f32 {
        self.window.get(n) * self.prev.enhanced.get(l) * (
            self.prev.params.fundamental * n as f32 * l as f32 +
                self.prev.phase.get(l)
        ).cos()
    }

    fn amplitude(&self, l: usize, n: isize) -> f32 {
        self.prev.enhanced.get(l) + n as f32 / SAMPLES as f32 *
            (self.enhanced.get(l) - self.prev.enhanced.get(l))
    }

    fn theta(&self, l: usize, n: isize) -> f32 {
        self.prev.phase.get(l) +
            (self.prev.params.fundamental * l as f32 + self.freq_change(l)) * n as f32 +
            (self.fundamental - self.prev.params.fundamental) *
                l as f32 * (n as f32).powi(2) / (2.0 * SAMPLES as f32)
    }

    fn phase_change(&self, l: usize) -> f32 {
        self.phase.get(l) - self.prev.phase.get(l) - (
            self.prev.params.fundamental + self.fundamental
        ) * l as f32 * SAMPLES as f32 / 2.0
    }

    fn freq_change(&self, l: usize) -> f32 {
        (SAMPLES as f32).recip() * (self.phase_change(l) - 2.0 * PI * (
            (self.phase_change(l) + PI) / (2.0 * PI)
        ).floor())
    }

    pub fn get(&self, n: usize) -> f32 {
        (1..self.end).map(|l| {
            2.0 * self.get_pair(l, n as isize)
        }).fold(0.0, |s, x| s + x)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use params::BaseParams;
    use prev::PrevFrame;
    use descramble::{descramble, Bootstrap};

    #[test]
    fn test_phase_base() {
        let chunks = [
            0b001000010010,
            0b110011001100,
            0b111000111000,
            0b111111111111,
            0b10101110101,
            0b00101111010,
            0b01110111011,
            0b00001000,
        ];

        let b = Bootstrap::new(&chunks);
        let p = BaseParams::new(b.unwrap_period());
        let prev = PrevFrame::default();

        assert!((p.fundamental - 0.17575344).abs() < 0.000001);
        assert!((prev.params.fundamental - 0.0937765407).abs() < 0.000001);

        let pb = PhaseBase::new(&p, &prev);

        assert!((pb.get(1) - 21.56239846).abs() < 0.0001);
        assert!((pb.get(2) - 43.12479691).abs() < 0.0001);
        assert!((pb.get(3) - 64.68719537).abs() < 0.0001);
        assert!((pb.get(4) - 86.24959382).abs() < 0.0001);
        assert!((pb.get(5) - 107.8119923).abs() < 0.0001);
        assert!((pb.get(6) - 129.3743907).abs() < 0.0001);
        assert!((pb.get(20) - 431.2479691).abs() < 0.0001);
        assert!((pb.get(56) - 1207.494314).abs() < 0.001);
    }
}
<commit_msg>Remove (seemingly) arbitrary multiply by 2<commit_after>use std::cmp::max;
use std::f32::consts::PI;

use collect_slice::CollectSlice;

use consts::SAMPLES;
use descramble::VoiceDecisions;
use enhance::EnhancedSpectrals;
use noise::Noise;
use params::BaseParams;
use prev::PrevFrame;
use window;

pub struct PhaseBase([f32; 56]);

impl PhaseBase {
    pub fn new(params: &BaseParams, prev: &PrevFrame) -> PhaseBase {
        let mut phase_base = [0.0; 56];
        let common = (prev.params.fundamental + params.fundamental) *
            SAMPLES as f32 / 2.0;

        (1..57).map(|l| {
            prev.phase_base.get(l) + common * l as f32
        }).collect_slice_checked(&mut phase_base[..]);

        PhaseBase(phase_base)
    }

    pub fn get(&self, l: usize) -> f32 { self.0[l - 1] }
}

impl Default for PhaseBase {
    fn default() -> PhaseBase {
        PhaseBase([0.0; 56])
    }
}

pub struct Phase([f32; 56]);

impl Phase {
    pub fn new(params: &BaseParams, voice: &VoiceDecisions, base: &PhaseBase) -> Phase {
        let mut noise = Noise::new();
        let mut phase = [0.0; 56];

        let trans = params.harmonics as usize / 4;

        (1..trans+1).map(|l| {
            base.get(l)
        }).chain((trans+1..57).map(|l| {
            base.get(l) + voice.unvoiced_count as f32 * noise.next_phase() /
                params.harmonics as f32
        })).collect_slice_checked(&mut phase[..]);

        Phase(phase)
    }

    pub fn get(&self, l: usize) -> f32 { self.0[l - 1] }
}

impl Default for Phase {
    fn default() -> Phase {
        Phase([0.0; 56])
    }
}

pub struct Voiced<'a, 'b, 'c, 'd> {
    prev: &'a PrevFrame,
    phase: &'b Phase,
    enhanced: &'c EnhancedSpectrals,
    voice: &'d VoiceDecisions,
    window: window::Window,
    fundamental: f32,
    end: usize,
    freq_changed: bool,
}

impl<'a, 'b, 'c, 'd> Voiced<'a, 'b, 'c, 'd> {
    pub fn new(params: &BaseParams, prev: &'a PrevFrame, phase: &'b Phase,
               enhanced: &'c EnhancedSpectrals, voice: &'d VoiceDecisions)
        -> Voiced<'a, 'b, 'c, 'd>
    {
        let freq_diff = (params.fundamental - prev.params.fundamental).abs();

        Voiced {
            prev: prev,
            phase: phase,
            enhanced: enhanced,
            voice: voice,
            window: window::synthesis_full(),
            fundamental: params.fundamental,
            end: max(params.harmonics, prev.params.harmonics) as usize + 1,
            freq_changed: freq_diff >= 0.1 * params.fundamental,
        }
    }

    fn get_pair(&self, l: usize, n: isize) -> f32 {
        match (self.voice.is_voiced(l), self.prev.voice.is_voiced(l)) {
            (false, false) => 0.0,
            (false, true) => self.sig_prev(l, n),
            (true, false) => self.sig_cur(l, n),
            (true, true) => if l >= 8 || self.freq_changed {
                self.sig_prev(l, n) + self.sig_cur(l, n)
            } else {
                self.amplitude(l, n) * self.theta(l, n).cos()
            },
        }
    }

    fn sig_cur(&self, l: usize, n: isize) -> f32 {
        self.window.get(n - SAMPLES as isize) * self.enhanced.get(l) * (
            self.fundamental * (n - SAMPLES as isize) as f32 * l as f32 +
                self.phase.get(l)
        ).cos()
    }

    fn sig_prev(&self, l: usize, n: isize) -> f32 {
        self.window.get(n) * self.prev.enhanced.get(l) * (
            self.prev.params.fundamental * n as f32 * l as f32 +
                self.prev.phase.get(l)
        ).cos()
    }

    fn amplitude(&self, l: usize, n: isize) -> f32 {
        self.prev.enhanced.get(l) + n as f32 / SAMPLES as f32 *
            (self.enhanced.get(l) - self.prev.enhanced.get(l))
    }

    fn theta(&self, l: usize, n: isize) -> f32 {
        self.prev.phase.get(l) +
            (self.prev.params.fundamental * l as f32 + self.freq_change(l)) * n as f32 +
            (self.fundamental - self.prev.params.fundamental) *
                l as f32 * (n as f32).powi(2) / (2.0 * SAMPLES as f32)
    }

    fn phase_change(&self, l: usize) -> f32 {
        self.phase.get(l) - self.prev.phase.get(l) - (
            self.prev.params.fundamental + self.fundamental
        ) * l as f32 * SAMPLES as f32 / 2.0
    }

    fn freq_change(&self, l: usize) -> f32 {
        (SAMPLES as f32).recip() * (self.phase_change(l) - 2.0 * PI * (
            (self.phase_change(l) + PI) / (2.0 * PI)
        ).floor())
    }

    pub fn get(&self, n: usize) -> f32 {
        (1..self.end)
            .map(|l| self.get_pair(l, n as isize))
            .fold(0.0, |s, x| s + x)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use params::BaseParams;
    use prev::PrevFrame;
    use descramble::{descramble, Bootstrap};

    #[test]
    fn test_phase_base() {
        let chunks = [
            0b001000010010,
            0b110011001100,
            0b111000111000,
            0b111111111111,
            0b10101110101,
            0b00101111010,
            0b01110111011,
            0b00001000,
        ];

        let b = Bootstrap::new(&chunks);
        let p = BaseParams::new(b.unwrap_period());
        let prev = PrevFrame::default();

        assert!((p.fundamental - 0.17575344).abs() < 0.000001);
        assert!((prev.params.fundamental - 0.0937765407).abs() < 0.000001);

        let pb = PhaseBase::new(&p, &prev);

        assert!((pb.get(1) - 21.56239846).abs() < 0.0001);
        assert!((pb.get(2) - 43.12479691).abs() < 0.0001);
        assert!((pb.get(3) - 64.68719537).abs() < 0.0001);
        assert!((pb.get(4) - 86.24959382).abs() < 0.0001);
        assert!((pb.get(5) - 107.8119923).abs() < 0.0001);
        assert!((pb.get(6) - 129.3743907).abs() < 0.0001);
        assert!((pb.get(20) - 431.2479691).abs() < 0.0001);
        assert!((pb.get(56) - 1207.494314).abs() < 0.001);
    }
}
<|endoftext|>