<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-pass

#![deny(dead_code)]

const LEN: usize = 4;

#[derive(Debug)]
struct Wrapper([u8; LEN]);

fn main() {
    println!("{:?}", Wrapper([0, 1, 2, 3]));
}
<commit_msg>Copyrite<commit_after>// compile-pass

#![deny(dead_code)]

const LEN: usize = 4;

#[derive(Debug)]
struct Wrapper([u8; LEN]);

fn main() {
    println!("{:?}", Wrapper([0, 1, 2, 3]));
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use std::collections::{HashMap, HashSet};
use std::collections::hash_set::Drain;
use std::sync::Arc;

use chrono::UTC;
use futures;
use futures::{Async, Complete, Future, Oneshot, Poll, task};
use futures::IntoFuture;
use futures::stream::{Peekable, Fuse as StreamFuse, Stream};
use futures::task::park;
use rand::Rng;
use rand;
use tokio_core::reactor::Handle;
use tokio_core::channel::{channel, Sender, Receiver};

use ::client::{BasicClientHandle, ClientHandle};
use ::error::*;
use ::rr::{domain, DNSClass, RData, Record, RecordType};
use ::rr::dnssec::Signer;
use ::rr::rdata::NULL;
use ::op::{Edns, Message, MessageType, OpCode, Query, UpdateMessage};
use ::udp::{UdpClientStream, UdpClientStreamHandle};
use ::rr::dnssec::TrustAnchor;
use ::tcp::{TcpClientStream, TcpClientStreamHandle};

pub struct SecureClientHandle {
  client: BasicClientHandle,
  trust_anchor: Arc<TrustAnchor>,
}

impl SecureClientHandle {
  pub fn new(client: BasicClientHandle) -> SecureClientHandle {
    Self::with_trust_anchor(client, TrustAnchor::default())
  }

  pub fn with_trust_anchor(client: BasicClientHandle, trust_anchor: TrustAnchor) -> SecureClientHandle {
    SecureClientHandle {
      client: client,
      trust_anchor: Arc::new(trust_anchor),
    }
  }
}

// let ds_response = try!(self.inner_query(&name, dnskey.get_dns_class(), RecordType::DS, true));
// let ds_rrset: Vec<&Record> = ds_response.get_answers().iter().filter(|rr| rr.get_rr_type() == RecordType::DS).collect();
// let ds_rrsigs: Vec<&Record> = ds_response.get_answers().iter().filter(|rr| rr.get_rr_type() == RecordType::RRSIG).collect();

impl ClientHandle for SecureClientHandle {
  fn send(&self, mut message: Message) -> Box<Future<Item=Message, Error=ClientError>> {
    // dnssec only matters on queries.
    if let OpCode::Query = message.get_op_code() {
      let client = self.client.clone();
      let trust_anchor = self.trust_anchor.clone();

      {
        let edns = message.get_edns_mut();
        edns.set_dnssec_ok(true);
      }

      message.authentic_data(true);
      message.checking_disabled(false);

      return Box::new(
        self.client.send(message)
                   .and_then(move |message_response|{
                     // group the record sets by name and type
                     //  each rrset type needs to validated independently

                     VerifyRrsetsFuture::new(
                       client,
                       trust_anchor,
                       message_response
                     )
                   })
                 )
    }

    self.client.send(message)
  }
}

pub struct VerifyRrsetsFuture {
  client: BasicClientHandle,
  trust_anchor: Arc<TrustAnchor>,
  message_result: Message,
  rrset_types: Vec<(domain::Name, RecordType)>,
}

//unsafe impl Send for VerifyRrsetsFuture {}

impl VerifyRrsetsFuture {
  fn new(
    client: BasicClientHandle,
    trust_anchor: Arc<TrustAnchor>,
    message_result: Message,
  ) -> VerifyRrsetsFuture {
    let mut rrset_types: HashSet<(domain::Name, RecordType)> = HashSet::new();
    for rrset in message_result.get_answers()
                               .iter()
                               .chain(message_result.get_name_servers())
                               .filter(|rr| rr.get_rr_type() != RecordType::RRSIG)
                               .map(|rr| (rr.get_name().clone(), rr.get_rr_type())) {
      rrset_types.insert(rrset);
    }

    VerifyRrsetsFuture{
      client: client,
      trust_anchor: trust_anchor,
      message_result: message_result,
      rrset_types: rrset_types.into_iter().collect(),
    }
  }
}

impl Future for VerifyRrsetsFuture {
  type Item = Message;
  type Error = ClientError;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    // TODO: Can we do this in parallel?
    // HINT: use select_all
    while let Some((name, record_type)) = self.rrset_types.pop() {
      let rrset: Vec<Record> = self.message_result.get_answers()
                                              .iter()
                                              .chain(self.message_result.get_name_servers())
                                              .filter(|rr| rr.get_rr_type() == record_type && rr.get_name() == &name)
                                              .cloned()
                                              .collect();
    }

    // FIXME: make message_result Option so that we can return and not clone.
    Ok(Async::Ready(self.message_result.clone()))
    // Err(ClientErrorKind::Message("unimplemented").into())
  }
}

// pub struct VerifyRrsigFuture {
//   client: ClientHandle,
//   trust_anchor: Rc<TrustAnchor>,
//
//   result: Message,
//   toProveStack: Box<SecureClientFuture>,
// }
//
// impl Future for VerifyRrsigFuture {
//   type Item = Message;
//   type Error = ClientError;
//
//   fn poll(&mut self) -> Poll<Item, Self::Error> {
//     Async::Ready(self.result)
//   }
// }
//
// pub struct VerifyDnsKeyFuture {
//   client: ClientHandle,
//   trust_anchor: TrustAnchor,
//
//   result: Message,
//   toProveStack: Box<SecureClientFuture>,
// }
//
// impl Future for VerifyDnsKeyFuture {
//   type Item = Message;
//   type Error = ClientError;
//
//   fn poll(&mut self) -> Poll<Item, Self::Error> {
//     Async::Ready(self.result)
//   }
// }
//
// pub struct VerifyNsecRrsetsFuture {
//   client: ClientHandle,
//   trust_anchor: AsRef<TrustAnchor>,
//   message_result: Message,
//   rrset_types: HashSet<(domain::Name, RecordType)>,
// }
//
// impl Future for VerifyNsecRrsetsFuture {
//   type Item = Message;
//   type Error = ClientError;
//
//   fn poll(&mut self) -> Poll<Item, Self::Error> {
//     Async::Ready(self.result)
//   }
// }
//
//
// pub struct VerifyNsecFuture {
//
// }
//
// impl Future for VerifyNsecFuture {
//   type Item = Message;
//   type Error = ClientError;
//
//   fn poll(&mut self) -> Poll<Item, Self::Error> {
//     Async::Ready(self.result)
//   }
// }

#[cfg(test)]
pub mod test {
  use std::fmt;
  use std::io;
  use std::net::*;

  use chrono::Duration;
  use futures;
  use futures::{Async, Complete, Future, finished, Oneshot, Poll, task};
  use futures::stream::{Fuse, Stream};
  use futures::task::park;
  use openssl::crypto::pkey::{PKey, Role};
  use tokio_core::reactor::{Core, Handle};
  use tokio_core::channel::{channel, Sender, Receiver};

  use ::client::{ClientFuture, BasicClientHandle, ClientHandle, SecureClientHandle, TestClientStream};
  use ::error::*;
  use ::op::{Message, ResponseCode};
  use ::authority::Catalog;
  use ::authority::authority_tests::{create_example, create_secure_example};
  use ::rr::domain;
  use ::rr::{DNSClass, RData, Record, RecordType};
  use ::rr::dnssec::{Algorithm, Signer, TrustAnchor};
  use ::serialize::binary::{BinDecoder, BinEncoder, BinSerializable};
  use ::udp::{UdpClientStream, UdpClientStreamHandle};
  use ::tcp::{TcpClientStream, TcpClientStreamHandle};

  #[test]
  fn test_secure_query_example_nonet() {
    let authority = create_secure_example();

    let public_key = {
      let signers = authority.get_secure_keys();
      signers.first().expect("expected a key in the authority").get_public_key()
    };

    let mut catalog = Catalog::new();
    catalog.upsert(authority.get_origin().clone(), authority);

    let mut trust_anchor = TrustAnchor::new();
    trust_anchor.insert_trust_anchor(public_key);

    let mut io_loop = Core::new().unwrap();
    let (stream, sender) = TestClientStream::new(catalog, io_loop.handle());
    let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
    let secure_client = SecureClientHandle::with_trust_anchor(client, trust_anchor);

    test_secure_query_example(secure_client, io_loop);
  }

  #[test]
  #[ignore]
  fn test_secure_query_example_udp() {
    let mut io_loop = Core::new().unwrap();
    let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
    let (stream, sender) = UdpClientStream::new(addr, io_loop.handle());
    let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
    let secure_client = SecureClientHandle::new(client);

    test_secure_query_example(secure_client, io_loop);
  }

  #[test]
  #[ignore]
  fn test_secure_query_example_tcp() {
    let mut io_loop = Core::new().unwrap();
    let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
    let (stream, sender) = TcpClientStream::new(addr, io_loop.handle());
    let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
    let secure_client = SecureClientHandle::new(client);

    test_secure_query_example(secure_client, io_loop);
  }

  #[cfg(test)]
  fn test_secure_query_example(client: SecureClientHandle, mut io_loop: Core) {
    let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
    let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A, true)).expect("query failed");

    println!("response records: {:?}", response);
    assert!(response.get_edns().expect("edns not here").is_dnssec_ok());

    let record = &response.get_answers()[0];
    assert_eq!(record.get_name(), &name);
    assert_eq!(record.get_rr_type(), RecordType::A);
    assert_eq!(record.get_dns_class(), DNSClass::IN);

    if let &RData::A(ref address) = record.get_rdata() {
      assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
    } else {
      assert!(false);
    }
  }
}
<commit_msg>Collect based RRSet validation<commit_after>// Copyright 2015-2016 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use std::collections::{HashMap, HashSet};
use std::collections::hash_set::Drain;
use std::mem;
use std::sync::Arc;

use chrono::UTC;
use futures;
use futures::{Async, Complete, Future, Oneshot, Poll, task};
use futures::{collect, Collect, IntoFuture};
use futures::stream::{Peekable, Fuse as StreamFuse, Stream};
use futures::task::park;
use rand::Rng;
use rand;
use tokio_core::reactor::Handle;
use tokio_core::channel::{channel, Sender, Receiver};

use ::client::{BasicClientHandle, ClientHandle};
use ::error::*;
use ::rr::{domain, DNSClass, RData, Record, RecordType};
use ::rr::dnssec::Signer;
use ::rr::rdata::NULL;
use ::op::{Edns, Message, MessageType, OpCode, Query, UpdateMessage};
use ::udp::{UdpClientStream, UdpClientStreamHandle};
use ::rr::dnssec::TrustAnchor;
use ::tcp::{TcpClientStream, TcpClientStreamHandle};

/// A ClientHandle which will return DNSSec validating futures.
#[derive(Clone)]
pub struct SecureClientHandle {
  client: BasicClientHandle,
  trust_anchor: Arc<TrustAnchor>,
}

impl SecureClientHandle {
  pub fn new(client: BasicClientHandle) -> SecureClientHandle {
    Self::with_trust_anchor(client, TrustAnchor::default())
  }

  pub fn with_trust_anchor(client: BasicClientHandle, trust_anchor: TrustAnchor) -> SecureClientHandle {
    SecureClientHandle {
      client: client,
      trust_anchor: Arc::new(trust_anchor),
    }
  }
}

impl ClientHandle for SecureClientHandle {
  fn send(&self, mut message: Message) -> Box<Future<Item=Message, Error=ClientError>> {
    // dnssec only matters on queries.
    if let OpCode::Query = message.get_op_code() {
      let client: SecureClientHandle = self.clone();
      let trust_anchor = self.trust_anchor.clone();

      {
        let edns = message.get_edns_mut();
        edns.set_dnssec_ok(true);
      }

      message.authentic_data(true);
      message.checking_disabled(false);

      return Box::new(
        self.client.send(message)
                   .and_then(move |message_response|{
                     // group the record sets by name and type
                     //  each rrset type needs to validated independently

                     VerifyRrsetsFuture::new(
                       client,
                       trust_anchor,
                       message_response
                     )
                   })
                 )
    }

    self.client.send(message)
  }
}

/// A future to verify all RRSets in a returned Message.
pub struct VerifyRrsetsFuture {
  client: SecureClientHandle,
  trust_anchor: Arc<TrustAnchor>,
  message_result: Option<Message>,
  rrsets: Collect<Vec<VerifyRrsetFuture>>,
}

impl VerifyRrsetsFuture {
  fn new(
    client: SecureClientHandle,
    trust_anchor: Arc<TrustAnchor>,
    message_result: Message,
  ) -> VerifyRrsetsFuture {
    let mut rrset_types: HashSet<(domain::Name, RecordType)> = HashSet::new();
    for rrset in message_result.get_answers()
                               .iter()
                               .chain(message_result.get_name_servers())
                               .filter(|rr| rr.get_rr_type() != RecordType::RRSIG)
                               .map(|rr| (rr.get_name().clone(), rr.get_rr_type())) {
      rrset_types.insert(rrset);
    }

    // collect all the rrsets to verify
    // TODO: is there a way to get rid of this clone() safely?
    let mut rrsets = Vec::with_capacity(rrset_types.len());
    for (name, record_type) in rrset_types {
      let rrset: Vec<Record> = message_result.get_answers()
                                             .iter()
                                             .chain(message_result.get_name_servers())
                                             .filter(|rr| rr.get_rr_type() == record_type &&
                                                          rr.get_name() == &name)
                                             .cloned()
                                             .collect();

      rrsets.push(VerifyRrsetFuture{ name: name, record_type: record_type, rrset: rrset });
    }

    // spawn a select_all over this vec, these are the individual RRSet validators
    let rrsets_to_verify = collect(rrsets);

    // return the full Message validator
    VerifyRrsetsFuture{
      client: client,
      trust_anchor: trust_anchor,
      message_result: Some(message_result),
      rrsets: rrsets_to_verify,
    }
  }
}

impl Future for VerifyRrsetsFuture {
  type Item = Message;
  type Error = ClientError;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    if self.message_result.is_none() {
      return Err(ClientErrorKind::Message("message is none").into())
    }

    // TODO: Can we do this in parallel?
    // HINT: use select_all
    match self.rrsets.poll() {
      Ok(Async::NotReady) => Ok(Async::NotReady),
      // all rrsets verified! woop!
      Ok(Async::Ready(_)) => {
        let message_result = mem::replace(&mut self.message_result, None);
        Ok(Async::Ready(message_result.unwrap())) // validated not none above...
      },
      // TODO, should we return the Message on errors? Allow the consumer to decide what to do
      //       on a validation failure?
      // any error, is an error for all
      Err(e) => Err(e),
    }
  }
}

/// A future for verifying a Rrset
struct VerifyRrsetFuture {
  name: domain::Name,
  record_type: RecordType,
  rrset: Vec<Record>,
}

impl Future for VerifyRrsetFuture {
  type Item = ();
  type Error = ClientError;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    Ok(Async::Ready(()))
  }
}

// pub struct VerifyRrsigFuture {
//   client: ClientHandle,
//   trust_anchor: Rc<TrustAnchor>,
//
//   result: Message,
//   toProveStack: Box<SecureClientFuture>,
// }
//
// impl Future for VerifyRrsigFuture {
//   type Item = Message;
//   type Error = ClientError;
//
//   fn poll(&mut self) -> Poll<Item, Self::Error> {
//     Async::Ready(self.result)
//   }
// }
//
// pub struct VerifyDnsKeyFuture {
//   client: ClientHandle,
//   trust_anchor: TrustAnchor,
//
//   result: Message,
//   toProveStack: Box<SecureClientFuture>,
// }
//
// impl Future for VerifyDnsKeyFuture {
//   type Item = Message;
//   type Error = ClientError;
//
//   fn poll(&mut self) -> Poll<Item, Self::Error> {
//     Async::Ready(self.result)
//   }
// }
//
// pub struct VerifyNsecRrsetsFuture {
//   client: ClientHandle,
//   trust_anchor: AsRef<TrustAnchor>,
//   message_result: Message,
//   rrset_types: HashSet<(domain::Name, RecordType)>,
// }
//
// impl Future for VerifyNsecRrsetsFuture {
//   type Item = Message;
//   type Error = ClientError;
//
//   fn poll(&mut self) -> Poll<Item, Self::Error> {
//     Async::Ready(self.result)
//   }
// }
//
//
// pub struct VerifyNsecFuture {
//
// }
//
// impl Future for VerifyNsecFuture {
//   type Item = Message;
//   type Error = ClientError;
//
//   fn poll(&mut self) -> Poll<Item, Self::Error> {
//     Async::Ready(self.result)
//   }
// }

#[cfg(test)]
pub mod test {
  use std::fmt;
  use std::io;
  use std::net::*;

  use chrono::Duration;
  use futures;
  use futures::{Async, Complete, Future, finished, Oneshot, Poll, task};
  use futures::stream::{Fuse, Stream};
  use futures::task::park;
  use openssl::crypto::pkey::{PKey, Role};
  use tokio_core::reactor::{Core, Handle};
  use tokio_core::channel::{channel, Sender, Receiver};

  use ::client::{ClientFuture, BasicClientHandle, ClientHandle, SecureClientHandle, TestClientStream};
  use ::error::*;
  use ::op::{Message, ResponseCode};
  use ::authority::Catalog;
  use ::authority::authority_tests::{create_example, create_secure_example};
  use ::rr::domain;
  use ::rr::{DNSClass, RData, Record, RecordType};
  use ::rr::dnssec::{Algorithm, Signer, TrustAnchor};
  use ::serialize::binary::{BinDecoder, BinEncoder, BinSerializable};
  use ::udp::{UdpClientStream, UdpClientStreamHandle};
  use ::tcp::{TcpClientStream, TcpClientStreamHandle};

  #[test]
  fn test_secure_query_example_nonet() {
    let authority = create_secure_example();

    let public_key = {
      let signers = authority.get_secure_keys();
      signers.first().expect("expected a key in the authority").get_public_key()
    };

    let mut catalog = Catalog::new();
    catalog.upsert(authority.get_origin().clone(), authority);

    let mut trust_anchor = TrustAnchor::new();
    trust_anchor.insert_trust_anchor(public_key);

    let mut io_loop = Core::new().unwrap();
    let (stream, sender) = TestClientStream::new(catalog, io_loop.handle());
    let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
    let secure_client = SecureClientHandle::with_trust_anchor(client, trust_anchor);

    test_secure_query_example(secure_client, io_loop);
  }

  #[test]
  #[ignore]
  fn test_secure_query_example_udp() {
    let mut io_loop = Core::new().unwrap();
    let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
    let (stream, sender) = UdpClientStream::new(addr, io_loop.handle());
    let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
    let secure_client = SecureClientHandle::new(client);

    test_secure_query_example(secure_client, io_loop);
  }

  #[test]
  #[ignore]
  fn test_secure_query_example_tcp() {
    let mut io_loop = Core::new().unwrap();
    let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
    let (stream, sender) = TcpClientStream::new(addr, io_loop.handle());
    let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
    let secure_client = SecureClientHandle::new(client);

    test_secure_query_example(secure_client, io_loop);
  }

  #[cfg(test)]
  fn test_secure_query_example(client: SecureClientHandle, mut io_loop: Core) {
    let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
    let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A, true)).expect("query failed");

    println!("response records: {:?}", response);
    assert!(response.get_edns().expect("edns not here").is_dnssec_ok());

    let record = &response.get_answers()[0];
    assert_eq!(record.get_name(), &name);
    assert_eq!(record.get_rr_type(), RecordType::A);
    assert_eq!(record.get_dns_class(), DNSClass::IN);

    if let &RData::A(ref address) = record.get_rdata() {
      assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
    } else {
      assert!(false);
    }
  }
}
<|endoftext|>


<commit_before>extern crate "sha1-hasher" as sha1;

use std::os;
use std::io::fs;
use std::io::{File, IoError, IoErrorKind, Reader, Writer, USER_RWX};
use std::io::process::{ProcessOutput, ProcessExit};

const HEADER: &'static [u8] = b"OBCF\x00\x01";
const FOOTER: &'static [u8] = b"END\x00";

pub struct Cache {
	cache_dir: Path
}

impl Cache {
	pub fn new() -> Self {
		let cache_dir = os::homedir().unwrap().join_many(&[".octobuild", "cache"]);
		Cache {
			cache_dir: cache_dir
		}
	}

	pub fn run_cached<F: Fn()->Result<ProcessOutput, IoError>>(&self, params: &str, inputs: &Vec<Path>, outputs: &Vec<Path>, worker: F) -> Result<ProcessOutput, IoError> {
		let hash = try! (generate_hash(params, inputs));
		let path = self.cache_dir.join(hash.slice(0, 2)).join(hash.slice(2, 4)).join(hash.slice_from(4));
		println!("Cache file: {:?}", path);
		// Try to read data from cache.
		match read_cache(&path, outputs) {
			Ok(output) => {return Ok(output)}
			Err(_) => {}
		}
		// Run task and save result to cache.
		let output = try !(worker());
		try !(write_cache(&path, outputs, &output));
		Ok(output)
	}
}

// @todo: Need more safe data writing (size before data).
fn generate_hash(params: &str, inputs: &Vec<Path>) -> Result<String, IoError> {
	use std::hash::Writer;

	let mut hash = sha1::Sha1::new();
	// str
	hash.write(params.as_bytes());
	hash.write(&[0]);
	// inputs
	for input in inputs.iter() {
		let content = try! (File::open(input).read_to_end());
		hash.write(content.as_slice());
		hash.write(&[0]);
	}
	Ok(hash.hexdigest())
}

fn write_cache(path: &Path, paths: &Vec<Path>, output: &ProcessOutput) -> Result<(), IoError> {
	if !output.status.success() {
		return Ok(());
	}
	try! (fs::mkdir_recursive(&path.dir_path(), USER_RWX));
	let mut stream = try! (File::create(path));
	try! (stream.write(HEADER));
	try! (stream.write_le_uint(paths.len()));
	for path in paths.iter() {
		let content = try! (File::open(path).read_to_end());
		try! (write_blob(&mut stream, content.as_slice()));
	}
	try! (write_output(&mut stream, output));
	try! (stream.write(FOOTER));
	try! (stream.flush());
	Ok(())
}

fn read_cache(path: &Path, paths: &Vec<Path>) -> Result<ProcessOutput, IoError> {
	let mut stream = try! (File::open(path));
	if try! (stream.read_exact(HEADER.len())) != HEADER {
		return Err(IoError {
			kind: IoErrorKind::InvalidInput,
			desc: "Invalid cache file header",
			detail: Some(path.display().to_string())
		})
	}
	if try! (stream.read_le_uint()) != paths.len() {
		return Err(IoError {
			kind: IoErrorKind::InvalidInput,
			desc: "Unexpected count of packed cached files",
			detail: Some(path.display().to_string())
		})
	}
	for path in paths.iter() {
		let content = try! (read_blob(&mut stream));
		try! (File::create(path).write(content.as_slice()));
	}
	let output = try! (read_output(&mut stream));
	if try! (stream.read_exact(FOOTER.len())) != FOOTER {
		return Err(IoError {
			kind: IoErrorKind::InvalidInput,
			desc: "Invalid cache file footer",
			detail: Some(path.display().to_string())
		})
	}
	Ok(output)
}

fn write_blob(stream: &mut Writer, blob: &[u8]) -> Result<(), IoError> {
	try! (stream.write_le_uint(blob.len()));
	try! (stream.write(blob));
	Ok(())
}

fn read_blob(stream: &mut Reader) -> Result<Vec<u8>, IoError> {
	let size = try! (stream.read_le_uint());
	stream.read_exact(size)
}

fn write_output(stream: &mut Writer, output: &ProcessOutput) -> Result<(), IoError> {
	try! (write_blob(stream, output.output.as_slice()));
	try! (write_blob(stream, output.error.as_slice()));
	Ok(())
}

fn read_output(stream: &mut Reader) -> Result<ProcessOutput, IoError> {
	let output = try! (read_blob(stream));
	let error  = try! (read_blob(stream));
	Ok(ProcessOutput {
		status: ProcessExit::ExitStatus(0),
		output: output,
		error: error,
	})
}
<commit_msg>Optimize memory usage<commit_after>extern crate "sha1-hasher" as sha1;

use std::os;
use std::io::fs;
use std::io::{File, IoError, IoErrorKind, Reader, Writer, USER_RWX};
use std::io::process::{ProcessOutput, ProcessExit};

const HEADER: &'static [u8] = b"OBCF\x00\x01";
const FOOTER: &'static [u8] = b"END\x00";
const DEFAULT_BUF_SIZE: usize = 1024 * 64;

pub struct Cache {
	cache_dir: Path
}

impl Cache {
	pub fn new() -> Self {
		let cache_dir = os::homedir().unwrap().join_many(&[".octobuild", "cache"]);
		Cache {
			cache_dir: cache_dir
		}
	}

	pub fn run_cached<F: Fn()->Result<ProcessOutput, IoError>>(&self, params: &str, inputs: &Vec<Path>, outputs: &Vec<Path>, worker: F) -> Result<ProcessOutput, IoError> {
		let hash = try! (generate_hash(params, inputs));
		let path = self.cache_dir.join(hash.slice(0, 2)).join(hash.slice(2, 4)).join(hash.slice_from(4));
		println!("Cache file: {:?}", path);
		// Try to read data from cache.
		match read_cache(&path, outputs) {
			Ok(output) => {return Ok(output)}
			Err(_) => {}
		}
		// Run task and save result to cache.
		let output = try !(worker());
		try !(write_cache(&path, outputs, &output));
		Ok(output)
	}
}

// @todo: Need more safe data writing (size before data).
fn generate_hash(params: &str, inputs: &Vec<Path>) -> Result<String, IoError> {
	use std::hash::Writer;

	let mut hash = sha1::Sha1::new();
	// str
	hash.write(params.as_bytes());
	hash.write(&[0]);
	// inputs
	for input in inputs.iter() {
		let mut file = try! (File::open(input));
		let mut buf: [u8; DEFAULT_BUF_SIZE] = [0; DEFAULT_BUF_SIZE];
		loop {
			match file.read(&mut buf) {
				Ok(size) => {
					hash.write(&buf.as_slice()[0..size]);
				}
				Err(ref e) if e.kind == IoErrorKind::EndOfFile => break,
				Err(e) => return Err(e)
			}
		}
		hash.write(&[0]);
	}
	Ok(hash.hexdigest())
}

fn write_cache(path: &Path, paths: &Vec<Path>, output: &ProcessOutput) -> Result<(), IoError> {
	if !output.status.success() {
		return Ok(());
	}
	try! (fs::mkdir_recursive(&path.dir_path(), USER_RWX));
	let mut stream = try! (File::create(path));
	try! (stream.write(HEADER));
	try! (stream.write_le_uint(paths.len()));
	for path in paths.iter() {
		let content = try! (File::open(path).read_to_end());
		try! (write_blob(&mut stream, content.as_slice()));
	}
	try! (write_output(&mut stream, output));
	try! (stream.write(FOOTER));
	try! (stream.flush());
	Ok(())
}

fn read_cache(path: &Path, paths: &Vec<Path>) -> Result<ProcessOutput, IoError> {
	let mut stream = try! (File::open(path));
	if try! (stream.read_exact(HEADER.len())) != HEADER {
		return Err(IoError {
			kind: IoErrorKind::InvalidInput,
			desc: "Invalid cache file header",
			detail: Some(path.display().to_string())
		})
	}
	if try! (stream.read_le_uint()) != paths.len() {
		return Err(IoError {
			kind: IoErrorKind::InvalidInput,
			desc: "Unexpected count of packed cached files",
			detail: Some(path.display().to_string())
		})
	}
	for path in paths.iter() {
		let content = try! (read_blob(&mut stream));
		try! (File::create(path).write(content.as_slice()));
	}
	let output = try! (read_output(&mut stream));
	if try! (stream.read_exact(FOOTER.len())) != FOOTER {
		return Err(IoError {
			kind: IoErrorKind::InvalidInput,
			desc: "Invalid cache file footer",
			detail: Some(path.display().to_string())
		})
	}
	Ok(output)
}

fn write_blob(stream: &mut Writer, blob: &[u8]) -> Result<(), IoError> {
	try! (stream.write_le_uint(blob.len()));
	try! (stream.write(blob));
	Ok(())
}

fn read_blob(stream: &mut Reader) -> Result<Vec<u8>, IoError> {
	let size = try! (stream.read_le_uint());
	stream.read_exact(size)
}

fn write_output(stream: &mut Writer, output: &ProcessOutput) -> Result<(), IoError> {
	try! (write_blob(stream, output.output.as_slice()));
	try! (write_blob(stream, output.error.as_slice()));
	Ok(())
}

fn read_output(stream: &mut Reader) -> Result<ProcessOutput, IoError> {
	let output = try! (read_blob(stream));
	let error  = try! (read_blob(stream));
	Ok(ProcessOutput {
		status: ProcessExit::ExitStatus(0),
		output: output,
		error: error,
	})
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::fmt::{Debug, Formatter, Result as FmtResult};

use rand::{thread_rng, Rng};
use sdl2::Sdl;
use sdl2::rect::Rect;
use ep::FromPrimitive;

use screen::Screen;
use instruction::{Opcodes, Instruction};

const FONT_SET: [u8; 80] = [
    0xf0, 0x90, 0x90, 0x90, 0xf0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xf0, 0x10, 0xf0, 0x80, 0xf0, // 2
    0xf0, 0x10, 0xf0, 0x10, 0xf0, // 3
    0x90, 0x90, 0xf0, 0x10, 0x10, // 4
    0xf0, 0x80, 0xf0, 0x10, 0xf0, // 5
    0xf0, 0x80, 0xf0, 0x90, 0xf0, // 6
    0xf0, 0x10, 0x20, 0x40, 0x40, // 7
    0xf0, 0x90, 0xf0, 0x90, 0xf0, // 8
    0xf0, 0x90, 0xf0, 0x10, 0xf0, // 9
    0xf0, 0x90, 0xf0, 0x90, 0x90, // A
    0xe0, 0x90, 0xe0, 0x90, 0xe0, // B
    0xf0, 0x80, 0x80, 0x80, 0x80, // C
    0xe0, 0x90, 0x90, 0x90, 0xe0, // D
    0xf0, 0x80, 0xf0, 0x80, 0xf0, // E
    0xf0, 0x80, 0xf0, 0x80, 0x80, // F
];

pub struct Chip8<'a> {
    regs:   [u8; 16],
    i:      u16,
    dt:     u8,
    st:     u8,
    pc:     usize,

    inst:   Instruction,
    jmp:    bool,

    keys:   [u8; 16],
    mem:    [u8; 4096],
    stack:  Vec<usize>,
    screen: Screen<'a>,
}

impl<'a> Debug for Chip8<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        self.regs[..].fmt(f)
    }
}

impl<'a> Chip8<'a> {
    pub fn new(sdl: &Sdl) -> Chip8<'a> {
        Chip8 {
            regs:   [0; 16],
            i:      0,
            dt:     0,
            st:     0,
            pc:     0x200,
            inst:   Instruction::new(),
            jmp:    false,
            keys:   [0; 16],
            mem:    [0; 4096],
            stack:  vec![],
            screen: Screen::new(sdl),
        }
    }

    pub fn load_rom(&mut self, path: &str) {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(Path::new(path)).unwrap();
        file.read_to_end(&mut rom).unwrap();
        for i in 0usize..rom.len() {
            self.mem[0x200 + i] = rom[i];
        }
        // TODO: move this
        for i in 0usize..FONT_SET.len() {
            self.mem[0x00 + i] = FONT_SET[i];
        }
    }

    pub fn run(&mut self) {
        let raw_data = (self.mem[self.pc], self.mem[self.pc +1]);
        self.inst.decode(raw_data);

        self.jmp  = false;

        println!("{:#x}: {:#x}", self.pc, self.inst.opcode);

        match Opcodes::from_u16(self.inst.opcode).unwrap() {
            Opcodes::CLS    => self.cls(),
            Opcodes::RET    => self.ret(),
            Opcodes::JMP    => self.jmp(),
            Opcodes::JMP_VA => self.jmp_va(),
            Opcodes::CALL   => self.call(),
            Opcodes::SE_VB  => self.se_vb(),
            Opcodes::SE_VV  => self.se_vv(),
            Opcodes::SNE_VB => self.sne_vb(),
            Opcodes::SNE_VV => self.sne_vv(),
            Opcodes::OR     => self.or(),
            Opcodes::ADD_VB => self.add_vb(),
            Opcodes::ADD_VV => self.add_vv(),
            Opcodes::ADD_IV => self.add_iv(),
            Opcodes::SUB    => self.sub(),
            Opcodes::XOR    => self.xor(),
            Opcodes::AND    => self.and(),
            Opcodes::LD_VB  => self.ld_vb(),
            Opcodes::LD_BV  => self.ld_bv(),
            Opcodes::LD_VV  => self.ld_vv(),
            Opcodes::LD_VI  => self.ld_vi(),
            Opcodes::LD_VK  => self.ld_vk(),
            Opcodes::LD_IV  => self.ld_iv(),
            Opcodes::LD_FV  => self.ld_fv(),
            Opcodes::LD_IA  => self.ld_ia(),
            Opcodes::LD_VDT => self.ld_vdt(),
            Opcodes::LD_DTV => self.ld_dtv(),
            Opcodes::LD_STV => self.ld_stv(),
            Opcodes::SKP    => self.skp(),
            Opcodes::SKNP   => self.sknp(),
            Opcodes::RND    => self.rnd(),
            Opcodes::SHR    => self.shr(),
            Opcodes::DRW    => self.drw(),
            _               => panic!("Unrecognized opcode: {:?}", self.inst.opcode),
        }

        if !self.jmp { self.inc_pc(); }

        if self.dt > 0 { self.dt -= 1; }
        if self.st > 0 { self.st -= 1; }
    }

    fn set_pc(&mut self, addr: u16) {
        self.pc = addr as usize;
    }

    fn inc_pc(&mut self) {
        self.pc += 2;
    }

    fn dec_pc(&mut self) {
        self.pc -= 2;
    }

    fn cls(&mut self) {
        self.screen.clear();
    }

    fn ret(&mut self) {
        let addr = self.stack.pop().unwrap();
        self.set_pc(addr as u16);
    }

    fn jmp(&mut self) {
        let addr = self.inst.nnn;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn jmp_va(&mut self) {
        let offset = self.regs[0] as u16;
        let addr = self.inst.nnn + offset;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn call(&mut self) {
        let old_addr = self.pc;
        let cur_addr = self.inst.nnn;
        self.stack.push(old_addr);
        self.set_pc(cur_addr);
        self.jmp = true;
    }

    fn se_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] == self.inst.kk {
            self.inc_pc();
        }
    }

    fn se_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] == self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn sne_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] != self.inst.kk {
            self.inc_pc();
        }
    }

    fn sne_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] != self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn or(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] |= self.regs[idx_y]
    }

    fn and(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] &= self.regs[idx_y];
    }

    fn add_vb(&mut self) {
        let idx_x = self.inst.x;

        // TODO: I guess this shouldn't be this way
        let res = self.regs[idx_x]  as u16 + self.inst.kk as u16;

        if res > 0xFF {
            self.regs[idx_x] = (res & 0xFF) as u8;
        } else {
            self.regs[idx_x] += self.inst.kk;
        }
    }

    fn add_vv(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x] as u16;
        let y = self.regs[self.inst.y] as u16;

        let res = x + y;
        if res > 0xFF {
            self.regs[15] = 1;
        } else {
            self.regs[15] = 0;
        }

        self.regs[idx_x] = res as u8;
    }

    fn add_iv(&mut self) {
        let idx = self.inst.x;
        let x   = self.regs[idx] as u16;
        self.regs[15] = if (self.i + x) > 0xFFF { 1 } else { 0 };
        self.i += x;
    }

    fn sub(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let x = self.regs[idx_x];
        let y = self.regs[idx_y];

        self.regs[15] = if x > y { 1 } else { 0 };

        if x <= y { self.regs[idx_x] = 0; }
        else { self.regs[idx_x] -= y; }
    }

    fn xor(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] ^= self.regs[idx_y];
    }

    fn shr(&mut self) {
        let idx_x = self.inst.x;
        let vx    = self.regs[idx_x];
        if vx & 0x01 == 0 {
            self.regs[15] = 1;
        }
        self.regs[idx_x] = vx >> 1;
    }

    fn ld_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] = self.regs[idx_y];
    }

    fn ld_vb(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.inst.kk;
    }

    fn ld_bv(&mut self) {
        let idx = self.inst.x;
        let mut vx  = self.regs[idx];
        let mut hundred = 100;

        for i in 0usize..3 {
            let bcd = vx / hundred;
            self.mem[self.i as usize + i] = bcd;
            vx -= bcd * hundred;
            hundred /= 10;
        }
    }

    fn ld_fv(&mut self) {
        let x = self.regs[self.inst.x];
        self.i = (x * 5) as u16;
    }

    fn ld_vi(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.regs[i] = self.mem[self.i as usize + i];
        }
    }

    fn ld_iv(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.mem[self.i as usize + i] = self.regs[i];
        }
    }

    fn ld_ia(&mut self) {
        self.i = self.inst.nnn;
    }

    fn ld_vk(&mut self) {
        let mut key_pressed = false;

        for i in 0..self.keys.len() {
            if self.keys[i] == 1 {
                self.regs[self.inst.x] = i as u8;
                key_pressed = true;
            }
        }

        if !key_pressed {
            self.dec_pc();
        }
    }

    fn ld_vdt(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.dt;
    }

    fn ld_dtv(&mut self) {
        let idx: usize = self.inst.x;
        self.dt = self.regs[idx];
    }

    fn ld_stv(&mut self) {
        let idx = self.inst.x;
        self.st = self.regs[idx];
    }

    fn rnd(&mut self) {
        let idx = self.inst.x;
        let byte = self.inst.kk;
        let n: u8 = thread_rng().gen_range(0,255);
        self.regs[idx] = n & byte;
    }

    fn drw(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let (x, y) = (self.regs[idx_x] as usize, self.regs[idx_y] as usize);
        let n = self.inst.n as usize;

        self.screen.renderer.clear();
        self.regs[15] = 0;

        for i in 0..n {
            let px = self.mem[(self.i + i as u16) as usize];
            for j in 0..8 {
                if px & (0x80 >> j) != 0 {
                    if self.screen.buffer[(x+j + (y+i) * 64) as usize] == 1 {
                        self.regs[15] = 1;
                    }
                    self.screen.buffer[(x+j + (y+i) * 64) as usize] ^= 1;
                }
            }
        }

        for i in 0usize..320 {
            for j in 0usize..640 {
                if self.screen.buffer[(j/10)+(i/10)*64] == 1 {
                    self.screen.renderer.fill_rect(
                        Rect::new(j as i32, i as i32, 1, 1)
                        );
                }
            }
        }

        self.screen.draw();
    }

    fn skp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 1{
            self.inc_pc();
        }
    }

    fn sknp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 0 {
            self.inc_pc();
        }
    }
    pub fn reset_keys(&mut self) {
        self.keys = [0;16];
    }

    pub fn press(&mut self, key: u8) {
        self.keys[key as usize] = 1;
    }
}
<commit_msg>optimized SHR instruction<commit_after>#![allow(dead_code)]

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::fmt::{Debug, Formatter, Result as FmtResult};

use rand::{thread_rng, Rng};
use sdl2::Sdl;
use sdl2::rect::Rect;
use ep::FromPrimitive;

use screen::Screen;
use instruction::{Opcodes, Instruction};

const FONT_SET: [u8; 80] = [
    0xf0, 0x90, 0x90, 0x90, 0xf0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xf0, 0x10, 0xf0, 0x80, 0xf0, // 2
    0xf0, 0x10, 0xf0, 0x10, 0xf0, // 3
    0x90, 0x90, 0xf0, 0x10, 0x10, // 4
    0xf0, 0x80, 0xf0, 0x10, 0xf0, // 5
    0xf0, 0x80, 0xf0, 0x90, 0xf0, // 6
    0xf0, 0x10, 0x20, 0x40, 0x40, // 7
    0xf0, 0x90, 0xf0, 0x90, 0xf0, // 8
    0xf0, 0x90, 0xf0, 0x10, 0xf0, // 9
    0xf0, 0x90, 0xf0, 0x90, 0x90, // A
    0xe0, 0x90, 0xe0, 0x90, 0xe0, // B
    0xf0, 0x80, 0x80, 0x80, 0x80, // C
    0xe0, 0x90, 0x90, 0x90, 0xe0, // D
    0xf0, 0x80, 0xf0, 0x80, 0xf0, // E
    0xf0, 0x80, 0xf0, 0x80, 0x80, // F
];

pub struct Chip8<'a> {
    regs:   [u8; 16],
    i:      u16,
    dt:     u8,
    st:     u8,
    pc:     usize,

    inst:   Instruction,
    jmp:    bool,

    keys:   [u8; 16],
    mem:    [u8; 4096],
    stack:  Vec<usize>,
    screen: Screen<'a>,
}

impl<'a> Debug for Chip8<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        self.regs[..].fmt(f)
    }
}

impl<'a> Chip8<'a> {
    pub fn new(sdl: &Sdl) -> Chip8<'a> {
        Chip8 {
            regs:   [0; 16],
            i:      0,
            dt:     0,
            st:     0,
            pc:     0x200,
            inst:   Instruction::new(),
            jmp:    false,
            keys:   [0; 16],
            mem:    [0; 4096],
            stack:  vec![],
            screen: Screen::new(sdl),
        }
    }

    pub fn load_rom(&mut self, path: &str) {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(Path::new(path)).unwrap();
        file.read_to_end(&mut rom).unwrap();
        for i in 0usize..rom.len() {
            self.mem[0x200 + i] = rom[i];
        }
        // TODO: move this
        for i in 0usize..FONT_SET.len() {
            self.mem[0x00 + i] = FONT_SET[i];
        }
    }

    pub fn run(&mut self) {
        let raw_data = (self.mem[self.pc], self.mem[self.pc +1]);
        self.inst.decode(raw_data);

        self.jmp  = false;

        println!("{:#x}: {:#x}", self.pc, self.inst.opcode);

        match Opcodes::from_u16(self.inst.opcode).unwrap() {
            Opcodes::CLS    => self.cls(),
            Opcodes::RET    => self.ret(),
            Opcodes::JMP    => self.jmp(),
            Opcodes::JMP_VA => self.jmp_va(),
            Opcodes::CALL   => self.call(),
            Opcodes::SE_VB  => self.se_vb(),
            Opcodes::SE_VV  => self.se_vv(),
            Opcodes::SNE_VB => self.sne_vb(),
            Opcodes::SNE_VV => self.sne_vv(),
            Opcodes::OR     => self.or(),
            Opcodes::ADD_VB => self.add_vb(),
            Opcodes::ADD_VV => self.add_vv(),
            Opcodes::ADD_IV => self.add_iv(),
            Opcodes::SUB    => self.sub(),
            Opcodes::XOR    => self.xor(),
            Opcodes::AND    => self.and(),
            Opcodes::LD_VB  => self.ld_vb(),
            Opcodes::LD_BV  => self.ld_bv(),
            Opcodes::LD_VV  => self.ld_vv(),
            Opcodes::LD_VI  => self.ld_vi(),
            Opcodes::LD_VK  => self.ld_vk(),
            Opcodes::LD_IV  => self.ld_iv(),
            Opcodes::LD_FV  => self.ld_fv(),
            Opcodes::LD_IA  => self.ld_ia(),
            Opcodes::LD_VDT => self.ld_vdt(),
            Opcodes::LD_DTV => self.ld_dtv(),
            Opcodes::LD_STV => self.ld_stv(),
            Opcodes::SKP    => self.skp(),
            Opcodes::SKNP   => self.sknp(),
            Opcodes::RND    => self.rnd(),
            Opcodes::SHR    => self.shr(),
            Opcodes::DRW    => self.drw(),
            _               => panic!("Unrecognized opcode: {:?}", self.inst.opcode),
        }

        if !self.jmp { self.inc_pc(); }

        if self.dt > 0 { self.dt -= 1; }
        if self.st > 0 { self.st -= 1; }
    }

    fn set_pc(&mut self, addr: u16) {
        self.pc = addr as usize;
    }

    fn inc_pc(&mut self) {
        self.pc += 2;
    }

    fn dec_pc(&mut self) {
        self.pc -= 2;
    }

    fn cls(&mut self) {
        self.screen.clear();
    }

    fn ret(&mut self) {
        let addr = self.stack.pop().unwrap();
        self.set_pc(addr as u16);
    }

    fn jmp(&mut self) {
        let addr = self.inst.nnn;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn jmp_va(&mut self) {
        let offset = self.regs[0] as u16;
        let addr = self.inst.nnn + offset;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn call(&mut self) {
        let old_addr = self.pc;
        let cur_addr = self.inst.nnn;
        self.stack.push(old_addr);
        self.set_pc(cur_addr);
        self.jmp = true;
    }

    fn se_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] == self.inst.kk {
            self.inc_pc();
        }
    }

    fn se_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] == self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn sne_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] != self.inst.kk {
            self.inc_pc();
        }
    }

    fn sne_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] != self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn or(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] |= self.regs[idx_y]
    }

    fn and(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] &= self.regs[idx_y];
    }

    fn add_vb(&mut self) {
        let idx_x = self.inst.x;

        // TODO: I guess this shouldn't be this way
        let res = self.regs[idx_x]  as u16 + self.inst.kk as u16;

        if res > 0xFF {
            self.regs[idx_x] = (res & 0xFF) as u8;
        } else {
            self.regs[idx_x] += self.inst.kk;
        }
    }

    fn add_vv(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x] as u16;
        let y = self.regs[self.inst.y] as u16;

        let res = x + y;
        if res > 0xFF {
            self.regs[15] = 1;
        } else {
            self.regs[15] = 0;
        }

        self.regs[idx_x] = res as u8;
    }

    fn add_iv(&mut self) {
        let idx = self.inst.x;
        let x   = self.regs[idx] as u16;
        self.regs[15] = if (self.i + x) > 0xFFF { 1 } else { 0 };
        self.i += x;
    }

    fn sub(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let x = self.regs[idx_x];
        let y = self.regs[idx_y];

        self.regs[15] = if x > y { 1 } else { 0 };

        if x <= y { self.regs[idx_x] = 0; }
        else { self.regs[idx_x] -= y; }
    }

    fn xor(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] ^= self.regs[idx_y];
    }

    fn shr(&mut self) {
        let idx_x = self.inst.x;
        let x     = self.regs[idx_x];
        self.regs[15] = x & 0x1;
        self.regs[idx_x] = x >> 1;
    }

    fn ld_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] = self.regs[idx_y];
    }

    fn ld_vb(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.inst.kk;
    }

    fn ld_bv(&mut self) {
        let idx = self.inst.x;
        let mut vx  = self.regs[idx];
        let mut hundred = 100;

        for i in 0usize..3 {
            let bcd = vx / hundred;
            self.mem[self.i as usize + i] = bcd;
            vx -= bcd * hundred;
            hundred /= 10;
        }
    }

    fn ld_fv(&mut self) {
        let x = self.regs[self.inst.x];
        self.i = (x * 5) as u16;
    }

    fn ld_vi(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.regs[i] = self.mem[self.i as usize + i];
        }
    }

    fn ld_iv(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.mem[self.i as usize + i] = self.regs[i];
        }
    }

    fn ld_ia(&mut self) {
        self.i = self.inst.nnn;
    }

    fn ld_vk(&mut self) {
        let mut key_pressed = false;

        for i in 0..self.keys.len() {
            if self.keys[i] == 1 {
                self.regs[self.inst.x] = i as u8;
                key_pressed = true;
            }
        }

        if !key_pressed {
            self.dec_pc();
        }
    }

    fn ld_vdt(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.dt;
    }

    fn ld_dtv(&mut self) {
        let idx: usize = self.inst.x;
        self.dt = self.regs[idx];
    }

    fn ld_stv(&mut self) {
        let idx = self.inst.x;
        self.st = self.regs[idx];
    }

    fn rnd(&mut self) {
        let idx = self.inst.x;
        let byte = self.inst.kk;
        let n: u8 = thread_rng().gen_range(0,255);
        self.regs[idx] = n & byte;
    }

    fn drw(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let (x, y) = (self.regs[idx_x] as usize, self.regs[idx_y] as usize);
        let n = self.inst.n as usize;

        self.screen.renderer.clear();
        self.regs[15] = 0;

        for i in 0..n {
            let px = self.mem[(self.i + i as u16) as usize];
            for j in 0..8 {
                if px & (0x80 >> j) != 0 {
                    if self.screen.buffer[(x+j + (y+i) * 64) as usize] == 1 {
                        self.regs[15] = 1;
                    }
                    self.screen.buffer[(x+j + (y+i) * 64) as usize] ^= 1;
                }
            }
        }

        for i in 0usize..320 {
            for j in 0usize..640 {
                if self.screen.buffer[(j/10)+(i/10)*64] == 1 {
                    self.screen.renderer.fill_rect(
                        Rect::new(j as i32, i as i32, 1, 1)
                        );
                }
            }
        }

        self.screen.draw();
    }

    fn skp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 1{
            self.inc_pc();
        }
    }

    fn sknp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 0 {
            self.inc_pc();
        }
    }
    pub fn reset_keys(&mut self) {
        self.keys = [0;16];
    }

    pub fn press(&mut self, key: u8) {
        self.keys[key as usize] = 1;
    }
}
<|endoftext|>


<commit_before>//! CSS angle values.

use std::f64::consts::*;

use cssparser::{Parser, Token};

use crate::error::*;
use crate::parsers::{finite_f32, Parse};

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Angle(f64);

impl Angle {
    pub fn new(rad: f64) -> Angle {
        Angle(Angle::normalize(rad))
    }

    pub fn from_degrees(deg: f64) -> Angle {
        Angle(Angle::normalize(deg.to_radians()))
    }

    pub fn from_vector(vx: f64, vy: f64) -> Angle {
        let rad = vy.atan2(vx);

        if rad.is_nan() {
            Angle(0.0)
        } else {
            Angle(Angle::normalize(rad))
        }
    }

    pub fn radians(self) -> f64 {
        self.0
    }

    pub fn bisect(&self, other: Angle) -> Angle {
        let half_delta = (other.0 - self.0) * 0.5;

        if FRAC_PI_2 < half_delta.abs() {
            Angle(Angle::normalize(self.0 + half_delta - PI))
        } else {
            Angle(Angle::normalize(self.0 + half_delta))
        }
    }

    // Normalizes an angle to [0.0, 2*PI)
    fn normalize(rad: f64) -> f64 {
        let res = rad % (PI * 2.0);
        if res.abs() < std::f64::EPSILON {
            res.abs()
        } else if res < 0.0 {
            res + PI * 2.0
        } else {
            res
        }
    }
}

// angle:
// https://www.w3.org/TR/SVG/types.html#DataTypeAngle
//
// angle ::= number ("deg" | "grad" | "rad")?
//
impl Parse for Angle {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Angle, ParseError<'i>> {
        let angle = {
            let loc = parser.current_source_location();

            let token = parser.next()?;

            match *token {
                Token::Number { value, .. } => {
                    let degrees = finite_f32(value).map_err(|e| loc.new_custom_error(e))?;
                    Angle::from_degrees(f64::from(degrees))
                }

                Token::Dimension {
                    value, ref unit, ..
                } => {
                    let value = f64::from(finite_f32(value).map_err(|e| loc.new_custom_error(e))?);

                    match unit.as_ref() {
                        "deg" => Angle::from_degrees(value),
                        "grad" => Angle::from_degrees(value * 360.0 / 400.0),
                        "rad" => Angle::new(value),
                        _ => {
                            return Err(loc.new_unexpected_token_error(token.clone()));
                        }
                    }
                }

                _ => return Err(loc.new_unexpected_token_error(token.clone())),
            }
        };

        parser.expect_exhausted()?;

        Ok(angle)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use float_cmp::ApproxEq;
    use std::f64;

    #[test]
    fn parses_angle() {
        assert_eq!(Angle::parse_str("0"), Ok(Angle::new(0.0)));
        assert_eq!(Angle::parse_str("15"), Ok(Angle::from_degrees(15.0)));
        assert_eq!(Angle::parse_str("180.5deg"), Ok(Angle::from_degrees(180.5)));
        assert_eq!(Angle::parse_str("1rad"), Ok(Angle::new(1.0)));
        assert_eq!(
            Angle::parse_str("-400grad"),
            Ok(Angle::from_degrees(-360.0))
        );

        assert!(Angle::parse_str("").is_err());
        assert!(Angle::parse_str("foo").is_err());
        assert!(Angle::parse_str("300foo").is_err());
    }

    fn test_bisection_angle(
        expected: f64,
        incoming_vx: f64,
        incoming_vy: f64,
        outgoing_vx: f64,
        outgoing_vy: f64,
    ) {
        let i = Angle::from_vector(incoming_vx, incoming_vy);
        let o = Angle::from_vector(outgoing_vx, outgoing_vy);
        let bisected = i.bisect(o);
        assert!(expected.approx_eq(bisected.radians(), (2.0 * PI * f64::EPSILON, 1)));
    }

    #[test]
    fn bisection_angle_is_correct_from_incoming_counterclockwise_to_outgoing() {
        // 1st quadrant
        test_bisection_angle(FRAC_PI_4, 1.0, 0.0, 0.0, 1.0);

        // 2nd quadrant
        test_bisection_angle(FRAC_PI_2 + FRAC_PI_4, 0.0, 1.0, -1.0, 0.0);

        // 3rd quadrant
        test_bisection_angle(PI + FRAC_PI_4, -1.0, 0.0, 0.0, -1.0);

        // 4th quadrant
        test_bisection_angle(PI + FRAC_PI_2 + FRAC_PI_4, 0.0, -1.0, 1.0, 0.0);
    }

    #[test]
    fn bisection_angle_is_correct_from_incoming_clockwise_to_outgoing() {
        // 1st quadrant
        test_bisection_angle(FRAC_PI_4, 0.0, 1.0, 1.0, 0.0);

        // 2nd quadrant
        test_bisection_angle(FRAC_PI_2 + FRAC_PI_4, -1.0, 0.0, 0.0, 1.0);

        // 3rd quadrant
        test_bisection_angle(PI + FRAC_PI_4, 0.0, -1.0, -1.0, 0.0);

        // 4th quadrant
        test_bisection_angle(PI + FRAC_PI_2 + FRAC_PI_4, 1.0, 0.0, 0.0, -1.0);
    }

    #[test]
    fn bisection_angle_is_correct_for_more_than_quarter_turn_angle() {
        test_bisection_angle(0.0, 0.1, -1.0, 0.1, 1.0);

        test_bisection_angle(FRAC_PI_2, 1.0, 0.1, -1.0, 0.1);

        test_bisection_angle(PI, -0.1, 1.0, -0.1, -1.0);

        test_bisection_angle(PI + FRAC_PI_2, -1.0, -0.1, 1.0, -0.1);
    }
}
<commit_msg>angle: take bisect param by value<commit_after>//! CSS angle values.

use std::f64::consts::*;

use cssparser::{Parser, Token};

use crate::error::*;
use crate::parsers::{finite_f32, Parse};

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Angle(f64);

impl Angle {
    pub fn new(rad: f64) -> Angle {
        Angle(Angle::normalize(rad))
    }

    pub fn from_degrees(deg: f64) -> Angle {
        Angle(Angle::normalize(deg.to_radians()))
    }

    pub fn from_vector(vx: f64, vy: f64) -> Angle {
        let rad = vy.atan2(vx);

        if rad.is_nan() {
            Angle(0.0)
        } else {
            Angle(Angle::normalize(rad))
        }
    }

    pub fn radians(self) -> f64 {
        self.0
    }

    pub fn bisect(self, other: Angle) -> Angle {
        let half_delta = (other.0 - self.0) * 0.5;

        if FRAC_PI_2 < half_delta.abs() {
            Angle(Angle::normalize(self.0 + half_delta - PI))
        } else {
            Angle(Angle::normalize(self.0 + half_delta))
        }
    }

    // Normalizes an angle to [0.0, 2*PI)
    fn normalize(rad: f64) -> f64 {
        let res = rad % (PI * 2.0);
        if res.abs() < std::f64::EPSILON {
            res.abs()
        } else if res < 0.0 {
            res + PI * 2.0
        } else {
            res
        }
    }
}

// angle:
// https://www.w3.org/TR/SVG/types.html#DataTypeAngle
//
// angle ::= number ("deg" | "grad" | "rad")?
//
impl Parse for Angle {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Angle, ParseError<'i>> {
        let angle = {
            let loc = parser.current_source_location();

            let token = parser.next()?;

            match *token {
                Token::Number { value, .. } => {
                    let degrees = finite_f32(value).map_err(|e| loc.new_custom_error(e))?;
                    Angle::from_degrees(f64::from(degrees))
                }

                Token::Dimension {
                    value, ref unit, ..
                } => {
                    let value = f64::from(finite_f32(value).map_err(|e| loc.new_custom_error(e))?);

                    match unit.as_ref() {
                        "deg" => Angle::from_degrees(value),
                        "grad" => Angle::from_degrees(value * 360.0 / 400.0),
                        "rad" => Angle::new(value),
                        _ => {
                            return Err(loc.new_unexpected_token_error(token.clone()));
                        }
                    }
                }

                _ => return Err(loc.new_unexpected_token_error(token.clone())),
            }
        };

        parser.expect_exhausted()?;

        Ok(angle)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use float_cmp::ApproxEq;
    use std::f64;

    #[test]
    fn parses_angle() {
        assert_eq!(Angle::parse_str("0"), Ok(Angle::new(0.0)));
        assert_eq!(Angle::parse_str("15"), Ok(Angle::from_degrees(15.0)));
        assert_eq!(Angle::parse_str("180.5deg"), Ok(Angle::from_degrees(180.5)));
        assert_eq!(Angle::parse_str("1rad"), Ok(Angle::new(1.0)));
        assert_eq!(
            Angle::parse_str("-400grad"),
            Ok(Angle::from_degrees(-360.0))
        );

        assert!(Angle::parse_str("").is_err());
        assert!(Angle::parse_str("foo").is_err());
        assert!(Angle::parse_str("300foo").is_err());
    }

    fn test_bisection_angle(
        expected: f64,
        incoming_vx: f64,
        incoming_vy: f64,
        outgoing_vx: f64,
        outgoing_vy: f64,
    ) {
        let i = Angle::from_vector(incoming_vx, incoming_vy);
        let o = Angle::from_vector(outgoing_vx, outgoing_vy);
        let bisected = i.bisect(o);
        assert!(expected.approx_eq(bisected.radians(), (2.0 * PI * f64::EPSILON, 1)));
    }

    #[test]
    fn bisection_angle_is_correct_from_incoming_counterclockwise_to_outgoing() {
        // 1st quadrant
        test_bisection_angle(FRAC_PI_4, 1.0, 0.0, 0.0, 1.0);

        // 2nd quadrant
        test_bisection_angle(FRAC_PI_2 + FRAC_PI_4, 0.0, 1.0, -1.0, 0.0);

        // 3rd quadrant
        test_bisection_angle(PI + FRAC_PI_4, -1.0, 0.0, 0.0, -1.0);

        // 4th quadrant
        test_bisection_angle(PI + FRAC_PI_2 + FRAC_PI_4, 0.0, -1.0, 1.0, 0.0);
    }

    #[test]
    fn bisection_angle_is_correct_from_incoming_clockwise_to_outgoing() {
        // 1st quadrant
        test_bisection_angle(FRAC_PI_4, 0.0, 1.0, 1.0, 0.0);

        // 2nd quadrant
        test_bisection_angle(FRAC_PI_2 + FRAC_PI_4, -1.0, 0.0, 0.0, 1.0);

        // 3rd quadrant
        test_bisection_angle(PI + FRAC_PI_4, 0.0, -1.0, -1.0, 0.0);

        // 4th quadrant
        test_bisection_angle(PI + FRAC_PI_2 + FRAC_PI_4, 1.0, 0.0, 0.0, -1.0);
    }

    #[test]
    fn bisection_angle_is_correct_for_more_than_quarter_turn_angle() {
        test_bisection_angle(0.0, 0.1, -1.0, 0.1, 1.0);

        test_bisection_angle(FRAC_PI_2, 1.0, 0.1, -1.0, 0.1);

        test_bisection_angle(PI, -0.1, 1.0, -0.1, -1.0);

        test_bisection_angle(PI + FRAC_PI_2, -1.0, -0.1, 1.0, -0.1);
    }
}
<|endoftext|>


<commit_before>use cairo;
use cairo::{PatternTrait, Rectangle};
use markup5ever::local_name;
use std::cell::{Cell, RefCell};

use crate::allowed_url::Href;
use crate::aspect_ratio::AspectRatio;
use crate::bbox::BoundingBox;
use crate::drawing_ctx::{ClipMode, DrawingCtx};
use crate::error::{NodeError, RenderingError};
use crate::float_eq_cairo::ApproxEqCairo;
use crate::length::{LengthHorizontal, LengthVertical};
use crate::node::*;
use crate::parsers::{ParseError, ParseValue};
use crate::property_bag::PropertyBag;
use crate::rect::RectangleExt;
use crate::viewbox::ViewBox;

#[derive(Default)]
pub struct NodeImage {
    aspect: Cell<AspectRatio>,
    x: Cell<LengthHorizontal>,
    y: Cell<LengthVertical>,
    w: Cell<LengthHorizontal>,
    h: Cell<LengthVertical>,
    href: RefCell<Option<Href>>,
}

impl NodeTrait for NodeImage {
    fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        for (attr, value) in pbag.iter() {
            match attr {
                local_name!("x") => self.x.set(attr.parse(value)?),
                local_name!("y") => self.y.set(attr.parse(value)?),
                local_name!("width") => self
                    .w
                    .set(attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?),
                local_name!("height") => self
                    .h
                    .set(attr.parse_and_validate(value, LengthVertical::check_nonnegative)?),

                local_name!("preserveAspectRatio") => self.aspect.set(attr.parse(value)?),

                // "path" is used by some older Adobe Illustrator versions
                local_name!("xlink:href") | local_name!("path") => {
                    let href = Href::parse(value).map_err(|_| {
                        NodeError::parse_error(attr, ParseError::new("could not parse href"))
                    })?;

                    *self.href.borrow_mut() = Some(href);
                }

                _ => (),
            }
        }

        Ok(())
    }

    fn overflow_hidden(&self) -> bool {
        true
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<(), RenderingError> {
        let values = cascaded.get();
        let params = draw_ctx.get_view_params();

        let x = self.x.get().normalize(values, &params);
        let y = self.y.get().normalize(values, &params);
        let w = self.w.get().normalize(values, &params);
        let h = self.h.get().normalize(values, &params);

        if w.approx_eq_cairo(&0.0) || h.approx_eq_cairo(&0.0) {
            return Ok(());
        }

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            let surface = if let Some(Href::PlainUrl(ref url)) = *self.href.borrow() {
                dc.lookup_image(&url)?
            } else {
                return Ok(());
            };

            let aspect = self.aspect.get();

            let clip_mode = if !values.is_overflow() && aspect.is_slice() {
                Some(ClipMode::ClipToViewport)
            } else {
                None
            };

            let image_width = surface.width();
            let image_height = surface.height();
            if clipping || image_width == 0 || image_height == 0 {
                return Ok(());
            }

            // The bounding box for <image> is decided by the values of x, y, w, h and not by
            // the final computed image bounds.
            let bbox = BoundingBox::new(&dc.get_cairo_context().get_matrix()).with_rect(Some(
                cairo::Rectangle {
                    x,
                    y,
                    width: w,
                    height: h,
                },
            ));

            dc.with_saved_cr(&mut |dc| {
                let cr = dc.get_cairo_context();

                let image_width = f64::from(image_width);
                let image_height = f64::from(image_height);

                if let Some(_params) = dc.push_new_viewport(
                    Some(ViewBox::new(0.0, 0.0, image_width, image_height)),
                    &Rectangle::new(x, y, w, h),
                    aspect,
                    clip_mode,
                ) {
                    // We need to set extend appropriately, so can't use cr.set_source_surface().
                    //
                    // If extend is left at its default value (None), then bilinear scaling uses
                    // transparency outside of the image producing incorrect results.
                    // For example, in svg1.1/filters-blend-01-b.svgthere's a completely
                    // opaque 100×1 image of a gradient scaled to 100×98 which ends up
                    // transparent almost everywhere without this fix (which it shouldn't).
                    let ptn = surface.to_cairo_pattern();
                    ptn.set_extend(cairo::Extend::Pad);
                    cr.set_source(&ptn);

                    // Clip is needed due to extend being set to pad.
                    cr.rectangle(0.0, 0.0, image_width, image_height);
                    cr.clip();

                    cr.paint();
                }

                Ok(())
            })
            .and_then(|()| {
                dc.insert_bbox(&bbox);
                Ok(())
            })
        })
    }
}
<commit_msg>image: remove interior mutability<commit_after>use cairo;
use cairo::{PatternTrait, Rectangle};
use markup5ever::local_name;

use crate::allowed_url::Href;
use crate::aspect_ratio::AspectRatio;
use crate::bbox::BoundingBox;
use crate::drawing_ctx::{ClipMode, DrawingCtx};
use crate::error::{NodeError, RenderingError};
use crate::float_eq_cairo::ApproxEqCairo;
use crate::length::{LengthHorizontal, LengthVertical};
use crate::node::*;
use crate::parsers::{ParseError, ParseValue};
use crate::property_bag::PropertyBag;
use crate::rect::RectangleExt;
use crate::viewbox::ViewBox;

#[derive(Default)]
pub struct NodeImage {
    x: LengthHorizontal,
    y: LengthVertical,
    w: LengthHorizontal,
    h: LengthVertical,
    aspect: AspectRatio,
    href: Option<Href>,
}

impl NodeTrait for NodeImage {
    fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        for (attr, value) in pbag.iter() {
            match attr {
                local_name!("x") => self.x = attr.parse(value)?,
                local_name!("y") => self.y = attr.parse(value)?,
                local_name!("width") => {
                    self.w = attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?
                }
                local_name!("height") => {
                    self.h = attr.parse_and_validate(value, LengthVertical::check_nonnegative)?
                }
                local_name!("preserveAspectRatio") => self.aspect = attr.parse(value)?,

                // "path" is used by some older Adobe Illustrator versions
                local_name!("xlink:href") | local_name!("path") => {
                    let href = Href::parse(value).map_err(|_| {
                        NodeError::parse_error(attr, ParseError::new("could not parse href"))
                    })?;

                    self.href = Some(href);
                }

                _ => (),
            }
        }

        Ok(())
    }

    fn overflow_hidden(&self) -> bool {
        true
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<(), RenderingError> {
        let values = cascaded.get();
        let params = draw_ctx.get_view_params();

        let x = self.x.normalize(values, &params);
        let y = self.y.normalize(values, &params);
        let w = self.w.normalize(values, &params);
        let h = self.h.normalize(values, &params);

        if w.approx_eq_cairo(&0.0) || h.approx_eq_cairo(&0.0) {
            return Ok(());
        }

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            let surface = if let Some(Href::PlainUrl(ref url)) = self.href {
                dc.lookup_image(&url)?
            } else {
                return Ok(());
            };

            let clip_mode = if !values.is_overflow() && self.aspect.is_slice() {
                Some(ClipMode::ClipToViewport)
            } else {
                None
            };

            let image_width = surface.width();
            let image_height = surface.height();
            if clipping || image_width == 0 || image_height == 0 {
                return Ok(());
            }

            // The bounding box for <image> is decided by the values of x, y, w, h and not by
            // the final computed image bounds.
            let bbox = BoundingBox::new(&dc.get_cairo_context().get_matrix()).with_rect(Some(
                cairo::Rectangle {
                    x,
                    y,
                    width: w,
                    height: h,
                },
            ));

            dc.with_saved_cr(&mut |dc| {
                let cr = dc.get_cairo_context();

                let image_width = f64::from(image_width);
                let image_height = f64::from(image_height);

                if let Some(_params) = dc.push_new_viewport(
                    Some(ViewBox::new(0.0, 0.0, image_width, image_height)),
                    &Rectangle::new(x, y, w, h),
                    self.aspect,
                    clip_mode,
                ) {
                    // We need to set extend appropriately, so can't use cr.set_source_surface().
                    //
                    // If extend is left at its default value (None), then bilinear scaling uses
                    // transparency outside of the image producing incorrect results.
                    // For example, in svg1.1/filters-blend-01-b.svgthere's a completely
                    // opaque 100×1 image of a gradient scaled to 100×98 which ends up
                    // transparent almost everywhere without this fix (which it shouldn't).
                    let ptn = surface.to_cairo_pattern();
                    ptn.set_extend(cairo::Extend::Pad);
                    cr.set_source(&ptn);

                    // Clip is needed due to extend being set to pad.
                    cr.rectangle(0.0, 0.0, image_width, image_height);
                    cr.clip();

                    cr.paint();
                }

                Ok(())
            })
            .and_then(|()| {
                dc.insert_bbox(&bbox);
                Ok(())
            })
        })
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::iter::Map;
use std::io::BufReader;
use std::fs::File;

use serde_json;

use cgmath::*;
use shape::*;
use vec3d::Vec3d;
use vec3d::Rotatable;
use light::Light;

use color;
use color::Color;

#[derive(Serialize, Deserialize)]
pub struct Scene {
    shapes: Vec<Shape>,
    lights: Vec<Light>,
    camera_pos: Vec3d,
    camera_dir: Vec3d,
    camera_up: Vec3d,
    max_reflection: i32,
}

#[derive(Debug)]
pub enum CraycrayError {
    Io(io::Error),
    Serde(serde_json::Error),
}

impl Scene {
    pub fn new(camera_pos: Vec3d, camera_dir: Vec3d, camera_up: Vec3d) -> Scene {
        Scene {
            shapes: Vec::new(),
            lights: Vec::new(),
            camera_pos: camera_pos,
            camera_dir: camera_dir,
            camera_up: camera_up,
            max_reflection: 4,
        }
    }

    pub fn from_file(filename: &str) -> Result<Scene, CraycrayError> {
        File::open(filename)
            .map_err(CraycrayError::Io)
            .and_then(|f| serde_json::from_reader(BufReader::new(f)).map_err(CraycrayError::Serde))
    }

    pub fn add_shape(&mut self, s: Shape) {
        self.shapes.push(s);
    }

    pub fn step(&mut self) {
        // self.light.translate(&[1.0, 0.0, 0.0]);
    }

    pub fn mv_camera_fwd(&mut self) {
        self.camera_pos = self.camera_pos + self.camera_dir;
    }

    pub fn mv_camera_back(&mut self) {
        self.camera_pos = self.camera_pos - self.camera_dir;
    }

    pub fn rot_camera(&mut self, x_rot: f64, y_rot: f64) {
        // project camera_dir to X plane
        let mut x_proj = self.camera_dir;
        x_proj.y = 0.0;
        x_proj = x_proj.normalize();

        let angle = if x_proj.x < 0.0 {
            -Vec3d::new(0.0, 0.0, 1.0).dot(x_proj).acos()
        } else {
            Vec3d::new(0.0, 0.0, 1.0).dot(x_proj).acos()
        };

        self.camera_dir = self.camera_dir
            .rot_y(x_rot)
            .rot_y(-angle)
            .rot_x(y_rot)
            .rot_y(angle)
            .normalize();
    }

    /// Returns an iterator for a line at given resolution
    pub fn line_iter(&self, h: usize, v: usize, l: usize) -> LineIter {
        LineIter::new(self, h, v, l)
    }

    /// line_iter converted to (u8, u8, u8)
    pub fn line_iter_u8(&self,
                        h: usize,
                        v: usize,
                        l: usize)
                        -> Map<LineIter, fn(Color) -> (u8, u8, u8)> {
        self.line_iter(h, v, l).map(Color::col_to_u8)
    }

    // Recursively trace lines
    fn trace(&self, point: Vec3d, dir: Vec3d, depth: i32) -> Color {
        if depth >= self.max_reflection {
            return color::BLACK;
        }

        if let Some(intersect) = self.closest_q(point, dir) {
            let local = self.lights
                .iter()
                .filter(|l| {
                         let (f_unit, dist) = l.feeler(intersect.point);
                         self.is_direct_light(intersect.point, f_unit, dist)
                     })
                .map(|l| phong(point, &intersect, l))
                .sum::<Color>() + intersect.material.ambient_color;

            let tmp = (intersect.point - point).normalize();
            let reflection_dir = tmp - (intersect.normal * 2.0 * tmp.dot(intersect.normal));

            let reflected = self.trace(intersect.point, reflection_dir, depth + 1);

            local + (reflected * intersect.material.reflectivity)
        } else {
            color::BLACK
        }
    }

    // Is there anything on the path to the light
    fn is_direct_light(&self, point: Vec3d, dir: Vec3d, dl: f64) -> bool {
        !self.shapes
             .iter()
             .map(|&ref x| x.intersect_dist(point, dir))
             .any(|dist_opt| dist_opt.map_or(false, |i| i < dl))
    }

    // Checks against all objects and returns closest intersection
    fn closest_q(&self, point: Vec3d, dir: Vec3d) -> Option<Intersection> {
        let find_min_opt = |min, (idx, op_val)| {
            match (min, op_val) {
                (Some((_, min_val)), Some(val)) if val < min_val => Some((idx, val)),
                (None, Some(val)) => Some((idx, val)),
                _ => min,
            }
        };

        self.shapes
            .iter()
            .map(|x| x.intersect_dist(point, dir))
            .enumerate()
            .fold(None, find_min_opt)
            .and_then(|(idx, _)| self.shapes[idx].intersect(point, dir))
    }
}

/// Iterator that iterates over a single line
pub struct LineIter<'a> {
    h_res: usize,
    x: usize,
    right_step: Vec3d,
    point: Vec3d,
    scene: &'a Scene,
}

impl<'a> LineIter<'a> {
    fn new(scene: &Scene, h: usize, v: usize, l: usize) -> LineIter {
        let left = scene.camera_dir.cross(scene.camera_up).normalize();
        let up = left.cross(scene.camera_dir).normalize();
        let mut point = left + up + scene.camera_dir;
        let right_step = left * (-2.0 / h as f64);
        let down_step = up * (-2.0 / v as f64);

        point = point + down_step * (l as f64);
        LineIter {
            h_res: h,
            x: 0,
            point: point,
            right_step: right_step,
            scene: scene,
        }
    }
}

impl<'a> Iterator for LineIter<'a> {
    type Item = Color;

    fn next(&mut self) -> Option<Self::Item> {
        if self.x >= self.h_res {
            return None;
        }
        self.x += 1;

        self.point = self.point + self.right_step;

        let c = self.scene
            .trace(self.scene.camera_pos, self.point.normalize(), 0);

        Some(c)
    }
}

// Calculate color with Phong model
fn phong(view_point: Vec3d, intersection: &Intersection, light: &Light) -> Color {
    let point_material = intersection.material;
    let light_pos = light.get_pos();
    let light_color = light.get_color();

    let mut d = (light_pos - intersection.point)
        .normalize()
        .dot(intersection.normal);

    if d < 0.0 {
        d = 0.0;
    }

    let v = (view_point - intersection.point).normalize();
    let lt = (light_pos - intersection.point).normalize();
    let r = intersection.normal * (2.0 * intersection.normal.dot(lt)) - lt;

    let mut s = r.dot(v).powf(point_material.shininess);
    if s < 0.0 {
        s = 0.0;
    }

    let diffuse = light_color * point_material.diffuse_color * d;
    let specular = light_color * point_material.specular_color * s;

    diffuse + specular
}
<commit_msg>Fix performance hit<commit_after>use std::io;
use std::iter::Map;
use std::io::BufReader;
use std::fs::File;

use serde_json;

use cgmath::*;
use shape::*;
use vec3d::Vec3d;
use vec3d::Rotatable;
use light::Light;

use color;
use color::Color;

#[derive(Serialize, Deserialize)]
pub struct Scene {
    shapes: Vec<Shape>,
    lights: Vec<Light>,
    camera_pos: Vec3d,
    camera_dir: Vec3d,
    camera_up: Vec3d,
    max_reflection: i32,
}

#[derive(Debug)]
pub enum CraycrayError {
    Io(io::Error),
    Serde(serde_json::Error),
}

impl Scene {
    pub fn new(camera_pos: Vec3d, camera_dir: Vec3d, camera_up: Vec3d) -> Scene {
        Scene {
            shapes: Vec::new(),
            lights: Vec::new(),
            camera_pos: camera_pos,
            camera_dir: camera_dir,
            camera_up: camera_up,
            max_reflection: 4,
        }
    }

    pub fn from_file(filename: &str) -> Result<Scene, CraycrayError> {
        File::open(filename)
            .map_err(CraycrayError::Io)
            .and_then(|f| serde_json::from_reader(BufReader::new(f)).map_err(CraycrayError::Serde))
    }

    pub fn add_shape(&mut self, s: Shape) {
        self.shapes.push(s);
    }

    pub fn step(&mut self) {
        // self.light.translate(&[1.0, 0.0, 0.0]);
    }

    pub fn mv_camera_fwd(&mut self) {
        self.camera_pos = self.camera_pos + self.camera_dir;
    }

    pub fn mv_camera_back(&mut self) {
        self.camera_pos = self.camera_pos - self.camera_dir;
    }

    pub fn rot_camera(&mut self, x_rot: f64, y_rot: f64) {
        // project camera_dir to X plane
        let mut x_proj = self.camera_dir;
        x_proj.y = 0.0;
        x_proj = x_proj.normalize();

        let angle = if x_proj.x < 0.0 {
            -Vec3d::new(0.0, 0.0, 1.0).dot(x_proj).acos()
        } else {
            Vec3d::new(0.0, 0.0, 1.0).dot(x_proj).acos()
        };

        self.camera_dir = self.camera_dir
            .rot_y(x_rot)
            .rot_y(-angle)
            .rot_x(y_rot)
            .rot_y(angle)
            .normalize();
    }

    /// Returns an iterator for a line at given resolution
    pub fn line_iter(&self, h: usize, v: usize, l: usize) -> LineIter {
        LineIter::new(self, h, v, l)
    }

    /// line_iter converted to (u8, u8, u8)
    pub fn line_iter_u8(&self,
                        h: usize,
                        v: usize,
                        l: usize)
                        -> Map<LineIter, fn(Color) -> (u8, u8, u8)> {
        self.line_iter(h, v, l).map(Color::col_to_u8)
    }

    // Recursively trace lines
    fn trace(&self, point: Vec3d, dir: Vec3d, depth: i32) -> Color {
        if depth >= self.max_reflection {
            return color::BLACK;
        }

        if let Some(intersect) = self.closest_q(point, dir) {
            let local = self.lights
                .iter()
                .map(|l| {
                         let (f_unit, dist) = l.feeler(intersect.point);
                         let direct_light = self.is_direct_light(intersect.point, f_unit, dist);
                         if direct_light {
                             phong(point, &intersect, l)
                         } else {
                             color::BLACK
                         }
                     })
                .sum::<Color>() + intersect.material.ambient_color;

            let tmp = (intersect.point - point).normalize();
            let reflection_dir = tmp - (intersect.normal * 2.0 * tmp.dot(intersect.normal));

            let reflected = self.trace(intersect.point, reflection_dir, depth + 1);

            local + (reflected * intersect.material.reflectivity)
        } else {
            color::BLACK
        }
    }

    // Is there anything on the path to the light
    fn is_direct_light(&self, point: Vec3d, dir: Vec3d, dl: f64) -> bool {
        !self.shapes
             .iter()
             .map(|&ref x| x.intersect_dist(point, dir))
             .any(|dist_opt| dist_opt.map_or(false, |i| i < dl))
    }

    // Checks against all objects and returns closest intersection
    fn closest_q(&self, point: Vec3d, dir: Vec3d) -> Option<Intersection> {
        let find_min_opt = |min, (idx, op_val)| {
            match (min, op_val) {
                (Some((_, min_val)), Some(val)) if val < min_val => Some((idx, val)),
                (None, Some(val)) => Some((idx, val)),
                _ => min,
            }
        };

        self.shapes
            .iter()
            .map(|x| x.intersect_dist(point, dir))
            .enumerate()
            .fold(None, find_min_opt)
            .and_then(|(idx, _)| self.shapes[idx].intersect(point, dir))
    }
}

/// Iterator that iterates over a single line
pub struct LineIter<'a> {
    h_res: usize,
    x: usize,
    right_step: Vec3d,
    point: Vec3d,
    scene: &'a Scene,
}

impl<'a> LineIter<'a> {
    fn new(scene: &Scene, h: usize, v: usize, l: usize) -> LineIter {
        let left = scene.camera_dir.cross(scene.camera_up).normalize();
        let up = left.cross(scene.camera_dir).normalize();
        let mut point = left + up + scene.camera_dir;
        let right_step = left * (-2.0 / h as f64);
        let down_step = up * (-2.0 / v as f64);

        point = point + down_step * (l as f64);
        LineIter {
            h_res: h,
            x: 0,
            point: point,
            right_step: right_step,
            scene: scene,
        }
    }
}

impl<'a> Iterator for LineIter<'a> {
    type Item = Color;

    fn next(&mut self) -> Option<Self::Item> {
        if self.x >= self.h_res {
            return None;
        }
        self.x += 1;

        self.point = self.point + self.right_step;

        let c = self.scene
            .trace(self.scene.camera_pos, self.point.normalize(), 0);

        Some(c)
    }
}

// Calculate color with Phong model
fn phong(view_point: Vec3d, intersection: &Intersection, light: &Light) -> Color {
    let point_material = intersection.material;
    let light_pos = light.get_pos();
    let light_color = light.get_color();

    let mut d = (light_pos - intersection.point)
        .normalize()
        .dot(intersection.normal);

    if d < 0.0 {
        d = 0.0;
    }

    let v = (view_point - intersection.point).normalize();
    let lt = (light_pos - intersection.point).normalize();
    let r = intersection.normal * (2.0 * intersection.normal.dot(lt)) - lt;

    let mut s = r.dot(v).powf(point_material.shininess);
    if s < 0.0 {
        s = 0.0;
    }

    let diffuse = light_color * point_material.diffuse_color * d;
    let specular = light_color * point_material.specular_color * s;

    diffuse + specular
}
<|endoftext|>


<commit_before>//! Crate **ruma_identifiers** contains types for [Matrix](https://matrix.org/) identifiers
//! for events, rooms, room aliases, room versions, and users.

#![warn(rust_2018_idioms)]
#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    //missing_docs
)]
// Since we support Rust 1.36.0, we can't apply this suggestion yet
#![allow(clippy::use_self)]
#![cfg_attr(docsrs, feature(doc_cfg))]

use std::num::NonZeroU8;

#[cfg(feature = "serde")]
use serde::de::{self, Deserialize as _, Deserializer, Unexpected};

#[doc(inline)]
pub use crate::{error::Error, server_name::is_valid_server_name};

#[macro_use]
mod macros;

mod error;
mod server_name;

pub mod device_id;
pub mod device_key_id;
pub mod event_id;
pub mod key_algorithms;
pub mod room_alias_id;
pub mod room_id;
pub mod room_id_or_room_alias_id;
pub mod room_version_id;
pub mod server_key_id;
pub mod user_id;

/// An owned event ID.
///
/// Can be created via `new` (if the `rand` feature is enabled) and `TryFrom<String>` +
/// `TryFrom<&str>`, implements `Serialize` and `Deserialize` if the `serde` feature is enabled.
pub type EventId = event_id::EventId<Box<str>>;

/// A reference to an event ID.
///
/// Can be created via `TryFrom<&str>`, implements `Serialize` if the `serde` feature is enabled.
pub type EventIdRef<'a> = event_id::EventId<&'a str>;

/// An owned room alias ID.
///
/// Can be created via `TryFrom<String>` and `TryFrom<&str>`, implements `Serialize` and
/// `Deserialize` if the `serde` feature is enabled.
pub type RoomAliasId = room_alias_id::RoomAliasId<Box<str>>;

/// A reference to a room alias ID.
///
/// Can be created via `TryFrom<&str>`, implements `Serialize` if the `serde` feature is enabled.
pub type RoomAliasIdRef<'a> = room_alias_id::RoomAliasId<&'a str>;

/// An owned room ID.
///
/// Can be created via `new` (if the `rand` feature is enabled) and `TryFrom<String>` +
/// `TryFrom<&str>`, implements `Serialize` and `Deserialize` if the `serde` feature is enabled.
pub type RoomId = room_id::RoomId<Box<str>>;

/// A reference to a room ID.
///
/// Can be created via `TryFrom<&str>`, implements `Serialize` if the `serde` feature is enabled.
pub type RoomIdRef<'a> = room_id::RoomId<&'a str>;

/// An owned room alias ID or room ID.
///
/// Can be created via `TryFrom<String>`, `TryFrom<&str>`, `From<RoomId>` and `From<RoomAliasId>`;
/// implements `Serialize` and `Deserialize` if the `serde` feature is enabled.
pub type RoomIdOrAliasId = room_id_or_room_alias_id::RoomIdOrAliasId<Box<str>>;

/// A reference to a room alias ID or room ID.
///
/// Can be created via `TryFrom<&str>`, `From<RoomIdRef>` and `From<RoomAliasIdRef>`; implements
/// `Serialize` if the `serde` feature is enabled.
pub type RoomIdOrAliasIdRef<'a> = room_id_or_room_alias_id::RoomIdOrAliasId<&'a str>;

/// An owned room version ID.
///
/// Can be created using the `version_N` constructor functions, `TryFrom<String>` and
/// `TryFrom<&str>`; implements `Serialize` and `Deserialize` if the `serde` feature is enabled.
pub type RoomVersionId = room_version_id::RoomVersionId<Box<str>>;

/// A reference to a room version ID.
///
/// Can be created using the `version_N` constructor functions and via `TryFrom<&str>`, implements
/// `Serialize` if the `serde` feature is enabled.
pub type RoomVersionIdRef<'a> = room_version_id::RoomVersionId<&'a str>;

/// An owned user ID.
///
/// Can be created via `new` (if the `rand` feature is enabled) and `TryFrom<String>` +
/// `TryFrom<&str>`, implements `Serialize` and `Deserialize` if the `serde` feature is enabled.
pub type UserId = user_id::UserId<Box<str>>;

/// A reference to a user ID.
///
/// Can be created via `TryFrom<&str>`, implements `Serialize` if the `serde` feature is enabled.
pub type UserIdRef<'a> = user_id::UserId<&'a str>;

/// All identifiers must be 255 bytes or less.
const MAX_BYTES: usize = 255;
/// The minimum number of characters an ID can be.
///
/// This is an optimization and not required by the spec. The shortest possible valid ID is a sigil
/// + a single character local ID + a colon + a single character hostname.
const MIN_CHARS: usize = 4;

/// Generates a random identifier localpart.
#[cfg(feature = "rand")]
fn generate_localpart(length: usize) -> String {
    use rand::Rng as _;
    rand::thread_rng().sample_iter(&rand::distributions::Alphanumeric).take(length).collect()
}

/// Checks if an identifier is valid.
fn validate_id(id: &str, valid_sigils: &[char]) -> Result<(), Error> {
    if id.len() > MAX_BYTES {
        return Err(Error::MaximumLengthExceeded);
    }

    if id.len() < MIN_CHARS {
        return Err(Error::MinimumLengthNotSatisfied);
    }

    if !valid_sigils.contains(&id.chars().next().unwrap()) {
        return Err(Error::MissingSigil);
    }

    Ok(())
}

/// Checks an identifier that contains a localpart and hostname for validity,
/// and returns the index of the colon that separates the two.
fn parse_id(id: &str, valid_sigils: &[char]) -> Result<NonZeroU8, Error> {
    validate_id(id, valid_sigils)?;

    let colon_idx = id.find(':').ok_or(Error::MissingDelimiter)?;
    if colon_idx < 2 {
        return Err(Error::InvalidLocalPart);
    }

    if !is_valid_server_name(&id[colon_idx + 1..]) {
        return Err(Error::InvalidServerName);
    }

    Ok(NonZeroU8::new(colon_idx as u8).unwrap())
}

/// Deserializes any type of id using the provided TryFrom implementation.
///
/// This is a helper function to reduce the boilerplate of the Deserialize implementations.
#[cfg(feature = "serde")]
fn deserialize_id<'de, D, T>(deserializer: D, expected_str: &str) -> Result<T, D::Error>
where
    D: Deserializer<'de>,
    T: for<'a> std::convert::TryFrom<&'a str>,
{
    std::borrow::Cow::<'_, str>::deserialize(deserializer).and_then(|v| {
        T::try_from(&v).map_err(|_| de::Error::invalid_value(Unexpected::Str(&v), &expected_str))
    })
}
<commit_msg>identifiers: Add DeviceId, DeviceIdRef to the crate root<commit_after>//! Crate **ruma_identifiers** contains types for [Matrix](https://matrix.org/) identifiers
//! for events, rooms, room aliases, room versions, and users.

#![warn(rust_2018_idioms)]
#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    //missing_docs
)]
// Since we support Rust 1.36.0, we can't apply this suggestion yet
#![allow(clippy::use_self)]
#![cfg_attr(docsrs, feature(doc_cfg))]

use std::num::NonZeroU8;

#[cfg(feature = "serde")]
use serde::de::{self, Deserialize as _, Deserializer, Unexpected};

#[doc(inline)]
pub use crate::{error::Error, server_name::is_valid_server_name};

#[macro_use]
mod macros;

mod error;
mod server_name;

pub mod device_id;
pub mod device_key_id;
pub mod event_id;
pub mod key_algorithms;
pub mod room_alias_id;
pub mod room_id;
pub mod room_id_or_room_alias_id;
pub mod room_version_id;
pub mod server_key_id;
pub mod user_id;

/// An owned device ID.
///
/// While this is currently just a `String`, that will likely change in the future.
pub use device_id::DeviceId;

/// A reference to a device ID.
///
/// While this is currently just a string slice, that will likely change in the future.
pub type DeviceIdRef<'a> = &'a str;

/// An owned event ID.
///
/// Can be created via `new` (if the `rand` feature is enabled) and `TryFrom<String>` +
/// `TryFrom<&str>`, implements `Serialize` and `Deserialize` if the `serde` feature is enabled.
pub type EventId = event_id::EventId<Box<str>>;

/// A reference to an event ID.
///
/// Can be created via `TryFrom<&str>`, implements `Serialize` if the `serde` feature is enabled.
pub type EventIdRef<'a> = event_id::EventId<&'a str>;

/// An owned room alias ID.
///
/// Can be created via `TryFrom<String>` and `TryFrom<&str>`, implements `Serialize` and
/// `Deserialize` if the `serde` feature is enabled.
pub type RoomAliasId = room_alias_id::RoomAliasId<Box<str>>;

/// A reference to a room alias ID.
///
/// Can be created via `TryFrom<&str>`, implements `Serialize` if the `serde` feature is enabled.
pub type RoomAliasIdRef<'a> = room_alias_id::RoomAliasId<&'a str>;

/// An owned room ID.
///
/// Can be created via `new` (if the `rand` feature is enabled) and `TryFrom<String>` +
/// `TryFrom<&str>`, implements `Serialize` and `Deserialize` if the `serde` feature is enabled.
pub type RoomId = room_id::RoomId<Box<str>>;

/// A reference to a room ID.
///
/// Can be created via `TryFrom<&str>`, implements `Serialize` if the `serde` feature is enabled.
pub type RoomIdRef<'a> = room_id::RoomId<&'a str>;

/// An owned room alias ID or room ID.
///
/// Can be created via `TryFrom<String>`, `TryFrom<&str>`, `From<RoomId>` and `From<RoomAliasId>`;
/// implements `Serialize` and `Deserialize` if the `serde` feature is enabled.
pub type RoomIdOrAliasId = room_id_or_room_alias_id::RoomIdOrAliasId<Box<str>>;

/// A reference to a room alias ID or room ID.
///
/// Can be created via `TryFrom<&str>`, `From<RoomIdRef>` and `From<RoomAliasIdRef>`; implements
/// `Serialize` if the `serde` feature is enabled.
pub type RoomIdOrAliasIdRef<'a> = room_id_or_room_alias_id::RoomIdOrAliasId<&'a str>;

/// An owned room version ID.
///
/// Can be created using the `version_N` constructor functions, `TryFrom<String>` and
/// `TryFrom<&str>`; implements `Serialize` and `Deserialize` if the `serde` feature is enabled.
pub type RoomVersionId = room_version_id::RoomVersionId<Box<str>>;

/// A reference to a room version ID.
///
/// Can be created using the `version_N` constructor functions and via `TryFrom<&str>`, implements
/// `Serialize` if the `serde` feature is enabled.
pub type RoomVersionIdRef<'a> = room_version_id::RoomVersionId<&'a str>;

/// An owned user ID.
///
/// Can be created via `new` (if the `rand` feature is enabled) and `TryFrom<String>` +
/// `TryFrom<&str>`, implements `Serialize` and `Deserialize` if the `serde` feature is enabled.
pub type UserId = user_id::UserId<Box<str>>;

/// A reference to a user ID.
///
/// Can be created via `TryFrom<&str>`, implements `Serialize` if the `serde` feature is enabled.
pub type UserIdRef<'a> = user_id::UserId<&'a str>;

/// All identifiers must be 255 bytes or less.
const MAX_BYTES: usize = 255;
/// The minimum number of characters an ID can be.
///
/// This is an optimization and not required by the spec. The shortest possible valid ID is a sigil
/// + a single character local ID + a colon + a single character hostname.
const MIN_CHARS: usize = 4;

/// Generates a random identifier localpart.
#[cfg(feature = "rand")]
fn generate_localpart(length: usize) -> String {
    use rand::Rng as _;
    rand::thread_rng().sample_iter(&rand::distributions::Alphanumeric).take(length).collect()
}

/// Checks if an identifier is valid.
fn validate_id(id: &str, valid_sigils: &[char]) -> Result<(), Error> {
    if id.len() > MAX_BYTES {
        return Err(Error::MaximumLengthExceeded);
    }

    if id.len() < MIN_CHARS {
        return Err(Error::MinimumLengthNotSatisfied);
    }

    if !valid_sigils.contains(&id.chars().next().unwrap()) {
        return Err(Error::MissingSigil);
    }

    Ok(())
}

/// Checks an identifier that contains a localpart and hostname for validity,
/// and returns the index of the colon that separates the two.
fn parse_id(id: &str, valid_sigils: &[char]) -> Result<NonZeroU8, Error> {
    validate_id(id, valid_sigils)?;

    let colon_idx = id.find(':').ok_or(Error::MissingDelimiter)?;
    if colon_idx < 2 {
        return Err(Error::InvalidLocalPart);
    }

    if !is_valid_server_name(&id[colon_idx + 1..]) {
        return Err(Error::InvalidServerName);
    }

    Ok(NonZeroU8::new(colon_idx as u8).unwrap())
}

/// Deserializes any type of id using the provided TryFrom implementation.
///
/// This is a helper function to reduce the boilerplate of the Deserialize implementations.
#[cfg(feature = "serde")]
fn deserialize_id<'de, D, T>(deserializer: D, expected_str: &str) -> Result<T, D::Error>
where
    D: Deserializer<'de>,
    T: for<'a> std::convert::TryFrom<&'a str>,
{
    std::borrow::Cow::<'_, str>::deserialize(deserializer).and_then(|v| {
        T::try_from(&v).map_err(|_| de::Error::invalid_value(Unexpected::Str(&v), &expected_str))
    })
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use siphasher::sip::SipHasher24 as SipHasher;

use super::value::Value;

#[derive(Debug)]
pub struct Scope {
    idents: HashMap<u64, Value>,
    parent: Option<Box<Scope>>,
}

impl Scope {
    pub fn new() -> Self {
        Scope {
            idents: HashMap::new(),
            parent: None,
        }
    }

    pub fn new_child<'b>(self) -> Self {
        Scope {
            idents: HashMap::new(),
            parent: Some(Box::new(self)),
        }
    }

    pub fn lookup_ident(&self, ident: &str) -> Option<&Value> {
        let id = intern_ident(ident);
        self.lookup_id(id)
    }

    fn lookup_id(&self, id: u64) -> Option<&Value> {
        self.idents.get(&id)
        .or_else(|| self.parent.as_ref().and_then(|p| p.lookup_id(id)))
    }

    pub fn add_ident(&mut self, ident: &str, value: Value) {
        let id = intern_ident(ident);
        self.idents.insert(id, value);
    }
}

pub fn intern_ident(ident: &str) -> u64 {
    let mut s = SipHasher::new();
    ident.hash(&mut s);
    s.finish()
}
<commit_msg>scope refactoring pt 1<commit_after>use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::borrow::Cow;
use siphasher::sip::SipHasher24 as SipHasher;

use super::value::Value;

#[derive(Debug)]
pub struct Scope {
    idents: HashMap<u64, (String, Value)>,
    parent: Option<Box<Scope>>,
}

impl Scope {
    pub fn new() -> Self {
        Scope {
            idents: HashMap::new(),
            parent: None,
        }
    }

    pub fn new_child<'b>(self) -> Self {
        Scope {
            idents: HashMap::new(),
            parent: Some(Box::new(self)),
        }
    }

    pub fn lookup_ident(&self, id: u64) -> Option<&Value> {
        self.idents.get(&id)
        .map(|&(ident, value)| &value)
        .or_else(|| self.parent.as_ref().and_then(|p| p.lookup_id(id)))
    }

    pub fn add_ident<'a, T: 'a + Into<Cow<'a, str>>>(&mut self, ident: T, value: Value) {
        let ident = ident.into();
        let id = intern_ident(&ident);
        self.idents.insert(id, (ident.into_owned(), value));
    }
}

pub fn intern_ident(ident: &str) -> u64 {
    let mut s = SipHasher::new();
    ident.hash(&mut s);
    s.finish()
}
<|endoftext|>