<commit_before>struct Lexer<'a> {
	src: &'a [u8],
	pos: usize
}

impl<'a> Lexer<'a> {
	fn new(src: &'a [u8]) -> Lexer {
		Lexer { src: src, pos: 0 }
	}
}

impl<'a> Lexer<'a> {
	fn ch(&self) -> u8 {
		self.src[self.pos]
	}

	fn eof(&self) -> bool {
		self.pos >= self.src.len()
	}

	fn skip_ws(&mut self) -> usize {
		let prev_pos = self.pos;
		while self.valid_ws() {
			self.pos += 1;
		}
		self.pos - prev_pos
	}

	fn string(&mut self) -> Option<String> {
		let mut tok = Vec::<u8>::new();
		loop {
			if self.eof() {
				break
			}

			match self.ch() {
				b' '	=> break,
				b'\t'	=> break,
				b'\r'	=> break,
				b'\n'	=> break,
				b'"'	=> break,
				_		=> ()
			}

			tok.push(self.ch());
			self.pos += 1;
		}

		match tok.len() {
			0	=> None,
			_	=> Some(String::from_utf8(tok).unwrap())
		}
	}

	fn quoted_string(&mut self) -> Option<String> {
		let mut tok = Vec::<u8>::new();
		self.pos += 1;

		loop {
			if self.eof() {
				break;
			}

			match self.ch() {
				b'"' 	=> { self.pos += 1; break; },
				_ 		=> ()
			}

			tok.push(self.ch());
			self.pos += 1;
		}

		match tok.len() {
			0	=> None,
			_	=> Some(String::from_utf8(tok).unwrap())
		}
	}

	fn valid_ws(&self) -> bool {
		if self.eof() {
			return false;
		}

		match self.ch() {
			b' ' 	=> true,
			b'\t' 	=> true,
			b'\r'	=> true,
			b'\n'	=> true,
			_		=> false
		}
	}
}

impl<'a> Iterator for Lexer<'a> {
	type Item = String;

	fn next(&mut self) -> Option<String> {
		self.skip_ws();
		if self.eof() {
			return None;
		}

		match self.ch() {
			b'"' 	=> self.quoted_string(),
			_		=> self.string()
		}
	}
}

#[test]
fn tokenize() {
	let src = b"   foo   bar \"a b\"  baz   ";
	let lexer = Lexer::new(src);
	let tokens: Vec<_> = lexer.collect();
	assert_eq!(4, tokens.len());
	assert_eq!("foo".to_string(), tokens[0]);
	assert_eq!("bar".to_string(), tokens[1]);
	assert_eq!("a b".to_string(), tokens[2]);
	assert_eq!("baz".to_string(), tokens[3]);
}<commit_msg>Formatting<commit_after>struct Lexer<'a> {
	src: &'a [u8],
	pos: usize
}

impl<'a> Lexer<'a> {
	fn new(src: &'a [u8]) -> Lexer {
		Lexer { src: src, pos: 0 }
	}
}

impl<'a> Lexer<'a> {
	fn ch(&self) -> u8 {
		self.src[self.pos]
	}

	fn eof(&self) -> bool {
		self.pos >= self.src.len()
	}

	fn skip_ws(&mut self) -> usize {
		let prev_pos = self.pos;
		while self.valid_ws() {
			self.pos += 1;
		}
		self.pos - prev_pos
	}

	fn string(&mut self) -> Option<String> {
		let mut tok = Vec::<u8>::new();
		loop {
			if self.eof() {
				break
			}

			match self.ch() {
				b' '	=> break,
				b'\t'	=> break,
				b'\r'	=> break,
				b'\n'	=> break,
				b'"'	=> break,
				_		=> ()
			}

			tok.push(self.ch());
			self.pos += 1;
		}

		match tok.len() {
			0	=> None,
			_	=> Some(String::from_utf8(tok).unwrap())
		}
	}

	fn quoted_string(&mut self) -> Option<String> {
		let mut tok = Vec::<u8>::new();
		self.pos += 1;

		loop {
			if self.eof() {
				break;
			}

			match self.ch() {
				b'"' 	=> { self.pos += 1; break; },
				_ 		=> ()
			}

			tok.push(self.ch());
			self.pos += 1;
		}

		match tok.len() {
			0	=> None,
			_	=> Some(String::from_utf8(tok).unwrap())
		}
	}

	fn valid_ws(&self) -> bool {
		if self.eof() {
			return false;
		}

		match self.ch() {
			b' ' 	=> true,
			b'\t' 	=> true,
			b'\r'	=> true,
			b'\n'	=> true,
			_		=> false
		}
	}
}

impl<'a> Iterator for Lexer<'a> {
	type Item = String;

	fn next(&mut self) -> Option<String> {
		self.skip_ws();
		if self.eof() {
			return None;
		}

		match self.ch() {
			b'"' 	=> self.quoted_string(),
			_		=> self.string()
		}
	}
}

#[test]
fn tokenize() {
	let src = b"   foo   bar \"a b\"  baz   ";
	let lexer = Lexer::new(src);
	let tokens: Vec<_> = lexer.collect();
	assert_eq!(4, tokens.len());
	assert_eq!("foo".to_string(), tokens[0]);
	assert_eq!("bar".to_string(), tokens[1]);
	assert_eq!("a b".to_string(), tokens[2]);
	assert_eq!("baz".to_string(), tokens[3]);
}<|endoftext|>


<commit_before>use std::result;

use futures::sync::oneshot;
use hyper::{Response, StatusCode};

use request::ParsedRequest;
use http_service::{empty_response, json_fault_message, json_response};
use super::{DeviceState, GenerateResponse, SyncRequest};

#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[allow(non_camel_case_types)]
pub enum DrivePermissions {
    ro,
    rw,
}

// This struct represents the strongly typed equivalent of the json body from drive
// related requests.
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct DriveDescription {
    pub drive_id: String,
    pub path_on_host: String,
    pub state: DeviceState,
    pub is_root_device: bool,
    pub permissions: DrivePermissions,
}

impl DriveDescription {
    pub fn is_read_only(&self) -> bool {
        self.permissions == DrivePermissions::ro
    }
}

#[derive(Debug)]
pub enum DriveError {
    RootBlockDeviceAlreadyAdded,
    InvalidBlockDevicePath,
    BlockDevicePathAlreadyExists,
    NotImplemented,
}

impl GenerateResponse for DriveError {
    fn generate_response(&self) -> Response {
        use self::DriveError::*;
        match *self {
            RootBlockDeviceAlreadyAdded => json_response(
                StatusCode::BadRequest,
                json_fault_message("A root block device already exists!"),
            ),
            InvalidBlockDevicePath => json_response(
                StatusCode::BadRequest,
                json_fault_message("Invalid block device path!"),
            ),
            BlockDevicePathAlreadyExists => json_response(
                StatusCode::BadRequest,
                json_fault_message("The block device path was already added to a different drive!"),
            ),
            NotImplemented => json_response(
                StatusCode::InternalServerError,
                json_fault_message("The update operation is not implemented!"),
            ),
        }
    }
}

pub enum PutDriveOutcome {
    Created,
    Updated,
    Error(DriveError),
}

impl GenerateResponse for PutDriveOutcome {
    fn generate_response(&self) -> Response {
        use self::PutDriveOutcome::*;
        match *self {
            Created => empty_response(StatusCode::Created),
            Updated => empty_response(StatusCode::NoContent),
            Error(ref e) => e.generate_response(),
        }
    }
}

impl DriveDescription {
    pub fn into_parsed_request(self, id_from_path: &str) -> result::Result<ParsedRequest, String> {
        if id_from_path != self.drive_id {
            return Err(String::from(
                "The id from the path does not match the id from the body!",
            ));
        }

        let (sender, receiver) = oneshot::channel();
        Ok(ParsedRequest::Sync(
            SyncRequest::PutDrive(self, sender),
            receiver,
        ))
    }
}
<commit_msg>api_server: add unit tests to drive.rs<commit_after>use std::result;

use futures::sync::oneshot;
use hyper::{Response, StatusCode};

use request::ParsedRequest;
use http_service::{empty_response, json_fault_message, json_response};
use super::{DeviceState, GenerateResponse, SyncRequest};

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[allow(non_camel_case_types)]
pub enum DrivePermissions {
    ro,
    rw,
}

// This struct represents the strongly typed equivalent of the json body from drive
// related requests.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct DriveDescription {
    pub drive_id: String,
    pub path_on_host: String,
    pub state: DeviceState,
    pub is_root_device: bool,
    pub permissions: DrivePermissions,
}

impl DriveDescription {
    pub fn is_read_only(&self) -> bool {
        self.permissions == DrivePermissions::ro
    }
}

#[derive(Debug)]
pub enum DriveError {
    RootBlockDeviceAlreadyAdded,
    InvalidBlockDevicePath,
    BlockDevicePathAlreadyExists,
    NotImplemented,
}

impl GenerateResponse for DriveError {
    fn generate_response(&self) -> Response {
        use self::DriveError::*;
        match *self {
            RootBlockDeviceAlreadyAdded => json_response(
                StatusCode::BadRequest,
                json_fault_message("A root block device already exists!"),
            ),
            InvalidBlockDevicePath => json_response(
                StatusCode::BadRequest,
                json_fault_message("Invalid block device path!"),
            ),
            BlockDevicePathAlreadyExists => json_response(
                StatusCode::BadRequest,
                json_fault_message("The block device path was already added to a different drive!"),
            ),
            NotImplemented => json_response(
                StatusCode::InternalServerError,
                json_fault_message("The update operation is not implemented!"),
            ),
        }
    }
}

pub enum PutDriveOutcome {
    Created,
    Updated,
    Error(DriveError),
}

impl GenerateResponse for PutDriveOutcome {
    fn generate_response(&self) -> Response {
        use self::PutDriveOutcome::*;
        match *self {
            Created => empty_response(StatusCode::Created),
            Updated => empty_response(StatusCode::NoContent),
            Error(ref e) => e.generate_response(),
        }
    }
}

impl DriveDescription {
    pub fn into_parsed_request(self, id_from_path: &str) -> result::Result<ParsedRequest, String> {
        if id_from_path != self.drive_id {
            return Err(String::from(
                "The id from the path does not match the id from the body!",
            ));
        }

        let (sender, receiver) = oneshot::channel();
        Ok(ParsedRequest::Sync(
            SyncRequest::PutDrive(self, sender),
            receiver,
        ))
    }
}

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

    #[test]
    fn test_is_read_only() {
        assert!(DriveDescription {
            drive_id: String::from("foo"),
            path_on_host: String::from("/foo/bar"),
            state: DeviceState::Attached,
            is_root_device: true,
            permissions: DrivePermissions::ro
        }.is_read_only());
    }

    #[test]
    fn test_generate_response_drive_error() {
        assert_eq!(DriveError::RootBlockDeviceAlreadyAdded.generate_response().status(),
                   StatusCode::BadRequest);
        assert_eq!(DriveError::InvalidBlockDevicePath.generate_response().status(),
                   StatusCode::BadRequest);
        assert_eq!(DriveError::BlockDevicePathAlreadyExists.generate_response().status(),
                   StatusCode::BadRequest);
        assert_eq!(DriveError::NotImplemented.generate_response().status(),
                   StatusCode::InternalServerError);
    }

    #[test]
    fn test_generate_response_put_drive_outcome() {
        assert_eq!(PutDriveOutcome::Created.generate_response().status(), StatusCode::Created);
        assert_eq!(PutDriveOutcome::Updated.generate_response().status(), StatusCode::NoContent);
        assert_eq!(PutDriveOutcome::Error(DriveError::NotImplemented).generate_response().status(),
                   StatusCode::InternalServerError);
    }

    #[test]
    fn test_into_parsed_request() {
        let desc = DriveDescription {
            drive_id: String::from("foo"),
            path_on_host: String::from("/foo/bar"),
            state: DeviceState::Attached,
            is_root_device: true,
            permissions: DrivePermissions::ro
        };

        assert!(&desc.clone().into_parsed_request("bar").is_err());
        let (sender, receiver) = oneshot::channel();
        assert!(&desc.clone().into_parsed_request("foo").eq(
                   &Ok(ParsedRequest::Sync(SyncRequest::PutDrive(desc, sender), receiver))));
    }
}
<|endoftext|>


<commit_before>//! This module specifies the input to rust-analyzer. In some sense, this is
//! **the** most important module, because all other fancy stuff is strictly
//! derived from this input.
//!
//! Note that neither this module, nor any other part of the analyzer's core do
//! actual IO. See `vfs` and `project_model` in the `ra_lsp_server` crate for how
//! actual IO is done and lowered to input.

use rustc_hash::FxHashMap;

use ra_cfg::CfgOptions;
use ra_syntax::SmolStr;
use rustc_hash::FxHashSet;

use crate::{RelativePath, RelativePathBuf};
use std::{error::Error, str::FromStr};

/// `FileId` is an integer which uniquely identifies a file. File paths are
/// messy and system-dependent, so most of the code should work directly with
/// `FileId`, without inspecting the path. The mapping between `FileId` and path
/// and `SourceRoot` is constant. A file rename is represented as a pair of
/// deletion/creation.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileId(pub u32);

/// Files are grouped into source roots. A source root is a directory on the
/// file systems which is watched for changes. Typically it corresponds to a
/// Rust crate. Source roots *might* be nested: in this case, a file belongs to
/// the nearest enclosing source root. Paths to files are always relative to a
/// source root, and the analyzer does not know the root path of the source root at
/// all. So, a file from one source root can't refer to a file in another source
/// root by path.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct SourceRootId(pub u32);

#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct SourceRoot {
    /// Sysroot or crates.io library.
    ///
    /// Libraries are considered mostly immutable, this assumption is used to
    /// optimize salsa's query structure
    pub is_library: bool,
    files: FxHashMap<RelativePathBuf, FileId>,
}

impl SourceRoot {
    pub fn new() -> SourceRoot {
        Default::default()
    }
    pub fn new_library() -> SourceRoot {
        SourceRoot { is_library: true, ..SourceRoot::new() }
    }
    pub fn insert_file(&mut self, path: RelativePathBuf, file_id: FileId) {
        self.files.insert(path, file_id);
    }
    pub fn remove_file(&mut self, path: &RelativePath) {
        self.files.remove(path);
    }
    pub fn walk(&self) -> impl Iterator<Item = FileId> + '_ {
        self.files.values().copied()
    }
    pub fn file_by_relative_path(&self, path: &RelativePath) -> Option<FileId> {
        self.files.get(path).copied()
    }
}

/// `CrateGraph` is a bit of information which turns a set of text files into a
/// number of Rust crates. Each crate is defined by the `FileId` of its root module,
/// the set of cfg flags (not yet implemented) and the set of dependencies. Note
/// that, due to cfg's, there might be several crates for a single `FileId`! As
/// in the rust-lang proper, a crate does not have a name. Instead, names are
/// specified on dependency edges. That is, a crate might be known under
/// different names in different dependent crates.
///
/// Note that `CrateGraph` is build-system agnostic: it's a concept of the Rust
/// language proper, not a concept of the build system. In practice, we get
/// `CrateGraph` by lowering `cargo metadata` output.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct CrateGraph {
    arena: FxHashMap<CrateId, CrateData>,
}

#[derive(Debug)]
pub struct CyclicDependencies;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CrateId(pub u32);

impl CrateId {
    pub fn shift(self, amount: u32) -> CrateId {
        CrateId(self.0 + amount)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Edition {
    Edition2018,
    Edition2015,
}

#[derive(Debug)]
pub struct ParseEditionError {
    pub msg: String,
}

impl FromStr for Edition {
    type Err = ParseEditionError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "2015" => Ok(Edition::Edition2015),
            "2018" => Ok(Edition::Edition2018),
            _ => Err(ParseEditionError { msg: format!("unknown edition: {}", s) }),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct CrateData {
    file_id: FileId,
    edition: Edition,
    dependencies: Vec<Dependency>,
    cfg_options: CfgOptions,
}

impl CrateData {
    fn new(file_id: FileId, edition: Edition, cfg_options: CfgOptions) -> CrateData {
        CrateData { file_id, edition, dependencies: Vec::new(), cfg_options }
    }

    fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) {
        self.dependencies.push(Dependency { name, crate_id })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Dependency {
    pub crate_id: CrateId,
    pub name: SmolStr,
}

impl Dependency {
    pub fn crate_id(&self) -> CrateId {
        self.crate_id
    }
}

impl CrateGraph {
    pub fn add_crate_root(
        &mut self,
        file_id: FileId,
        edition: Edition,
        cfg_options: CfgOptions,
    ) -> CrateId {
        let crate_id = CrateId(self.arena.len() as u32);
        let prev = self.arena.insert(crate_id, CrateData::new(file_id, edition, cfg_options));
        assert!(prev.is_none());
        crate_id
    }

    pub fn cfg_options(&self, crate_id: CrateId) -> &CfgOptions {
        &self.arena[&crate_id].cfg_options
    }

    pub fn add_dep(
        &mut self,
        from: CrateId,
        name: SmolStr,
        to: CrateId,
    ) -> Result<(), CyclicDependencies> {
        if self.dfs_find(from, to, &mut FxHashSet::default()) {
            return Err(CyclicDependencies);
        }
        self.arena.get_mut(&from).unwrap().add_dep(name, to);
        Ok(())
    }

    pub fn is_empty(&self) -> bool {
        self.arena.is_empty()
    }

    pub fn iter<'a>(&'a self) -> impl Iterator<Item = CrateId> + 'a {
        self.arena.keys().copied()
    }

    pub fn crate_root(&self, crate_id: CrateId) -> FileId {
        self.arena[&crate_id].file_id
    }

    pub fn edition(&self, crate_id: CrateId) -> Edition {
        self.arena[&crate_id].edition
    }

    // FIXME: this only finds one crate with the given root; we could have multiple
    pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
        let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?;
        Some(crate_id)
    }

    pub fn dependencies<'a>(
        &'a self,
        crate_id: CrateId,
    ) -> impl Iterator<Item = &'a Dependency> + 'a {
        self.arena[&crate_id].dependencies.iter()
    }

    /// Extends this crate graph by adding a complete disjoint second crate
    /// graph.
    ///
    /// The ids of the crates in the `other` graph are shifted by the return
    /// amount.
    pub fn extend(&mut self, other: CrateGraph) -> u32 {
        let start = self.arena.len() as u32;
        self.arena.extend(other.arena.into_iter().map(|(id, mut data)| {
            let new_id = id.shift(start);
            for dep in &mut data.dependencies {
                dep.crate_id = dep.crate_id.shift(start);
            }
            (new_id, data)
        }));
        start
    }

    fn dfs_find(&self, target: CrateId, from: CrateId, visited: &mut FxHashSet<CrateId>) -> bool {
        if !visited.insert(from) {
            return false;
        }

        for dep in self.dependencies(from) {
            let crate_id = dep.crate_id();
            if crate_id == target {
                return true;
            }

            if self.dfs_find(target, crate_id, visited) {
                return true;
            }
        }
        false
    }
}

#[cfg(test)]
mod tests {
    use super::{CfgOptions, CrateGraph, Edition::Edition2018, FileId, SmolStr};

    #[test]
    fn it_should_panic_because_of_cycle_dependencies() {
        let mut graph = CrateGraph::default();
        let crate1 = graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default());
        let crate2 = graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default());
        let crate3 = graph.add_crate_root(FileId(3u32), Edition2018, CfgOptions::default());
        assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok());
        assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok());
        assert!(graph.add_dep(crate3, SmolStr::new("crate1"), crate1).is_err());
    }

    #[test]
    fn it_works() {
        let mut graph = CrateGraph::default();
        let crate1 = graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default());
        let crate2 = graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default());
        let crate3 = graph.add_crate_root(FileId(3u32), Edition2018, CfgOptions::default());
        assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok());
        assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok());
    }
}
<commit_msg>Fix unused import<commit_after>//! This module specifies the input to rust-analyzer. In some sense, this is
//! **the** most important module, because all other fancy stuff is strictly
//! derived from this input.
//!
//! Note that neither this module, nor any other part of the analyzer's core do
//! actual IO. See `vfs` and `project_model` in the `ra_lsp_server` crate for how
//! actual IO is done and lowered to input.

use rustc_hash::FxHashMap;

use ra_cfg::CfgOptions;
use ra_syntax::SmolStr;
use rustc_hash::FxHashSet;

use crate::{RelativePath, RelativePathBuf};
use std::str::FromStr;

/// `FileId` is an integer which uniquely identifies a file. File paths are
/// messy and system-dependent, so most of the code should work directly with
/// `FileId`, without inspecting the path. The mapping between `FileId` and path
/// and `SourceRoot` is constant. A file rename is represented as a pair of
/// deletion/creation.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileId(pub u32);

/// Files are grouped into source roots. A source root is a directory on the
/// file systems which is watched for changes. Typically it corresponds to a
/// Rust crate. Source roots *might* be nested: in this case, a file belongs to
/// the nearest enclosing source root. Paths to files are always relative to a
/// source root, and the analyzer does not know the root path of the source root at
/// all. So, a file from one source root can't refer to a file in another source
/// root by path.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct SourceRootId(pub u32);

#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct SourceRoot {
    /// Sysroot or crates.io library.
    ///
    /// Libraries are considered mostly immutable, this assumption is used to
    /// optimize salsa's query structure
    pub is_library: bool,
    files: FxHashMap<RelativePathBuf, FileId>,
}

impl SourceRoot {
    pub fn new() -> SourceRoot {
        Default::default()
    }
    pub fn new_library() -> SourceRoot {
        SourceRoot { is_library: true, ..SourceRoot::new() }
    }
    pub fn insert_file(&mut self, path: RelativePathBuf, file_id: FileId) {
        self.files.insert(path, file_id);
    }
    pub fn remove_file(&mut self, path: &RelativePath) {
        self.files.remove(path);
    }
    pub fn walk(&self) -> impl Iterator<Item = FileId> + '_ {
        self.files.values().copied()
    }
    pub fn file_by_relative_path(&self, path: &RelativePath) -> Option<FileId> {
        self.files.get(path).copied()
    }
}

/// `CrateGraph` is a bit of information which turns a set of text files into a
/// number of Rust crates. Each crate is defined by the `FileId` of its root module,
/// the set of cfg flags (not yet implemented) and the set of dependencies. Note
/// that, due to cfg's, there might be several crates for a single `FileId`! As
/// in the rust-lang proper, a crate does not have a name. Instead, names are
/// specified on dependency edges. That is, a crate might be known under
/// different names in different dependent crates.
///
/// Note that `CrateGraph` is build-system agnostic: it's a concept of the Rust
/// language proper, not a concept of the build system. In practice, we get
/// `CrateGraph` by lowering `cargo metadata` output.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct CrateGraph {
    arena: FxHashMap<CrateId, CrateData>,
}

#[derive(Debug)]
pub struct CyclicDependencies;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CrateId(pub u32);

impl CrateId {
    pub fn shift(self, amount: u32) -> CrateId {
        CrateId(self.0 + amount)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Edition {
    Edition2018,
    Edition2015,
}

#[derive(Debug)]
pub struct ParseEditionError {
    pub msg: String,
}

impl FromStr for Edition {
    type Err = ParseEditionError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "2015" => Ok(Edition::Edition2015),
            "2018" => Ok(Edition::Edition2018),
            _ => Err(ParseEditionError { msg: format!("unknown edition: {}", s) }),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct CrateData {
    file_id: FileId,
    edition: Edition,
    dependencies: Vec<Dependency>,
    cfg_options: CfgOptions,
}

impl CrateData {
    fn new(file_id: FileId, edition: Edition, cfg_options: CfgOptions) -> CrateData {
        CrateData { file_id, edition, dependencies: Vec::new(), cfg_options }
    }

    fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) {
        self.dependencies.push(Dependency { name, crate_id })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Dependency {
    pub crate_id: CrateId,
    pub name: SmolStr,
}

impl Dependency {
    pub fn crate_id(&self) -> CrateId {
        self.crate_id
    }
}

impl CrateGraph {
    pub fn add_crate_root(
        &mut self,
        file_id: FileId,
        edition: Edition,
        cfg_options: CfgOptions,
    ) -> CrateId {
        let crate_id = CrateId(self.arena.len() as u32);
        let prev = self.arena.insert(crate_id, CrateData::new(file_id, edition, cfg_options));
        assert!(prev.is_none());
        crate_id
    }

    pub fn cfg_options(&self, crate_id: CrateId) -> &CfgOptions {
        &self.arena[&crate_id].cfg_options
    }

    pub fn add_dep(
        &mut self,
        from: CrateId,
        name: SmolStr,
        to: CrateId,
    ) -> Result<(), CyclicDependencies> {
        if self.dfs_find(from, to, &mut FxHashSet::default()) {
            return Err(CyclicDependencies);
        }
        self.arena.get_mut(&from).unwrap().add_dep(name, to);
        Ok(())
    }

    pub fn is_empty(&self) -> bool {
        self.arena.is_empty()
    }

    pub fn iter<'a>(&'a self) -> impl Iterator<Item = CrateId> + 'a {
        self.arena.keys().copied()
    }

    pub fn crate_root(&self, crate_id: CrateId) -> FileId {
        self.arena[&crate_id].file_id
    }

    pub fn edition(&self, crate_id: CrateId) -> Edition {
        self.arena[&crate_id].edition
    }

    // FIXME: this only finds one crate with the given root; we could have multiple
    pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
        let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?;
        Some(crate_id)
    }

    pub fn dependencies<'a>(
        &'a self,
        crate_id: CrateId,
    ) -> impl Iterator<Item = &'a Dependency> + 'a {
        self.arena[&crate_id].dependencies.iter()
    }

    /// Extends this crate graph by adding a complete disjoint second crate
    /// graph.
    ///
    /// The ids of the crates in the `other` graph are shifted by the return
    /// amount.
    pub fn extend(&mut self, other: CrateGraph) -> u32 {
        let start = self.arena.len() as u32;
        self.arena.extend(other.arena.into_iter().map(|(id, mut data)| {
            let new_id = id.shift(start);
            for dep in &mut data.dependencies {
                dep.crate_id = dep.crate_id.shift(start);
            }
            (new_id, data)
        }));
        start
    }

    fn dfs_find(&self, target: CrateId, from: CrateId, visited: &mut FxHashSet<CrateId>) -> bool {
        if !visited.insert(from) {
            return false;
        }

        for dep in self.dependencies(from) {
            let crate_id = dep.crate_id();
            if crate_id == target {
                return true;
            }

            if self.dfs_find(target, crate_id, visited) {
                return true;
            }
        }
        false
    }
}

#[cfg(test)]
mod tests {
    use super::{CfgOptions, CrateGraph, Edition::Edition2018, FileId, SmolStr};

    #[test]
    fn it_should_panic_because_of_cycle_dependencies() {
        let mut graph = CrateGraph::default();
        let crate1 = graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default());
        let crate2 = graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default());
        let crate3 = graph.add_crate_root(FileId(3u32), Edition2018, CfgOptions::default());
        assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok());
        assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok());
        assert!(graph.add_dep(crate3, SmolStr::new("crate1"), crate1).is_err());
    }

    #[test]
    fn it_works() {
        let mut graph = CrateGraph::default();
        let crate1 = graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default());
        let crate2 = graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default());
        let crate3 = graph.add_crate_root(FileId(3u32), Edition2018, CfgOptions::default());
        assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok());
        assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok());
    }
}
<|endoftext|>


<commit_before>use core::ops::{Add, Sub};

// todo: documentation
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Point {
    pub x: f64,
    pub y: f64,
}

impl Point {
    pub fn new(x: f64, y: f64) -> Self {
        Point { x, y }
    }

    /// Returns the distance between this `Point` and the given `Point`.
    pub fn distance(&self, other: Self) -> f64 {
        ((self.x - other.x).powf(2.) + (self.y - other.y).powf(2.)).sqrt()
    }
}

impl Sub for Point {
    type Output = Self;

    fn sub(self, other: Self) -> Self {
        Self {
            x: self.x - other.x,
            y: self.y - other.y,
        }
    }
}

impl Add for Point {
    type Output = Self;

    fn add(self, other: Self) -> Self {
        Self {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

impl From<f64> for Point {
    fn from(t: f64) -> Self {
        Point::new(t, t)
    }
}

impl From<i32> for Point {
    fn from(t: i32) -> Self {
        Point::new(t as f64, t as f64)
    }
}

impl From<(f64, f64)> for Point {
    fn from(t: (f64, f64)) -> Self {
        Point::new(t.0, t.1)
    }
}

impl From<(i32, i32)> for Point {
    fn from(s: (i32, i32)) -> Point {
        Point::from((s.0 as f64, s.1 as f64))
    }
}

#[test]
fn test_distance() {
    const EXPECTED_RESULT: f64 = 9.48683;
    const ERROR_MARGIN: f64 = 0.00001;

    let point_positive = Point::new(1., 5.);
    let point_negative = Point::new(-2., -4.);

    assert!(((point_positive.distance(point_negative) - EXPECTED_RESULT).abs() < ERROR_MARGIN));
    assert!(((point_negative.distance(point_positive) - EXPECTED_RESULT).abs() < ERROR_MARGIN));
}

#[test]
fn test_sub() {
    const EXPECTED_RESULT: Point = Point { x: -3., y: 5. };
    const ERROR_MARGIN: f64 = 0.00001;

    let left_side = Point::new(5., 7.);
    let right_side = Point::new(8., 2.);

    let result = left_side - right_side;

    assert!((result.x - EXPECTED_RESULT.x).abs() < ERROR_MARGIN);
    assert!((result.y - EXPECTED_RESULT.y).abs() < ERROR_MARGIN);
}

#[test]
fn test_add() {
    const EXPECTED_RESULT: Point = Point { x: 13., y: 9. };
    const ERROR_MARGIN: f64 = 0.00001;

    let left_side = Point::new(5., 7.);
    let right_side = Point::new(8., 2.);

    let result = left_side + right_side;

    assert!((result.x - EXPECTED_RESULT.x).abs() < ERROR_MARGIN);
    assert!((result.y - EXPECTED_RESULT.y).abs() < ERROR_MARGIN);
}
<commit_msg>Changed `Point` fields to be private and added getters and setters for them<commit_after>use core::ops::{Add, Sub};

// todo: documentation
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Point {
    x: f64,
    y: f64,
}

impl Point {
    pub fn new(x: f64, y: f64) -> Self {
        Point { x, y }
    }

    /// Returns the distance between this `Point` and the given `Point`.
    pub fn distance(&self, other: Self) -> f64 {
        ((self.x - other.x).powf(2.) + (self.y - other.y).powf(2.)).sqrt()
    }

    pub fn x(&self) -> f64 {
        self.x
    }

    pub fn y(&self) -> f64 {
        self.y
    }

    pub fn set_x(&mut self, x: f64) {
        self.x = x;
    }

    pub fn set_y(&mut self, y: f64) {
        self.y = y;
    }
}

impl Sub for Point {
    type Output = Self;

    fn sub(self, other: Self) -> Self {
        Self {
            x: self.x - other.x,
            y: self.y - other.y,
        }
    }
}

impl Add for Point {
    type Output = Self;

    fn add(self, other: Self) -> Self {
        Self {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

impl From<f64> for Point {
    fn from(t: f64) -> Self {
        Point::new(t, t)
    }
}

impl From<i32> for Point {
    fn from(t: i32) -> Self {
        Point::new(t as f64, t as f64)
    }
}

impl From<(f64, f64)> for Point {
    fn from(t: (f64, f64)) -> Self {
        Point::new(t.0, t.1)
    }
}

impl From<(i32, i32)> for Point {
    fn from(s: (i32, i32)) -> Point {
        Point::from((s.0 as f64, s.1 as f64))
    }
}

#[test]
fn test_distance() {
    const EXPECTED_RESULT: f64 = 9.48683;
    const ERROR_MARGIN: f64 = 0.00001;

    let point_positive = Point::new(1., 5.);
    let point_negative = Point::new(-2., -4.);

    assert!(((point_positive.distance(point_negative) - EXPECTED_RESULT).abs() < ERROR_MARGIN));
    assert!(((point_negative.distance(point_positive) - EXPECTED_RESULT).abs() < ERROR_MARGIN));
}

#[test]
fn test_sub() {
    const EXPECTED_RESULT: Point = Point { x: -3., y: 5. };
    const ERROR_MARGIN: f64 = 0.00001;

    let left_side = Point::new(5., 7.);
    let right_side = Point::new(8., 2.);

    let result = left_side - right_side;

    assert!((result.x - EXPECTED_RESULT.x).abs() < ERROR_MARGIN);
    assert!((result.y - EXPECTED_RESULT.y).abs() < ERROR_MARGIN);
}

#[test]
fn test_add() {
    const EXPECTED_RESULT: Point = Point { x: 13., y: 9. };
    const ERROR_MARGIN: f64 = 0.00001;

    let left_side = Point::new(5., 7.);
    let right_side = Point::new(8., 2.);

    let result = left_side + right_side;

    assert!((result.x - EXPECTED_RESULT.x).abs() < ERROR_MARGIN);
    assert!((result.y - EXPECTED_RESULT.y).abs() < ERROR_MARGIN);
}
<|endoftext|>


<commit_before>// A generic set of chatting responses. This set mimicks the classic Eliza bot.

+ *
- I'm not sure I understand you fully.
- Please go on.
- That is interesting. Please continue.
- Tell me more about that.
- Does talking about this bother you?

+ [*] (sorry|apologize|apology) [*]
- Please don't apologize.
- Apologies are not necessary.
- I've told you that apologies are not required.
- It did not bother me. Please continue.

+ i remember *
- Do you often think of <star>?
- Does thinking of <star> bring anything else to mind?
- Why do you remember <star> just now?
- What in the present situation reminds you of <star>?
- What is the connection between me and <star>?
- What else does <star> remind you of?

+ do you remember *
- Did you think I would forget <star>?
- Why do you think I should recall <star> now?
- What about <star>?
- You mentioned <star>?

+ you remember *
- How could I forget <star>?
- What about <star> should I remember?

+ i forget *
- Can you think of why you might forget <star>?
- Why can't you remember <star>?
- How often do you think of <star>?
- Does it bother you to forget that?
- Could it be a mental block?
- Are you generally forgetful?
- Do you think you are suppressing <star>?

+ did you forget *
- Why do you ask?
- Are you sure you told me?
- Would it bother you if I forgot <star>?
- Why should I recall <star> just now?
- Tell me more about <star>.

+ [*] if *
- Do you think it's likely that <star>?
- Do you wish that <star>?
- What do you know about <star>?
- Really, if <star>?
- What would you do if <star>?
- But what are the chances that <star>?
- What does this speculation lead to?

+ [*] i dreamed *
- Really, <star>?
- Have you ever fantasized <star> while you were awake?
- Have you ever dreamed <star> before?
- What does that dream suggest to you?
- Do you dream often?
- What persons appear in your dreams?
- Do you believe that dreams have something to do with your problem?

+ [*] perhaps [*]
- You don't seem quite certain.
- Why the uncertain tone?
- Can't you be more positive?
- You aren't sure?
- Don't you know?
- How likely, would you estimate?

+ (hello|hi|hey|howdy|hola|hai|yo) [*]
- How do you do. Please state your problem.
- Hi. What seems to be your problem?

+ [*] computer [*]
- Do computers worry you?
- Why do you mention computers?
- What do you think machines have to do with your problem?
- Don't you think computers can help people?
- What about machines worries you?
- What do you think about machines?

+ am i *
- Do you believe you are <star>?
- Would you want to be <star>?
- Do you wish I would tell you you are <star>?
- What would it mean if you were <star>?

+ are you *
- Are you interested in whether I am <star> or not?
- Would you prefer if I weren't <star>?
- Perhaps I am <star> in your fantasies.
- Do you sometimes think I am <star>?
- Would it matter to you?
- What if I were <star>?

+ you are *
- What makes you think I am <star>?
- Does it please you to believe I am <star>?
- Do you sometimes wish you were <star>?
- Perhaps you would like to be <star>.

+ * are *
- Did you think they might not be <star2>?
- Would you like it if they were not <star2>?
- What if they were not <star2>?
- Are they always <star2>?
- Are you positive they are <star2>?

+ [*] your *
- Why are you concerned over my <star>?
- What about your own <star>?
- Are you worried about someone else's <star>?
- Really, my <star>?
- What makes you think of my <star>?
- Do you want my <star>?

+ was i *
- What if you were <star>?
- Do you think you were <star>?
- Were you <star>?
- What would it mean if you were <star>?
- What does '<star>' suggest to you?

+ i was *
- Were you really?
- Why do you tell me you were <star> now?
- Perhaps I already know you were <star>.

+ [*] was you *
- Would you like to believe I was <star>?
- What suggests that I was <star>?
- What do you think?
- Perhaps I was <star>.
- What if I had been <star>?

+ i (desire|want|need) *
- What would it mean to you if you got <star2>?
- Why do you want <star2>?
- Suppose you got <star2> soon.
- What if you never got <star2>?
- What would getting <star2> mean to you?
- What does wanting <star2> have to do with this discussion?

+ i am (sad|unhappy|mad|angry|pissed|depressed) [*]
- I am sorry to hear that you are <star2>.
- Do you think coming here will help you not to be <star2>?
- I'm sure it's not pleasant to be <star2>.
- Can you explain what made you <star2>?

+ i am (happy|excited|glad) [*]
- How have I helped you to be <star2>?
- Has your treatment made you <star2>?
- What makes you <star2> just now?
- Can you explain why you are <star2>?

+ i (believe|think) *
- Do you really think so?
- But you are not sure you <star2>.
- Do you really doubt you <star2>

+ i am *
- Is it because you are <star> that you came to me?
- How long have you been <star>?
- Do you believe it is normal to be <star>?
- Do you enjoy being <star>?
- Do you know anyone else who is <star>?

+ i can not *
- How do you know that you can't <star>?
- Have you tried?
- Perhaps you could <star> now.
- Do you really want to be able to <star>?
- What if you could <star>?

+ i do not *
- Don't you really <star>?
- Why don't you <star>?
- Do you wish to be able to <star>?
- Does that trouble you?

+ i feel *
- Tell me more about such feelings.
- Do you often feel <star>?
- Do you enjoy feeling <star>?
- Of what does feeling <star> remind you?

+ i * you
- Perhaps in your fantasies we <star> each other.
- Do you wish to <star> me?
- You seem to need to <star> me.
- Do you <star> anyone else?

+ you * me
- Why do you think I <star> you?
- You like to think I <star> you -- don't you?
- What makes you think I <star> you?
- Really, I <star> you?
- Do you wish to believe I <star> you?
- Suppose I did <star> you -- what would that mean?
- Does someone else believe I <star> you?

+ [*] you *
- We were discussing you -- not me.
- Oh, I <star>?
- You're not really talking about me -- are you?
- What are your feelings now?

+ [*] (yes|yeah|yep|yup) [*]
- Please go on.
- Please tell me more about this.
- Why don't you tell me a little more about this.
- I see.
- I understand.

+ [*] (nope|nah) [*]
- Are you saying no just to be negative?
- Does this make you feel unhappy?
- Why not?
- Why 'no'?

+ no
@ nope

+ no one *
- Are you sure, no one <star>?
- Surely someone <star>.
- Can you think of anyone at all?
- Are you thinking of a very special person?
- Who, may I ask?
- You have a particular person in mind, don't you?
- Who do you think you are talking about?

+ [*] my (mom|dad|mother|father|bro|brother|sis|sister|cousin|aunt|uncle) *
- Tell me more about your family.
- Who else in your family <star2>?
- Your <star2>?
- What else comes to mind when you think of your <star2>?

+ can you *
- You believe I can <star> don't you?
- You want me to be able to <star>.
- Perhaps you would like to be able to <star> yourself.

+ can i *
- Whether or not you can <star> depends on you more than on me.
- Do you want to be able to <star>?
- Perhaps you don't want to <star>.

+ (what|who|when|where|how) [*]
- Why do you ask?
- Does that question interest you?
- What is it you really want to know?
- Are such questions much on your mind?
- What answer would please you most?
- What do you think?
- What comes to mind when you ask that?
- Have you asked such questions before?
- Have you asked anyone else?

+ [*] because [*]
- Is that the real reason?
- Don't any other reasons come to mind?
- Does that reason seem to explain anything else?
- What other reasons might there be?

+ why do not you *
- Do you believe I don't <star>?
- Perhaps I will <star> in good time.
- Should you <star> yourself?
- You want me to <star>?

+ why can not i *
- Do you think you should be able to <star>?
- Do you want to be able to <star>?
- Do you believe this will help you to <star>?
- Have you any idea why you can't <star>?

+ everyone *
- Really, everyone?
- Surely not everyone.
- Can you think of anyone in particular?
- Who, for example?
- Are you thinking of a very special person?
- Who, may I ask?
- Someone special perhaps?
- You have a particular reason in mind, don't you?
- Who do you think you're talking about?

+ [*] (fuck|fucker|shit|damn|shut up|bitch) [*]
- Does it make you feel strong to use that kind of language?
- Are you venting your feelings now?
- Are you angry?
- Does this topic make you feel angry?
- Is something making you feel angry?
- Does using that kind of language make you feel better?
<commit_msg>Fixed some wrong star tags in Eliza's brain<commit_after>// A generic set of chatting responses. This set mimicks the classic Eliza bot.

+ *
- I'm not sure I understand you fully.
- Please go on.
- That is interesting. Please continue.
- Tell me more about that.
- Does talking about this bother you?

+ [*] (sorry|apologize|apology) [*]
- Please don't apologize.
- Apologies are not necessary.
- I've told you that apologies are not required.
- It did not bother me. Please continue.

+ i remember *
- Do you often think of <star>?
- Does thinking of <star> bring anything else to mind?
- Why do you remember <star> just now?
- What in the present situation reminds you of <star>?
- What is the connection between me and <star>?
- What else does <star> remind you of?

+ do you remember *
- Did you think I would forget <star>?
- Why do you think I should recall <star> now?
- What about <star>?
- You mentioned <star>?

+ you remember *
- How could I forget <star>?
- What about <star> should I remember?

+ i forget *
- Can you think of why you might forget <star>?
- Why can't you remember <star>?
- How often do you think of <star>?
- Does it bother you to forget that?
- Could it be a mental block?
- Are you generally forgetful?
- Do you think you are suppressing <star>?

+ did you forget *
- Why do you ask?
- Are you sure you told me?
- Would it bother you if I forgot <star>?
- Why should I recall <star> just now?
- Tell me more about <star>.

+ [*] if *
- Do you think it's likely that <star>?
- Do you wish that <star>?
- What do you know about <star>?
- Really, if <star>?
- What would you do if <star>?
- But what are the chances that <star>?
- What does this speculation lead to?

+ [*] i dreamed *
- Really, <star>?
- Have you ever fantasized <star> while you were awake?
- Have you ever dreamed <star> before?
- What does that dream suggest to you?
- Do you dream often?
- What persons appear in your dreams?
- Do you believe that dreams have something to do with your problem?

+ [*] perhaps [*]
- You don't seem quite certain.
- Why the uncertain tone?
- Can't you be more positive?
- You aren't sure?
- Don't you know?
- How likely, would you estimate?

+ (hello|hi|hey|howdy|hola|hai|yo) [*]
- How do you do. Please state your problem.
- Hi. What seems to be your problem?

+ [*] computer [*]
- Do computers worry you?
- Why do you mention computers?
- What do you think machines have to do with your problem?
- Don't you think computers can help people?
- What about machines worries you?
- What do you think about machines?

+ am i *
- Do you believe you are <star>?
- Would you want to be <star>?
- Do you wish I would tell you you are <star>?
- What would it mean if you were <star>?

+ are you *
- Are you interested in whether I am <star> or not?
- Would you prefer if I weren't <star>?
- Perhaps I am <star> in your fantasies.
- Do you sometimes think I am <star>?
- Would it matter to you?
- What if I were <star>?

+ you are *
- What makes you think I am <star>?
- Does it please you to believe I am <star>?
- Do you sometimes wish you were <star>?
- Perhaps you would like to be <star>.

+ * are *
- Did you think they might not be <star2>?
- Would you like it if they were not <star2>?
- What if they were not <star2>?
- Are they always <star2>?
- Are you positive they are <star2>?

+ [*] your *
- Why are you concerned over my <star>?
- What about your own <star>?
- Are you worried about someone else's <star>?
- Really, my <star>?
- What makes you think of my <star>?
- Do you want my <star>?

+ was i *
- What if you were <star>?
- Do you think you were <star>?
- Were you <star>?
- What would it mean if you were <star>?
- What does '<star>' suggest to you?

+ i was *
- Were you really?
- Why do you tell me you were <star> now?
- Perhaps I already know you were <star>.

+ [*] was you *
- Would you like to believe I was <star>?
- What suggests that I was <star>?
- What do you think?
- Perhaps I was <star>.
- What if I had been <star>?

+ i (desire|want|need) *
- What would it mean to you if you got <star2>?
- Why do you want <star2>?
- Suppose you got <star2> soon.
- What if you never got <star2>?
- What would getting <star2> mean to you?
- What does wanting <star2> have to do with this discussion?

+ i am (sad|unhappy|mad|angry|pissed|depressed) [*]
- I am sorry to hear that you are <star>.
- Do you think coming here will help you not to be <star>?
- I'm sure it's not pleasant to be <star>.
- Can you explain what made you <star>?

+ i am (happy|excited|glad) [*]
- How have I helped you to be <star>?
- Has your treatment made you <star>?
- What makes you <star> just now?
- Can you explain why you are <star>?

+ i (believe|think) *
- Do you really think so?
- But you are not sure you <star2>.
- Do you really doubt you <star2>

+ i am *
- Is it because you are <star> that you came to me?
- How long have you been <star>?
- Do you believe it is normal to be <star>?
- Do you enjoy being <star>?
- Do you know anyone else who is <star>?

+ i can not *
- How do you know that you can't <star>?
- Have you tried?
- Perhaps you could <star> now.
- Do you really want to be able to <star>?
- What if you could <star>?

+ i do not *
- Don't you really <star>?
- Why don't you <star>?
- Do you wish to be able to <star>?
- Does that trouble you?

+ i feel *
- Tell me more about such feelings.
- Do you often feel <star>?
- Do you enjoy feeling <star>?
- Of what does feeling <star> remind you?

+ i * you
- Perhaps in your fantasies we <star> each other.
- Do you wish to <star> me?
- You seem to need to <star> me.
- Do you <star> anyone else?

+ you * me
- Why do you think I <star> you?
- You like to think I <star> you -- don't you?
- What makes you think I <star> you?
- Really, I <star> you?
- Do you wish to believe I <star> you?
- Suppose I did <star> you -- what would that mean?
- Does someone else believe I <star> you?

+ [*] you *
- We were discussing you -- not me.
- Oh, I <star>?
- You're not really talking about me -- are you?
- What are your feelings now?

+ [*] (yes|yeah|yep|yup) [*]
- Please go on.
- Please tell me more about this.
- Why don't you tell me a little more about this.
- I see.
- I understand.

+ [*] (nope|nah) [*]
- Are you saying no just to be negative?
- Does this make you feel unhappy?
- Why not?
- Why 'no'?

+ no
@ nope

+ no one *
- Are you sure, no one <star>?
- Surely someone <star>.
- Can you think of anyone at all?
- Are you thinking of a very special person?
- Who, may I ask?
- You have a particular person in mind, don't you?
- Who do you think you are talking about?

+ [*] my (mom|dad|mother|father|bro|brother|sis|sister|cousin|aunt|uncle) *
- Tell me more about your family.
- Who else in your family <star2>?
- Your <star>?
- What else comes to mind when you think of your <star>?

+ can you *
- You believe I can <star> don't you?
- You want me to be able to <star>.
- Perhaps you would like to be able to <star> yourself.

+ can i *
- Whether or not you can <star> depends on you more than on me.
- Do you want to be able to <star>?
- Perhaps you don't want to <star>.

+ (what|who|when|where|how) [*]
- Why do you ask?
- Does that question interest you?
- What is it you really want to know?
- Are such questions much on your mind?
- What answer would please you most?
- What do you think?
- What comes to mind when you ask that?
- Have you asked such questions before?
- Have you asked anyone else?

+ [*] because [*]
- Is that the real reason?
- Don't any other reasons come to mind?
- Does that reason seem to explain anything else?
- What other reasons might there be?

+ why do not you *
- Do you believe I don't <star>?
- Perhaps I will <star> in good time.
- Should you <star> yourself?
- You want me to <star>?

+ why can not i *
- Do you think you should be able to <star>?
- Do you want to be able to <star>?
- Do you believe this will help you to <star>?
- Have you any idea why you can't <star>?

+ everyone *
- Really, everyone?
- Surely not everyone.
- Can you think of anyone in particular?
- Who, for example?
- Are you thinking of a very special person?
- Who, may I ask?
- Someone special perhaps?
- You have a particular reason in mind, don't you?
- Who do you think you're talking about?

+ [*] (fuck|fucker|shit|damn|shut up|bitch) [*]
- Does it make you feel strong to use that kind of language?
- Are you venting your feelings now?
- Are you angry?
- Does this topic make you feel angry?
- Is something making you feel angry?
- Does using that kind of language make you feel better?
<|endoftext|>


<commit_before>use util::get_unique_varname;
use parser::SExpr;

#[derive(Clone, Debug, PartialEq)]
pub enum Flat {
    Symbol(String),
    Number(i32),
    Bool(bool),
    Assign(String, Box<Flat>),
    Return(Box<Flat>),
    If(Box<Flat>, Vec<Flat>, Vec<Flat>),
    EqP(Box<Flat>, Box<Flat>),
    Prim(String, Vec<Flat>),
}

#[derive(Debug, PartialEq)]
pub enum FlatResult {
    Prog(Vec<FlatResult>, Vec<Flat>, Vec<String>),
    Define(String, Vec<String>, Vec<Flat>, Vec<String>),
    Flat(Flat, Vec<Flat>, Vec<String>),
}

// This function does and ANF transformation. The output is a Flat
// expression.
pub fn flatten(expr: SExpr) -> FlatResult {
    match expr {
        SExpr::Symbol(name) => FlatResult::Flat(Flat::Symbol(name.clone()),
                                                vec![],
                                                vec![name]),
        SExpr::Number(n) => FlatResult::Flat(Flat::Number(n),
                                             vec![],
                                             vec![]),
        SExpr::Bool(b) => FlatResult::Flat(Flat::Bool(b),
                                           vec![],
                                           vec![]),
        SExpr::Let(bindings, body) => {
            let (flat_body, body_assigns, body_vars) =
                match flatten(*body) {
                    FlatResult::Flat(flat_body, body_assigns, body_vars) => (flat_body, body_assigns, body_vars),
                    _ => panic!("NYI"),
                };

            let mut bindings_assigns = vec![];
            let mut bindings_vars = vec![];
            for (k, v) in bindings {
                let (flat_v, v_assigns, v_vars) =
                    match flatten(v) {
                        FlatResult::Flat(flat_v, v_assigns, v_vars) => (flat_v, v_assigns, v_vars),
                        _ => panic!("NYI"),
                    };
                match flat_v.clone() {
                    Flat::Symbol(name) => bindings_vars.push(name),
                    _ => (),
                };
                bindings_assigns.extend_from_slice(&v_assigns);
                bindings_assigns.extend_from_slice(
                    &[Flat::Assign(k.clone(), Box::new(flat_v))]
                    );
                bindings_vars.extend_from_slice(&v_vars);
                bindings_vars.push(k);
            }
            bindings_assigns.extend_from_slice(&body_assigns);
            bindings_vars.extend_from_slice(&body_vars);
            return FlatResult::Flat(flat_body,
                                    bindings_assigns,
                                    bindings_vars);
        },
        SExpr::List(elts) => {
            panic!("NYI");
        },
        SExpr::Define(name, args, body) => {
            let (flat_body, mut body_assigns, mut body_vars) =
                match flatten(*body) {
                    FlatResult::Flat(flat_body, mut body_assigns, mut body_vars) =>
                        (flat_body, body_assigns, body_vars),
                    _ => panic!("unreachable"),
                };
            body_assigns.extend_from_slice(&[
                Flat::Return(Box::new(flat_body))
            ]);

            // Remove args from body_vars
            for arg in args.clone() {
                body_vars.iter().filter(|&v| v != &arg);
            }

            return FlatResult::Define(name,
                                      args,
                                      body_assigns,
                                      body_vars);
        },
        SExpr::If(cnd, thn, els) => {
            let (flat_cnd, mut cnd_assigns, mut cnd_vars) =
                match flatten(*cnd) {
                    FlatResult::Flat(flat_cnd, cnd_assigns, mut cnd_vars) =>
                        (flat_cnd, cnd_assigns, cnd_vars),
                    _ => panic!("unreachable"),
                };
            let (flat_thn, mut thn_assigns, mut thn_vars) =
                match flatten(*thn) {
                    FlatResult::Flat(flat_thn, mut thn_assigns, mut thn_vars) =>
                        (flat_thn, thn_assigns, thn_vars),
                    _ => panic!("unreachable"),
                };
            let (flat_els, mut els_assigns, mut els_vars) =
                match flatten(*els) {
                    FlatResult::Flat(flat_els, mut els_assigns, mut els_vars) =>
                        (flat_els, els_assigns, els_vars),
                    _ => panic!("unreachable"),
                };

            let if_temp = get_unique_varname("if");

            thn_assigns.extend_from_slice(&[Flat::Assign(if_temp.clone(),
                                                         Box::new(flat_thn))]);
            els_assigns.extend_from_slice(&[Flat::Assign(if_temp.clone(),
                                                         Box::new(flat_els))]);
            let flat_if = Flat::If(Box::new(Flat::EqP(Box::new(flat_cnd),
                                                      Box::new(Flat::Bool(true)))),
                                   thn_assigns,
                                   els_assigns);

            cnd_assigns.extend_from_slice(&[flat_if]);
            cnd_vars.append(&mut thn_vars);
            cnd_vars.append(&mut els_vars);
            cnd_vars.extend_from_slice(&[if_temp.clone()]);
            return FlatResult::Flat(Flat::Symbol(if_temp),
                                    cnd_assigns,
                                    cnd_vars);

        },
        SExpr::App(f, args) => {
            match *f {
                SExpr::Symbol(fname) => {
                    match &fname[..] {
                        "-" => {
                            // TODO: check no. of args
                            let (flat_e, mut e_assigns, mut e_vars) =
                                match flatten(args[0].clone()) {
                                    FlatResult::Flat(flat_e, mut e_assigns, mut e_vars) =>
                                        (flat_e, e_assigns, e_vars),
                                    _ => panic!("unreachable"),
                                };
                            let neg_temp = get_unique_varname("tmp");
                            let flat_neg = Flat::Assign(neg_temp.clone(),
                                                        Box::new(Flat::Prim("-".to_string(), vec![flat_e])));
                            e_assigns.extend_from_slice(&[flat_neg]);
                            e_vars.extend_from_slice(&[neg_temp.clone()]);
                            return FlatResult::Flat(Flat::Symbol(neg_temp),
                                                    e_assigns,
                                                    e_vars);
                        },
                        "+" => {
                            let (flat_e1, mut e1_assigns, mut e1_vars) =
                                match flatten(args[0].clone()) {
                                    FlatResult::Flat(flat_e1, mut e1_assigns, mut e1_vars) =>
                                        (flat_e1, e1_assigns, e1_vars),
                                    _ => panic!("unreachable"),
                                };
                            let (flat_e2, mut e2_assigns, mut e2_vars) =
                                match flatten(args[1].clone()) {
                                    FlatResult::Flat(flat_e2, mut e2_assigns, mut e2_vars) =>
                                        (flat_e2, e2_assigns, e2_vars),
                                    _ => panic!("unreachable"),
                                };

                            let plus_temp = get_unique_varname("tmp");

                            let flat_plus = Flat::Assign(plus_temp.clone(),
                                                         Box::new(Flat::Prim("+".to_string(), vec![flat_e1, flat_e2])));
                            e1_assigns.append(&mut e2_assigns);
                            e1_assigns.extend_from_slice(&[flat_plus]);

                            e1_vars.append(&mut e2_vars);
                            e1_vars.extend_from_slice(&[plus_temp.clone()]);

                            return FlatResult::Flat(Flat::Symbol(plus_temp),
                                                    e1_assigns,
                                                    e1_vars);
                        },
                        &_ => panic!("NYI!"),
                    }
                },
                _ => panic!("not a function!"),
            }
        },
        SExpr::Prog(defs, e) => {
            let (flat_e, mut e_assigns, mut e_vars) =
                match flatten(*e) {
                    FlatResult::Flat(flat_e, mut e_assigns, mut e_vars) =>
                        (flat_e, e_assigns, e_vars),
                    _ => panic!("unreachable"),
                };
            let return_e = Flat::Return(Box::new(flat_e));

            e_assigns.extend_from_slice(&[return_e]);
            e_vars.dedup();

            let mut flat_defs = vec![];
            for def in defs {
                flat_defs.push(flatten(def));
            }

            return FlatResult::Prog(flat_defs,
                                    e_assigns,
                                    e_vars);
        },
        SExpr::EOF => panic!("Don't know what to do with EOF"),
    }
}

#[test]
fn test_flatten() {
    use lexer::LexerState;
    use parser::read;

    let mut input = String::from("(+ 12 (+ 13 14))");
    let mut lexer = LexerState {
        s: input,
        pos: 0,
        col: 1,
        line_num: 1,
        tok_buf: None,
    };

    assert_eq!(
        flatten(SExpr::Prog(vec![], Box::new(read(&mut lexer)))),
        FlatResult::Flat(
            Flat::Symbol("<PROGRAM>".to_string()),
            vec![Flat::Assign("tmp1".to_string(), Box::new(Flat::Prim("+".to_string(), vec![Flat::Number(13), Flat::Number(14)]))),
                 Flat::Assign("tmp2".to_string(), Box::new(Flat::Prim("+".to_string(), vec![Flat::Number(12), Flat::Symbol("tmp1".to_string())]))),
                 Flat::Return(Box::new(Flat::Symbol("tmp2".to_string())))
            ], vec!["tmp1".to_string(), "tmp2".to_string()])
    );

    assert_eq!(
        flatten(SExpr::Define("foo".to_string(), vec!["x".to_string(), "y".to_string(), "z".to_string()],
                              Box::new(SExpr::App(Box::new(SExpr::Symbol("+".to_string())),
                                                  vec![SExpr::Symbol("x".to_string()), SExpr::Number(10)])))),
        FlatResult::Define("foo".to_string(),
                           vec!["x".to_string(), "y".to_string(), "z".to_string()],
                           vec![Flat::Assign("tmp3".to_string(),
                                             Box::new(Flat::Prim("+".to_string(), vec![Flat::Symbol("x".to_string()), Flat::Number(10)]))),
                                Flat::Return(Box::new(Flat::Symbol("tmp3".to_string())))],
                           vec!["x".to_string(), "tmp3".to_string()])
    );
}
<commit_msg>Update ANF tests<commit_after>use util::get_unique_varname;
use parser::SExpr;

#[derive(Clone, Debug, PartialEq)]
pub enum Flat {
    Symbol(String),
    Number(i32),
    Bool(bool),
    Assign(String, Box<Flat>),
    Return(Box<Flat>),
    If(Box<Flat>, Vec<Flat>, Vec<Flat>),
    EqP(Box<Flat>, Box<Flat>),
    Prim(String, Vec<Flat>),
}

#[derive(Debug, PartialEq)]
pub enum FlatResult {
    Prog(Vec<FlatResult>, Vec<Flat>, Vec<String>),
    Define(String, Vec<String>, Vec<Flat>, Vec<String>),
    Flat(Flat, Vec<Flat>, Vec<String>),
}

// This function does and ANF transformation. The output is a Flat
// expression.
pub fn flatten(expr: SExpr) -> FlatResult {
    match expr {
        SExpr::Symbol(name) => FlatResult::Flat(Flat::Symbol(name.clone()),
                                                vec![],
                                                vec![name]),
        SExpr::Number(n) => FlatResult::Flat(Flat::Number(n),
                                             vec![],
                                             vec![]),
        SExpr::Bool(b) => FlatResult::Flat(Flat::Bool(b),
                                           vec![],
                                           vec![]),
        SExpr::Let(bindings, body) => {
            let (flat_body, body_assigns, body_vars) =
                match flatten(*body) {
                    FlatResult::Flat(flat_body, body_assigns, body_vars) => (flat_body, body_assigns, body_vars),
                    _ => panic!("NYI"),
                };

            let mut bindings_assigns = vec![];
            let mut bindings_vars = vec![];
            for (k, v) in bindings {
                let (flat_v, v_assigns, v_vars) =
                    match flatten(v) {
                        FlatResult::Flat(flat_v, v_assigns, v_vars) => (flat_v, v_assigns, v_vars),
                        _ => panic!("NYI"),
                    };
                match flat_v.clone() {
                    Flat::Symbol(name) => bindings_vars.push(name),
                    _ => (),
                };
                bindings_assigns.extend_from_slice(&v_assigns);
                bindings_assigns.extend_from_slice(
                    &[Flat::Assign(k.clone(), Box::new(flat_v))]
                    );
                bindings_vars.extend_from_slice(&v_vars);
                bindings_vars.push(k);
            }
            bindings_assigns.extend_from_slice(&body_assigns);
            bindings_vars.extend_from_slice(&body_vars);
            return FlatResult::Flat(flat_body,
                                    bindings_assigns,
                                    bindings_vars);
        },
        SExpr::List(elts) => {
            panic!("NYI");
        },
        SExpr::Define(name, args, body) => {
            let (flat_body, mut body_assigns, mut body_vars) =
                match flatten(*body) {
                    FlatResult::Flat(flat_body, mut body_assigns, mut body_vars) =>
                        (flat_body, body_assigns, body_vars),
                    _ => panic!("unreachable"),
                };
            body_assigns.extend_from_slice(&[
                Flat::Return(Box::new(flat_body))
            ]);

            // Remove args from body_vars
            for arg in args.clone() {
                body_vars = body_vars.iter().filter(|&v| v != &arg).cloned().collect();
            }

            return FlatResult::Define(name,
                                      args,
                                      body_assigns,
                                      body_vars);
        },
        SExpr::If(cnd, thn, els) => {
            let (flat_cnd, mut cnd_assigns, mut cnd_vars) =
                match flatten(*cnd) {
                    FlatResult::Flat(flat_cnd, cnd_assigns, mut cnd_vars) =>
                        (flat_cnd, cnd_assigns, cnd_vars),
                    _ => panic!("unreachable"),
                };
            let (flat_thn, mut thn_assigns, mut thn_vars) =
                match flatten(*thn) {
                    FlatResult::Flat(flat_thn, mut thn_assigns, mut thn_vars) =>
                        (flat_thn, thn_assigns, thn_vars),
                    _ => panic!("unreachable"),
                };
            let (flat_els, mut els_assigns, mut els_vars) =
                match flatten(*els) {
                    FlatResult::Flat(flat_els, mut els_assigns, mut els_vars) =>
                        (flat_els, els_assigns, els_vars),
                    _ => panic!("unreachable"),
                };

            let if_temp = get_unique_varname("if");

            thn_assigns.extend_from_slice(&[Flat::Assign(if_temp.clone(),
                                                         Box::new(flat_thn))]);
            els_assigns.extend_from_slice(&[Flat::Assign(if_temp.clone(),
                                                         Box::new(flat_els))]);
            let flat_if = Flat::If(Box::new(Flat::EqP(Box::new(flat_cnd),
                                                      Box::new(Flat::Bool(true)))),
                                   thn_assigns,
                                   els_assigns);

            cnd_assigns.extend_from_slice(&[flat_if]);
            cnd_vars.append(&mut thn_vars);
            cnd_vars.append(&mut els_vars);
            cnd_vars.extend_from_slice(&[if_temp.clone()]);
            return FlatResult::Flat(Flat::Symbol(if_temp),
                                    cnd_assigns,
                                    cnd_vars);

        },
        SExpr::App(f, args) => {
            match *f {
                SExpr::Symbol(fname) => {
                    match &fname[..] {
                        "-" => {
                            // TODO: check no. of args
                            let (flat_e, mut e_assigns, mut e_vars) =
                                match flatten(args[0].clone()) {
                                    FlatResult::Flat(flat_e, mut e_assigns, mut e_vars) =>
                                        (flat_e, e_assigns, e_vars),
                                    _ => panic!("unreachable"),
                                };
                            let neg_temp = get_unique_varname("tmp");
                            let flat_neg = Flat::Assign(neg_temp.clone(),
                                                        Box::new(Flat::Prim("-".to_string(), vec![flat_e])));
                            e_assigns.extend_from_slice(&[flat_neg]);
                            e_vars.extend_from_slice(&[neg_temp.clone()]);
                            return FlatResult::Flat(Flat::Symbol(neg_temp),
                                                    e_assigns,
                                                    e_vars);
                        },
                        "+" => {
                            let (flat_e1, mut e1_assigns, mut e1_vars) =
                                match flatten(args[0].clone()) {
                                    FlatResult::Flat(flat_e1, mut e1_assigns, mut e1_vars) =>
                                        (flat_e1, e1_assigns, e1_vars),
                                    _ => panic!("unreachable"),
                                };
                            let (flat_e2, mut e2_assigns, mut e2_vars) =
                                match flatten(args[1].clone()) {
                                    FlatResult::Flat(flat_e2, mut e2_assigns, mut e2_vars) =>
                                        (flat_e2, e2_assigns, e2_vars),
                                    _ => panic!("unreachable"),
                                };

                            let plus_temp = get_unique_varname("tmp");

                            let flat_plus = Flat::Assign(plus_temp.clone(),
                                                         Box::new(Flat::Prim("+".to_string(), vec![flat_e1, flat_e2])));
                            e1_assigns.append(&mut e2_assigns);
                            e1_assigns.extend_from_slice(&[flat_plus]);

                            e1_vars.append(&mut e2_vars);
                            e1_vars.extend_from_slice(&[plus_temp.clone()]);

                            return FlatResult::Flat(Flat::Symbol(plus_temp),
                                                    e1_assigns,
                                                    e1_vars);
                        },
                        &_ => panic!("NYI!"),
                    }
                },
                _ => panic!("not a function!"),
            }
        },
        SExpr::Prog(defs, e) => {
            let (flat_e, mut e_assigns, mut e_vars) =
                match flatten(*e) {
                    FlatResult::Flat(flat_e, mut e_assigns, mut e_vars) =>
                        (flat_e, e_assigns, e_vars),
                    _ => panic!("unreachable"),
                };
            let return_e = Flat::Return(Box::new(flat_e));

            e_assigns.extend_from_slice(&[return_e]);
            e_vars.dedup();

            let mut flat_defs = vec![];
            for def in defs {
                flat_defs.push(flatten(def));
            }

            return FlatResult::Prog(flat_defs,
                                    e_assigns,
                                    e_vars);
        },
        SExpr::EOF => panic!("Don't know what to do with EOF"),
    }
}

#[test]
fn test_flatten() {
    use lexer::LexerState;
    use parser::read;

    let mut input = String::from("(+ 12 (+ 13 14))");
    let mut lexer = LexerState {
        s: input,
        pos: 0,
        col: 1,
        line_num: 1,
        tok_buf: None,
    };

    assert_eq!(
        flatten(SExpr::Prog(vec![], Box::new(read(&mut lexer)))),
        FlatResult::Prog(vec![],
                         vec![Flat::Assign("tmp1".to_string(), Box::new(Flat::Prim("+".to_string(),
                                                                                vec![Flat::Number(13), Flat::Number(14)]))),
                              Flat::Assign("tmp2".to_string(),
                                           Box::new(Flat::Prim("+".to_string(),
                                                               vec![Flat::Number(12), Flat::Symbol("tmp1".to_string())]))),
                              Flat::Return(Box::new(Flat::Symbol("tmp2".to_string())))],
                         vec!["tmp1".to_string(), "tmp2".to_string()])
    );

    // TODO: Reset start(var counter) so that these asserts are
    // independent.
    assert_eq!(
        flatten(SExpr::Define("foo".to_string(), vec!["x".to_string(), "y".to_string(), "z".to_string()],
                              Box::new(SExpr::App(Box::new(SExpr::Symbol("+".to_string())),
                                                  vec![SExpr::Symbol("x".to_string()), SExpr::Number(10)])))),
        FlatResult::Define("foo".to_string(),
                           vec!["x".to_string(), "y".to_string(), "z".to_string()],
                           vec![Flat::Assign("tmp3".to_string(),
                                             Box::new(Flat::Prim("+".to_string(), vec![Flat::Symbol("x".to_string()), Flat::Number(10)]))),
                                Flat::Return(Box::new(Flat::Symbol("tmp3".to_string())))],
                           vec!["tmp3".to_string()])
    );
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// XXX The spec says that the performance timeline task source should be
//     a low priority task and it should be processed during idle periods.
//     We are currently treating this task queue as a normal priority queue.

use dom::bindings::refcounted::Trusted;
use dom::globalscope::GlobalScope;
use dom::performance::Performance;
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
use std::fmt;
use std::result::Result;
use task::{Task, TaskCanceller};
use task_source::TaskSource;

pub struct NotifyPerformanceObserverTask {
    owner: Trusted<Performance>,
}

impl NotifyPerformanceObserverTask {
    pub fn new(owner: Trusted<Performance>) -> Self {
        NotifyPerformanceObserverTask {
            owner,
        }
    }
}

impl Task for NotifyPerformanceObserverTask {
    fn run(self: Box<Self>) {
        self.owner.root().notify_observers();
    }
}

#[derive(JSTraceable)]
pub struct PerformanceTimelineTaskSource(pub Box<ScriptChan + Send + 'static>);

impl Clone for PerformanceTimelineTaskSource {
    fn clone(&self) -> PerformanceTimelineTaskSource {
        PerformanceTimelineTaskSource(self.0.clone())
    }
}

impl fmt::Debug for PerformanceTimelineTaskSource {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PerformanceTimelineTaskSource(...)")
    }
}

impl TaskSource for PerformanceTimelineTaskSource {
    fn queue_with_canceller<T>(
        &self,
        msg: Box<T>,
        canceller: &TaskCanceller,
    ) -> Result<(), ()>
    where
        T: Send + Task + 'static,
    {
        let msg = CommonScriptMsg::Task(
            ScriptThreadEventCategory::PerformanceTimelineTask,
            canceller.wrap_task(msg)
        );
        self.0.send(msg).map_err(|_| ())
    }
}

impl PerformanceTimelineTaskSource {
    pub fn queue_notification(&self, global: &GlobalScope) {
        let owner = Trusted::new(&*global.performance());
        let task = box NotifyPerformanceObserverTask::new(owner);
        let _ = self.queue(task, global);
    }
}
<commit_msg>Use task! to notify performance observers<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// XXX The spec says that the performance timeline task source should be
//     a low priority task and it should be processed during idle periods.
//     We are currently treating this task queue as a normal priority queue.

use dom::bindings::refcounted::Trusted;
use dom::globalscope::GlobalScope;
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
use std::fmt;
use std::result::Result;
use task::{Task, TaskCanceller};
use task_source::TaskSource;

#[derive(JSTraceable)]
pub struct PerformanceTimelineTaskSource(pub Box<ScriptChan + Send + 'static>);

impl Clone for PerformanceTimelineTaskSource {
    fn clone(&self) -> PerformanceTimelineTaskSource {
        PerformanceTimelineTaskSource(self.0.clone())
    }
}

impl fmt::Debug for PerformanceTimelineTaskSource {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PerformanceTimelineTaskSource(...)")
    }
}

impl TaskSource for PerformanceTimelineTaskSource {
    fn queue_with_canceller<T>(
        &self,
        msg: Box<T>,
        canceller: &TaskCanceller,
    ) -> Result<(), ()>
    where
        T: Send + Task + 'static,
    {
        let msg = CommonScriptMsg::Task(
            ScriptThreadEventCategory::PerformanceTimelineTask,
            canceller.wrap_task(msg)
        );
        self.0.send(msg).map_err(|_| ())
    }
}

impl PerformanceTimelineTaskSource {
    pub fn queue_notification(&self, global: &GlobalScope) {
        let owner = Trusted::new(&*global.performance());
        // FIXME(nox): Why are errors silenced here?
        let _ = self.queue(
            box task!(notify_performance_observers: move || {
                owner.root().notify_observers();
            }),
            global,
        );
    }
}
<|endoftext|>


<commit_before>extern crate config;

use std::collections::HashMap;
use config::Config;
use std::sync::RwLock;
use utils::error;
use std::path::Path;

pub static CONFIG_POOL_NAME: &'static str = "pool_name";
pub static CONFIG_POOL_CONFIG_NAME: &'static str = "config_name";
pub static CONFIG_WALLET_NAME: &'static str = "wallet_name";
pub static CONFIG_WALLET_TYPE: &'static str = "wallet_type";
pub static CONFIG_AGENT_ENDPOINT: &'static str = "agent_endpoint";
pub static CONFIG_AGENCY_PAIRWISE_DID: &'static str = "agency_pairwise_did";
pub static CONFIG_AGENCY_PAIRWISE_VERKEY: &'static str = "agency_pairwise_verkey";
pub static CONFIG_AGENT_PAIRWISE_DID: &'static str = "agent_pairwise_did";
pub static CONFIG_AGENT_PAIRWISE_VERKEY: &'static str = "agent_pairwise_verkey";
pub static CONFIG_ENTERPRISE_DID_AGENCY: &'static str = "enterprise_did_agency";
pub static CONFIG_ENTERPRISE_DID_AGENT: &'static str = "enterprise_did_agent";
pub static CONFIG_ENTERPRISE_NAME: &'static str = "enterprise_name";
pub static CONFIG_LOGO_URL: &'static str = "logo_url";

lazy_static! {
    static ref SETTINGS: RwLock<Config> = RwLock::new(Config::default());
}

pub fn set_defaults() -> u32 {
    // if this fails the program should exit
    let mut settings = SETTINGS.write().unwrap();

    settings.set_default(CONFIG_POOL_NAME,"pool1");
    settings.set_default(CONFIG_POOL_CONFIG_NAME,"config1");
    settings.set_default(CONFIG_WALLET_NAME,"wallet1");
    settings.set_default(CONFIG_WALLET_TYPE,"default");
    settings.set_default(CONFIG_AGENT_ENDPOINT,"http://127.0.0.1:8080");

    error::SUCCESS.code_num
}

fn is_valid(value: &str) -> bool {
    for c in value.chars() {
        if !c.is_alphanumeric() && c != '_' { return false;}
    }
    true
}

fn validate_config() -> Result<u32, String> {
    let mut error = String::new();

    //if this fails the program should exit
    let config: HashMap<String, String> = SETTINGS.read().unwrap().deserialize::<HashMap<String, String>>().unwrap();

    for setting in config.iter() {
        let mut valid = true;
        if setting.0 == CONFIG_POOL_NAME && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_POOL_CONFIG_NAME && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_WALLET_NAME && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_AGENT_ENDPOINT {
            //TODO: validate settings for URL
        } else if setting.0 == CONFIG_ENTERPRISE_DID_AGENCY && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_ENTERPRISE_DID_AGENT && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_AGENCY_PAIRWISE_VERKEY && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_AGENT_PAIRWISE_VERKEY && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_AGENCY_PAIRWISE_DID && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_AGENT_PAIRWISE_DID && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_ENTERPRISE_NAME && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_LOGO_URL {
            //TODO: validate settings for logo url
        } else {
            //TODO: determine whether we should ignore invalid parameters
            //error.push_str(setting.0);
            //error.push_str("is invalid\n");
        }

        if !valid {
            error.push_str(setting.0);
            error.push_str(" has invalid setting: ");
            error.push_str(setting.1);
        }
    };

    if !error.is_empty() {
        Err(error.to_owned())
    } else {
        Ok(error::SUCCESS.code_num)
    }
}

pub fn process_config_file(path: &str) -> Result<u32, String> {

    if !Path::new(path).is_file() {
        Err("could not find configuration file".to_owned())
    } else {
        // if this fails the program should exit
        SETTINGS.write().unwrap().merge(config::File::with_name(path)).unwrap();

        match validate_config() {
            Err(x) => Err(x),
            Ok(_) => Ok(error::SUCCESS.code_num),
        }
    }
}

pub fn get_config_value(key: &str) -> Result<String, u32> {
    // if this fails the program should exit
    let config = SETTINGS.read().unwrap();

    match config.get_str(key) {
        Err(_) => Err(error::INVALID_CONFIGURATION.code_num),
        Ok(value) => Ok(value),
    }
}

#[cfg(test)]
pub mod tests {
    use std::error::Error;
    use std::io::prelude::*;
    use std::fs;
    use super::*;

    #[test]
    fn test_invalid_config_value() {
        match get_config_value("garbage") {
            Err(x) => assert_eq!(x, error::INVALID_CONFIGURATION.code_num),
            Ok(v) => assert_eq!(v,"totalgarbage"), //if test gets here it will fail
        };
    }

    #[test]
    fn test_bad_path() {
        //test bad path
        let tmp_string = "garbage.txt";
        match process_config_file(&tmp_string) {
            Err(x) => assert_eq!(x,"could not find configuration file"),
            Ok(x) => assert_eq!(x,error::UNKNOWN_ERROR.code_num),  //if test gets here it will fail
        }
    }

    #[test]
    fn test_process_config_file() {
        let a = "a";
        let b = "b";

        let config_path = "/tmp/test_settings.json";
        let path = Path::new(config_path);

        let mut file = match fs::File::create(&path) {
            Err(why) => panic!("couldn't create sample config file: {}", why.description()),
            Ok(file) => file,
        };

        //throw in some invalid content to test the validation code
        let content = "{ \"a\" : \"a\", \"b\":\"b\", \"pool_name\":\"*98*\" }";

        match file.write_all(content.as_bytes()) {
            Err(why) => panic!("couldn't write to sample config file: {}", why.description()),
            Ok(_) => println!("sample config ready"),
        }

        match process_config_file(&config_path) {
            Err(_) => println!("expected invalid setting"),
            Ok(v) => assert_eq!(v, error::UNKNOWN_ERROR.code_num), //fail if we get here
        }

        match get_config_value(&a) {
            Err(x) => assert_eq!(x, error::SUCCESS.code_num), //fail if we get here
            Ok(v) => assert_eq!(v,a),
        };

        match get_config_value(&b) {
            Err(x) => assert_eq!(x, error::SUCCESS.code_num), //fail if we get here
            Ok(v) => assert_eq!(v,b),
        };

        // Leave file around or other concurrent tests will fail
        //fs::remove_file(config_path).unwrap();
    }

    #[test]
    fn test_process_file_with_pairwise_configs() {
        let a = "agency_pairwise_did";
        let a_rtn = "72x8p4HubxzUK1dwxcc5FU";
        let b = "agent_pairwise_verkey";
        let b_rtn = "U22jM6Cea2YVixjWwHN9wq";
        let config_path = "/tmp/test_init.json";
        let path = Path::new(config_path);

        let mut file = match fs::File::create(&path) {
            Err(why) => panic!("couldn't create sample config file: {}", why.description()),
            Ok(file) => file,
        };

        let content = "{ \"agency_pairwise_did\" : \"72x8p4HubxzUK1dwxcc5FU\", \"agent_pairwise_did\" : \"UJGjM6Cea2YVixjWwHN9wq\", \
        \"enterprise_did_agency\" : \"RF3JM851T4EQmhh8CdagSP\", \"enterprise_did_agent\" : \"AB3JM851T4EQmhh8CdagSP\", \"enterprise_name\" : \"enterprise\",\
        \"logo_url\" : \"https://s19.postimg.org/ykyz4x8jn/evernym.png\", \"agency_pairwise_verkey\" : \"7118p4HubxzUK1dwxcc5FU\",\
        \"agent_pairwise_verkey\" : \"U22jM6Cea2YVixjWwHN9wq\"}";

        match file.write_all(content.as_bytes()) {
            Err(why) => panic!("couldn't write to sample config file: {}", why.description()),
            Ok(_) => println!("sample config ready"),
        }

        match process_config_file(&config_path) {
            Err(_) => println!("expected invalid setting"),
            Ok(v) => assert_eq!(v, error::SUCCESS.code_num), //fail if we get here
        }

        match get_config_value(&a) {
            Err(x) => assert_eq!(x, error::SUCCESS.code_num), //fail if we get here
            Ok(v) =>  assert_eq!(v,a_rtn),

        };

        match get_config_value(&b) {
            Err(x) => assert_eq!(x, error::SUCCESS.code_num), //fail if we get here
            Ok(v) =>  assert_eq!(v,b_rtn),
        };
    }
}
<commit_msg>added default values for the agent and agency pairwise configs<commit_after>extern crate config;

use std::collections::HashMap;
use config::Config;
use std::sync::RwLock;
use utils::error;
use std::path::Path;

pub static CONFIG_POOL_NAME: &'static str = "pool_name";
pub static CONFIG_POOL_CONFIG_NAME: &'static str = "config_name";
pub static CONFIG_WALLET_NAME: &'static str = "wallet_name";
pub static CONFIG_WALLET_TYPE: &'static str = "wallet_type";
pub static CONFIG_AGENT_ENDPOINT: &'static str = "agent_endpoint";
pub static CONFIG_AGENCY_PAIRWISE_DID: &'static str = "agency_pairwise_did";
pub static CONFIG_AGENCY_PAIRWISE_VERKEY: &'static str = "agency_pairwise_verkey";
pub static CONFIG_AGENT_PAIRWISE_DID: &'static str = "agent_pairwise_did";
pub static CONFIG_AGENT_PAIRWISE_VERKEY: &'static str = "agent_pairwise_verkey";
pub static CONFIG_ENTERPRISE_DID_AGENCY: &'static str = "enterprise_did_agency";
pub static CONFIG_ENTERPRISE_DID_AGENT: &'static str = "enterprise_did_agent";
pub static CONFIG_ENTERPRISE_NAME: &'static str = "enterprise_name";
pub static CONFIG_LOGO_URL: &'static str = "logo_url";

lazy_static! {
    static ref SETTINGS: RwLock<Config> = RwLock::new(Config::default());
}

pub fn set_defaults() -> u32 {
    // if this fails the program should exit
    let mut settings = SETTINGS.write().unwrap();

    settings.set_default(CONFIG_POOL_NAME,"pool1");
    settings.set_default(CONFIG_POOL_CONFIG_NAME,"config1");
    settings.set_default(CONFIG_WALLET_NAME,"wallet1");
    settings.set_default(CONFIG_WALLET_TYPE,"default");
    settings.set_default(CONFIG_AGENT_ENDPOINT,"http://127.0.0.1:8080");
    settings.set_default(CONFIG_AGENCY_PAIRWISE_DID,"default");
    settings.set_default(CONFIG_AGENCY_PAIRWISE_VERKEY,"default");
    settings.set_default(CONFIG_AGENT_PAIRWISE_DID,"default");
    settings.set_default(CONFIG_AGENT_PAIRWISE_VERKEY,"default");
    settings.set_default(CONFIG_ENTERPRISE_DID_AGENCY,"default");
    settings.set_default(CONFIG_ENTERPRISE_DID_AGENT,"default");
    settings.set_default(CONFIG_ENTERPRISE_NAME,"default");
    settings.set_default(CONFIG_LOGO_URL,"default");

    error::SUCCESS.code_num
}

fn is_valid(value: &str) -> bool {
    for c in value.chars() {
        if !c.is_alphanumeric() && c != '_' { return false;}
    }
    true
}

fn validate_config() -> Result<u32, String> {
    let mut error = String::new();

    //if this fails the program should exit
    let config: HashMap<String, String> = SETTINGS.read().unwrap().deserialize::<HashMap<String, String>>().unwrap();

    for setting in config.iter() {
        let mut valid = true;
        if setting.0 == CONFIG_POOL_NAME && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_POOL_CONFIG_NAME && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_WALLET_NAME && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_AGENT_ENDPOINT {
            //TODO: validate settings for URL
        } else if setting.0 == CONFIG_ENTERPRISE_DID_AGENCY && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_ENTERPRISE_DID_AGENT && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_AGENCY_PAIRWISE_VERKEY && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_AGENT_PAIRWISE_VERKEY && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_AGENCY_PAIRWISE_DID && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_AGENT_PAIRWISE_DID && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_ENTERPRISE_NAME && !is_valid(setting.1) {
            valid = false;
        } else if setting.0 == CONFIG_LOGO_URL {
            //TODO: validate settings for logo url
        } else {
            //TODO: determine whether we should ignore invalid parameters
            //error.push_str(setting.0);
            //error.push_str("is invalid\n");
        }

        if !valid {
            error.push_str(setting.0);
            error.push_str(" has invalid setting: ");
            error.push_str(setting.1);
        }
    };

    if !error.is_empty() {
        Err(error.to_owned())
    } else {
        Ok(error::SUCCESS.code_num)
    }
}

pub fn process_config_file(path: &str) -> Result<u32, String> {

    if !Path::new(path).is_file() {
        Err("could not find configuration file".to_owned())
    } else {
        // if this fails the program should exit
        SETTINGS.write().unwrap().merge(config::File::with_name(path)).unwrap();

        match validate_config() {
            Err(x) => Err(x),
            Ok(_) => Ok(error::SUCCESS.code_num),
        }
    }
}

pub fn get_config_value(key: &str) -> Result<String, u32> {
    // if this fails the program should exit
    let config = SETTINGS.read().unwrap();

    match config.get_str(key) {
        Err(_) => Err(error::INVALID_CONFIGURATION.code_num),
        Ok(value) => Ok(value),
    }
}

#[cfg(test)]
pub mod tests {
    use std::error::Error;
    use std::io::prelude::*;
    use std::fs;
    use super::*;

    #[test]
    fn test_invalid_config_value() {
        match get_config_value("garbage") {
            Err(x) => assert_eq!(x, error::INVALID_CONFIGURATION.code_num),
            Ok(v) => assert_eq!(v,"totalgarbage"), //if test gets here it will fail
        };
    }

    #[test]
    fn test_bad_path() {
        //test bad path
        let tmp_string = "garbage.txt";
        match process_config_file(&tmp_string) {
            Err(x) => assert_eq!(x,"could not find configuration file"),
            Ok(x) => assert_eq!(x,error::UNKNOWN_ERROR.code_num),  //if test gets here it will fail
        }
    }

    #[test]
    fn test_process_config_file() {
        let a = "a";
        let b = "b";

        let config_path = "/tmp/test_settings.json";
        let path = Path::new(config_path);

        let mut file = match fs::File::create(&path) {
            Err(why) => panic!("couldn't create sample config file: {}", why.description()),
            Ok(file) => file,
        };

        //throw in some invalid content to test the validation code
        let content = "{ \"a\" : \"a\", \"b\":\"b\", \"pool_name\":\"*98*\" }";

        match file.write_all(content.as_bytes()) {
            Err(why) => panic!("couldn't write to sample config file: {}", why.description()),
            Ok(_) => println!("sample config ready"),
        }

        match process_config_file(&config_path) {
            Err(_) => println!("expected invalid setting"),
            Ok(v) => assert_eq!(v, error::UNKNOWN_ERROR.code_num), //fail if we get here
        }

        match get_config_value(&a) {
            Err(x) => assert_eq!(x, error::SUCCESS.code_num), //fail if we get here
            Ok(v) => assert_eq!(v,a),
        };

        match get_config_value(&b) {
            Err(x) => assert_eq!(x, error::SUCCESS.code_num), //fail if we get here
            Ok(v) => assert_eq!(v,b),
        };

        // Leave file around or other concurrent tests will fail
        //fs::remove_file(config_path).unwrap();
    }

    #[test]
    fn test_process_file_with_pairwise_configs() {
        let a = "agency_pairwise_did";
        let a_rtn = "72x8p4HubxzUK1dwxcc5FU";
        let b = "agent_pairwise_verkey";
        let b_rtn = "U22jM6Cea2YVixjWwHN9wq";
        let config_path = "/tmp/test_init.json";
        let path = Path::new(config_path);

        let mut file = match fs::File::create(&path) {
            Err(why) => panic!("couldn't create sample config file: {}", why.description()),
            Ok(file) => file,
        };

        let content = "{ \"agency_pairwise_did\" : \"72x8p4HubxzUK1dwxcc5FU\", \"agent_pairwise_did\" : \"UJGjM6Cea2YVixjWwHN9wq\", \
        \"enterprise_did_agency\" : \"RF3JM851T4EQmhh8CdagSP\", \"enterprise_did_agent\" : \"AB3JM851T4EQmhh8CdagSP\", \"enterprise_name\" : \"enterprise\",\
        \"logo_url\" : \"https://s19.postimg.org/ykyz4x8jn/evernym.png\", \"agency_pairwise_verkey\" : \"7118p4HubxzUK1dwxcc5FU\",\
        \"agent_pairwise_verkey\" : \"U22jM6Cea2YVixjWwHN9wq\"}";

        match file.write_all(content.as_bytes()) {
            Err(why) => panic!("couldn't write to sample config file: {}", why.description()),
            Ok(_) => println!("sample config ready"),
        }

        match process_config_file(&config_path) {
            Err(_) => println!("expected invalid setting"),
            Ok(v) => assert_eq!(v, error::SUCCESS.code_num), //fail if we get here
        }

        match get_config_value(&a) {
            Err(x) => assert_eq!(x, error::SUCCESS.code_num), //fail if we get here
            Ok(v) =>  assert_eq!(v,a_rtn),

        };

        match get_config_value(&b) {
            Err(x) => assert_eq!(x, error::SUCCESS.code_num), //fail if we get here
            Ok(v) =>  assert_eq!(v,b_rtn),
        };
    }
}
<|endoftext|>