<commit_before>//! The `source` subcommand.

use colored::*;

use command_runner::CommandRunner;
use errors::*;
use project::Project;

/// We implement `source` with a trait so we put it in its own module.
pub trait CommandSource {
    /// List all the source trees associated with a project.
    fn source_list<CR>(&self, runner: &CR) -> Result<()> where CR: CommandRunner;

    /// Clone the specified source tree.
    fn source_clone<CR>(&self, runner: &CR, alias: &str) -> Result<()>
        where CR: CommandRunner;

    /// Set the `mounted` flag on the specified source tree.
    fn source_set_mounted<CR>(&mut self,
                              runner: &CR,
                              alias: &str,
                              mounted: bool)
                              -> Result<()>
        where CR: CommandRunner;
}

impl CommandSource for Project {
    fn source_list<CR>(&self, _runner: &CR) -> Result<()>
        where CR: CommandRunner
    {
        for source in self.sources().iter() {
            println!("{:25} {}", source.alias().green(), source.context());
            if source.is_available_locally(self) {
                let path = source.path(self)
                    .canonicalize()?
                    .strip_prefix(self.root_dir())?
                    .to_owned();
                let mounted = if source.mounted() {
                    "(mounted)".normal()
                } else {
                    "(NOT MOUNTED)".red().bold()
                };
                println!("  Available at {} {}", path.display(), mounted);
            }
        }
        Ok(())
    }

    fn source_clone<CR>(&self, runner: &CR, alias: &str) -> Result<()>
        where CR: CommandRunner
    {
        let source = self.sources()
            .find_by_alias(alias)
            .ok_or_else(|| ErrorKind::UnknownSource(alias.to_owned()))?;
        if !source.is_available_locally(self) {
            source.clone_source(runner, self)?;
        } else {
            println!("'{}' is already available locally", source.alias());
        }
        Ok(())
    }

    fn source_set_mounted<CR>(&mut self,
                              runner: &CR,
                              alias: &str,
                              mounted: bool)
                              -> Result<()>
        where CR: CommandRunner
    {
        {
            // Look up the source mutably.  We do this in a block so we can
            // drop the mutable borrow before continuing and keep Rust
            // happy.
            let source = self.sources_mut()
                .find_by_alias_mut(alias)
                .ok_or_else(|| ErrorKind::UnknownSource(alias.to_owned()))?;

            // Set the mounted flag on our source.
            source.set_mounted(mounted);
        }

        // Write our persistent project settings back to disk.
        self.save_settings()?;

        // Clone the source if we're mounting it but don't have a local
        // copy yet.
        let source = self.sources()
            .find_by_alias(alias)
            .ok_or_else(|| ErrorKind::UnknownSource(alias.to_owned()))?;
        if source.mounted() && !source.is_available_locally(self) {
            self.source_clone(runner, alias)?;
        }

        // Notify the user that they need to run `up`.
        println!("Now run `cage up` for these changes to take effect.");

        Ok(())
    }
}

// No tests because this is a very thin wrapper over `Sources` and `Source`.
<commit_msg>Don't fail if we can't strip a path prefix<commit_after>//! The `source` subcommand.

use colored::*;

use command_runner::CommandRunner;
use errors::*;
use project::Project;

/// We implement `source` with a trait so we put it in its own module.
pub trait CommandSource {
    /// List all the source trees associated with a project.
    fn source_list<CR>(&self, runner: &CR) -> Result<()> where CR: CommandRunner;

    /// Clone the specified source tree.
    fn source_clone<CR>(&self, runner: &CR, alias: &str) -> Result<()>
        where CR: CommandRunner;

    /// Set the `mounted` flag on the specified source tree.
    fn source_set_mounted<CR>(&mut self,
                              runner: &CR,
                              alias: &str,
                              mounted: bool)
                              -> Result<()>
        where CR: CommandRunner;
}

impl CommandSource for Project {
    fn source_list<CR>(&self, _runner: &CR) -> Result<()>
        where CR: CommandRunner
    {
        for source in self.sources().iter() {
            println!("{:25} {}", source.alias().green(), source.context());
            if source.is_available_locally(self) {
                let canonical = source.path(self).canonicalize()?;
                // Try to strip the prefix, but this may fail on Windows
                // or if the source is in a weird location.
                let path = match canonical.strip_prefix(self.root_dir()) {
                    Ok(stripped) => stripped.to_owned(),
                    Err(_) => canonical.to_owned(),
                };
                let mounted = if source.mounted() {
                    "(mounted)".normal()
                } else {
                    "(NOT MOUNTED)".red().bold()
                };
                println!("  Available at {} {}", path.display(), mounted);
            }
        }
        Ok(())
    }

    fn source_clone<CR>(&self, runner: &CR, alias: &str) -> Result<()>
        where CR: CommandRunner
    {
        let source = self.sources()
            .find_by_alias(alias)
            .ok_or_else(|| ErrorKind::UnknownSource(alias.to_owned()))?;
        if !source.is_available_locally(self) {
            source.clone_source(runner, self)?;
        } else {
            println!("'{}' is already available locally", source.alias());
        }
        Ok(())
    }

    fn source_set_mounted<CR>(&mut self,
                              runner: &CR,
                              alias: &str,
                              mounted: bool)
                              -> Result<()>
        where CR: CommandRunner
    {
        {
            // Look up the source mutably.  We do this in a block so we can
            // drop the mutable borrow before continuing and keep Rust
            // happy.
            let source = self.sources_mut()
                .find_by_alias_mut(alias)
                .ok_or_else(|| ErrorKind::UnknownSource(alias.to_owned()))?;

            // Set the mounted flag on our source.
            source.set_mounted(mounted);
        }

        // Write our persistent project settings back to disk.
        self.save_settings()?;

        // Clone the source if we're mounting it but don't have a local
        // copy yet.
        let source = self.sources()
            .find_by_alias(alias)
            .ok_or_else(|| ErrorKind::UnknownSource(alias.to_owned()))?;
        if source.mounted() && !source.is_available_locally(self) {
            self.source_clone(runner, alias)?;
        }

        // Notify the user that they need to run `up`.
        println!("Now run `cage up` for these changes to take effect.");

        Ok(())
    }
}

// No tests because this is a very thin wrapper over `Sources` and `Source`.
<|endoftext|>


<commit_before>//! Collection module for managing Algorithmia Data Collections
//!
//! # Examples
//!
//! ```no_run
//! use algorithmia::Service;
//! use std::fs::File;
//!
//! let algo_service = Service::new("111112222233333444445555566");
//! let my_bucket = algo_service.collection("my_user", "my_bucket");
//!
//! my_bucket.create();
//! let mut my_file = File::open("/path/to/file").unwrap();
//! my_bucket.upload_file(&mut my_file);
//!
//! my_bucket.write_file("some_filename", "file_contents".as_bytes());
//! ```

extern crate hyper;

use ::{Service, AlgorithmiaError, ApiErrorResponse, API_BASE_URL};
use hyper::Url;
use rustc_serialize::{json, Decoder};
use std::io::Read;
use std::fs::File;

static COLLECTION_BASE_PATH: &'static str = "data";

/// Algorithmia data collection
pub struct Collection<'a> {
    pub user: &'a str,
    pub name: &'a str,
}

pub type CollectionShowResult = Result<CollectionShow, AlgorithmiaError>;
pub type CollectionCreatedResult = Result<CollectionCreated, AlgorithmiaError>;
pub type CollectionFileAddedResult = Result<CollectionFileAdded, AlgorithmiaError>;

/// Permissions for a data collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionAcl {
    /// Readable by world
    pub read_w: bool,
    /// Readable by group
    pub read_g: bool,
    /// Readable by user
    pub read_u: bool,
    /// Readable by user's algorithms regardless who runs them
    pub read_a: bool,
}

/// Response when creating a new collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionCreated {
    pub collection_id: u32,
    pub object_id: String,
    pub collection_name: String,
    pub username: String,
    pub acl: CollectionAcl,
}

/// Response when querying an existing collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionShow {
    pub username: String,
    pub collection_name: String,
    pub files: Vec<String>,
}

/// Response when adding a file to a collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionFileAdded {
    pub result: String
}

/// Service endpoint for managing Algorithmia data collections
pub struct CollectionService<'a> {
    pub service: Service,
    pub collection: Collection<'a>,
}

impl<'a> Collection<'a> {
    /// Get the API Endpoint URL for a particular collection
    fn to_url(&self) -> Url {
        let url_string = format!("{}/{}/{}/{}", API_BASE_URL, COLLECTION_BASE_PATH, self.user, self.name);
        Url::parse(&*url_string).unwrap()
    }
}

impl<'c> CollectionService<'c> {
    /// Instantiate `CollectionService` directly - alternative to `Service::collection`
    ///
    /// # Examples
    /// ```
    /// # use algorithmia::collection::CollectionService;
    /// let my_bucket = CollectionService::new("111112222233333444445555566", "my_user", "my_bucket");
    /// ```
    pub fn new(api_key: &'c str, user: &'c str, name: &'c str) -> CollectionService<'c> {
        CollectionService {
            service: Service::new(api_key),
            collection: Collection{ user: user, name: name }
        }
    }

    /// Display collection details if it exists
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// let algo_service = Service::new("111112222233333444445555566");
    /// let my_bucket = algo_service.collection("my_user", "my_bucket");
    /// match my_bucket.show() {
    ///   Ok(bucket) => println!("Files: {}", bucket.files.connect(", ")),
    ///   Err(e) => println!("ERROR: {:?}", e),
    /// };
    /// ```
    pub fn show(&'c self) -> CollectionShowResult {
        let ref mut api_client = self.service.api_client();
        let req = api_client.get(self.collection.to_url());

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        match json::decode::<CollectionShow>(&*res_json) {
            Ok(result) => Ok(result),
            Err(why) => match json::decode::<ApiErrorResponse>(&*res_json) {
                Ok(api_error) => Err(AlgorithmiaError::ApiError(api_error.error)),
                Err(_) => Err(AlgorithmiaError::DecoderErrorWithContext(why, res_json)),
            }
        }
    }

    /// Create a collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// let algo_service = Service::new("111112222233333444445555566");
    /// let my_bucket = algo_service.collection("my_user", "my_bucket");
    /// match my_bucket.create() {
    ///   Ok(_) => println!("Successfully created collection"),
    ///   Err(e) => println!("ERROR creating collection: {:?}", e),
    /// };
    /// ```
    pub fn create(&'c self) -> CollectionCreatedResult {
        // Construct URL
        let url_string = format!("{}/{}/{}", API_BASE_URL, COLLECTION_BASE_PATH, self.collection.user);
        let url = Url::parse(&*url_string).unwrap();

        // POST request
        let ref mut api_client = self.service.api_client();
        let req = api_client.post(url).body(self.collection.name);

        // Parse response
        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionCreated>(res_json)

    }

    /// Upload a file to an existing collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// # use std::fs::File;
    /// let algo_service = Service::new("111112222233333444445555566");
    /// let my_bucket = algo_service.collection("my_user", "my_bucket");
    ///
    /// let mut my_file = File::open("/path/to/file").unwrap();
    /// match my_bucket.upload_file(&mut my_file) {
    ///   Ok(response) => println!("Successfully uploaded to: {}", response.result),
    ///   Err(e) => println!("ERROR uploading file: {:?}", e),
    /// };
    /// ```
    pub fn upload_file(&'c self, file: &mut File) -> CollectionFileAddedResult {
        let url_string = format!("{}/{}",
            self.collection.to_url(),
            file.path().unwrap().file_name().unwrap().to_str().unwrap()
        );
        let url = Url::parse(&*url_string).unwrap();

        let ref mut api_client = self.service.api_client();
        let req = api_client.post(url).body(file);

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionFileAdded>(res_json)
    }

    /// Write a file (raw bytes) directly to a data collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// let algo_service = Service::new("111112222233333444445555566");
    /// let my_bucket = algo_service.collection("my_user", "my_bucket");
    ///
    /// match my_bucket.write_file("some_filename", "file_contents".as_bytes()) {
    ///   Ok(response) => println!("Successfully uploaded to: {}", response.result),
    ///   Err(e) => println!("ERROR uploading file: {:?}", e),
    /// };
    /// ```
    pub fn write_file(&'c self, filename: &str, input_data: &[u8]) -> CollectionFileAddedResult {
        let url_string = format!("{}/{}", self.collection.to_url(), filename);
        let url = Url::parse(&*url_string).unwrap();

        let ref mut api_client = self.service.api_client();
        let req = api_client.post(url).body(&*input_data);

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionFileAdded>(res_json)
    }

}

#[test]
fn test_to_url() {
    let collection = Collection{ user: "anowell", name: "foo" };
    assert_eq!(collection.to_url().serialize(), format!("{}/data/anowell/foo", API_BASE_URL));
}
<commit_msg>Adding collection methods (not building)<commit_after>//! Collection module for managing Algorithmia Data Collections
//!
//! # Examples
//!
//! ```no_run
//! use algorithmia::Service;
//! use std::fs::File;
//!
//! let algo_service = Service::new("111112222233333444445555566");
//! let my_bucket = algo_service.collection("my_user", "my_bucket");
//!
//! my_bucket.create();
//! let mut my_file = File::open("/path/to/file").unwrap();
//! my_bucket.upload_file(&mut my_file);
//!
//! my_bucket.write_file("some_filename", "file_contents".as_bytes());
//! ```

extern crate hyper;

use ::{Service, AlgorithmiaError, ApiErrorResponse, API_BASE_URL};
use hyper::Url;
use rustc_serialize::{json, Decoder};
use std::io::Read;
use std::fs::File;

static COLLECTION_BASE_PATH: &'static str = "data";

/// Algorithmia data collection
pub struct Collection<'a> {
    pub user: &'a str,
    pub name: &'a str,
}

pub type CollectionShowResult = Result<CollectionShow, AlgorithmiaError>;
pub type CollectionCreatedResult = Result<CollectionCreated, AlgorithmiaError>;
pub type CollectionFileAddedResult = Result<CollectionFileAdded, AlgorithmiaError>;

/// Permissions for a data collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionAcl {
    /// Readable by world
    pub read_w: bool,
    /// Readable by group
    pub read_g: bool,
    /// Readable by user
    pub read_u: bool,
    /// Readable by user's algorithms regardless who runs them
    pub read_a: bool,
}

/// Response when creating a new collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionCreated {
    pub collection_id: u32,
    pub object_id: String,
    pub collection_name: String,
    pub username: String,
    pub acl: CollectionAcl,
}

/// Response when querying an existing collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionShow {
    pub username: String,
    pub collection_name: String,
    pub files: Vec<String>,
}

/// Response when adding a file to a collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionFileAdded {
    pub result: String
}

/// Service endpoint for managing Algorithmia data collections
pub struct CollectionService<'a> {
    pub service: Service,
    pub collection: Collection<'a>,
}

impl<'a> Collection<'a> {
    /// Get the API Endpoint URL for a particular collection
    fn to_url(&self) -> Url {
        let url_string = format!("{}/{}/{}/{}", API_BASE_URL, COLLECTION_BASE_PATH, self.user, self.name);
        Url::parse(&*url_string).unwrap()
    }
}

impl<'c> CollectionService<'c> {
    /// Instantiate `CollectionService` directly - alternative to `Service::collection`
    ///
    /// # Examples
    /// ```
    /// # use algorithmia::collection::CollectionService;
    /// let my_bucket = CollectionService::new("111112222233333444445555566", "my_user", "my_bucket");
    /// ```
    pub fn new(api_key: &'c str, user: &'c str, name: &'c str) -> CollectionService<'c> {
        CollectionService {
            service: Service::new(api_key),
            collection: Collection{ user: user, name: name }
        }
    }

    /// Display collection details if it exists
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// let algo_service = Service::new("111112222233333444445555566");
    /// let my_bucket = algo_service.collection("my_user", "my_bucket");
    /// match my_bucket.show() {
    ///   Ok(bucket) => println!("Files: {}", bucket.files.connect(", ")),
    ///   Err(e) => println!("ERROR: {:?}", e),
    /// };
    /// ```
    pub fn show(&'c self) -> CollectionShowResult {
        let ref mut api_client = self.service.api_client();
        let req = api_client.get(self.collection.to_url());

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        match json::decode::<CollectionShow>(&*res_json) {
            Ok(result) => Ok(result),
            Err(why) => match json::decode::<ApiErrorResponse>(&*res_json) {
                Ok(api_error) => Err(AlgorithmiaError::ApiError(api_error.error)),
                Err(_) => Err(AlgorithmiaError::DecoderErrorWithContext(why, res_json)),
            }
        }
    }

    /// Create a collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// let algo_service = Service::new("111112222233333444445555566");
    /// let my_bucket = algo_service.collection("my_user", "my_bucket");
    /// match my_bucket.create() {
    ///   Ok(_) => println!("Successfully created collection"),
    ///   Err(e) => println!("ERROR creating collection: {:?}", e),
    /// };
    /// ```
    pub fn create(&'c self) -> CollectionCreatedResult {
        // Construct URL
        let url_string = format!("{}/{}/{}", API_BASE_URL, COLLECTION_BASE_PATH, self.collection.user);
        let url = Url::parse(&*url_string).unwrap();

        // POST request
        let ref mut api_client = self.service.api_client();
        let req = api_client.post(url).body(self.collection.name);

        // Parse response
        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionCreated>(res_json)
    }

    /// Delete a collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// let algo_service = Service::new("111112222233333444445555566");
    /// let my_bucket = algo_service.collection("my_user", "my_bucket");
    /// match my_bucket.delete() {
    ///   Ok(_) => println!("Successfully deleted collection"),
    ///   Err(e) => println!("ERROR deleting collection: {:?}", e),
    /// };
    /// ```
    pub fn delete(&'c self) -> CollectionDeletedResult {
        // DELETE request
        let ref mut api_client = self.service.api_client();
        let req = api_client.delete(self.collection.to_url());

        // Parse response
        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionDeleted>(res_json)
    }

    /// Upload a file to an existing collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// # use std::fs::File;
    /// let algo_service = Service::new("111112222233333444445555566");
    /// let my_bucket = algo_service.collection("my_user", "my_bucket");
    ///
    /// let mut my_file = File::open("/path/to/file").unwrap();
    /// match my_bucket.upload_file(&mut my_file) {
    ///   Ok(response) => println!("Successfully uploaded to: {}", response.result),
    ///   Err(e) => println!("ERROR uploading file: {:?}", e),
    /// };
    /// ```
    pub fn upload_file(&'c self, file: &mut File) -> CollectionFileAddedResult {
        let url_string = format!("{}/{}",
            self.collection.to_url(),
            file.path().unwrap().file_name().unwrap().to_str().unwrap()
        );
        let url = Url::parse(&*url_string).unwrap();

        let ref mut api_client = self.service.api_client();
        let req = api_client.post(url).body(file);

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionFileAdded>(res_json)
    }

    /// Write a file (raw bytes) directly to a data collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// let algo_service = Service::new("111112222233333444445555566");
    /// let my_bucket = algo_service.collection("my_user", "my_bucket");
    ///
    /// match my_bucket.write_file("some_filename", "file_contents".as_bytes()) {
    ///   Ok(response) => println!("Successfully uploaded to: {}", response.result),
    ///   Err(e) => println!("ERROR uploading file: {:?}", e),
    /// };
    /// ```
    pub fn write_file(&'c self, filename: &str, input_data: &[u8]) -> CollectionFileAddedResult {
        let url_string = format!("{}/{}", self.collection.to_url(), filename);
        let url = Url::parse(&*url_string).unwrap();

        let ref mut api_client = self.service.api_client();
        let req = api_client.post(url).body(&*input_data);

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionFileAdded>(res_json)
    }

    /// Delete a file from a data collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// let algo_service = Service::new("111112222233333444445555566");
    /// let my_bucket = algo_service.collection("my_user", "my_bucket");
    ///
    /// match my_bucket.delete_file("some_filename") {
    ///   Ok(_) => println!("Successfully deleted file"),
    ///   Err(e) => println!("ERROR deleting file: {:?}", e),
    /// };
    /// ```
    pub fn delete_file(&'c self, filename: &str) -> CollectionFileDeletedResult {
        let url_string = format!("{}/{}", self.collection.to_url(), filename);
        let url = Url::parse(&*url_string).unwrap();

        let ref mut api_client = self.service.api_client();
        let req = api_client.delete(url);

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionFileDeleted>(res_json)
    }

}

#[test]
fn test_to_url() {
    let collection = Collection{ user: "anowell", name: "foo" };
    assert_eq!(collection.to_url().serialize(), format!("{}/data/anowell/foo", API_BASE_URL));
}
<|endoftext|>


<commit_before>//! Types for the *m.ignored_user_list* event.

use ruma_events_macros::BasicEventContent;
use ruma_identifiers::UserId;
use serde::{Deserialize, Serialize};

use crate::BasicEvent;

/// A list of users to ignore.
pub type IgnoredUserListEvent = BasicEvent<IgnoredUserListEventContent>;

/// The payload for `IgnoredUserListEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, BasicEventContent)]
#[ruma_event(type = "m.ignored_user_list")]
pub struct IgnoredUserListEventContent {
    /// A list of users to ignore.
    #[serde(with = "ruma_serde::vec_as_map_of_empty")]
    pub ignored_users: Vec<UserId>,
}

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    use ruma_identifiers::user_id;
    use ruma_serde::Raw;
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::IgnoredUserListEventContent;
    use crate::{AnyBasicEventContent, BasicEvent};

    #[test]
    fn serialization() {
        let ignored_user_list_event = BasicEvent {
            content: IgnoredUserListEventContent {
                ignored_users: vec![user_id!("@carl:example.com")],
            },
        };

        let json = json!({
            "content": {
                "ignored_users": {
                    "@carl:example.com": {}
                }
            },
            "type": "m.ignored_user_list"
        });

        assert_eq!(to_json_value(ignored_user_list_event).unwrap(), json);
    }

    #[test]
    fn deserialization() {
        let json = json!({
            "content": {
                "ignored_users": {
                    "@carl:example.com": {}
                }
            },
            "type": "m.ignored_user_list"
        });

        assert_matches!(
            from_json_value::<Raw<BasicEvent<AnyBasicEventContent>>>(json)
                .unwrap()
                .deserialize()
                .unwrap(),
            BasicEvent {
                content: AnyBasicEventContent::IgnoredUserList(IgnoredUserListEventContent {
                    ignored_users,
                }),
            } if ignored_users == vec![user_id!("@carl:example.com")]
        );
    }
}
<commit_msg>events: Make IgnoredUserListEventContent non-exhaustive<commit_after>//! Types for the *m.ignored_user_list* event.

use ruma_events_macros::BasicEventContent;
use ruma_identifiers::UserId;
use serde::{Deserialize, Serialize};

use crate::BasicEvent;

/// A list of users to ignore.
pub type IgnoredUserListEvent = BasicEvent<IgnoredUserListEventContent>;

/// The payload for `IgnoredUserListEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, BasicEventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.ignored_user_list")]
pub struct IgnoredUserListEventContent {
    /// A list of users to ignore.
    #[serde(with = "ruma_serde::vec_as_map_of_empty")]
    pub ignored_users: Vec<UserId>,
}

impl IgnoredUserListEventContent {
    /// Creates a new `IgnoredUserListEventContent` from the given user IDs.
    pub fn new(ignored_users: Vec<UserId>) -> Self {
        Self { ignored_users }
    }
}

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    use ruma_identifiers::user_id;
    use ruma_serde::Raw;
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::IgnoredUserListEventContent;
    use crate::{AnyBasicEventContent, BasicEvent};

    #[test]
    fn serialization() {
        let ignored_user_list_event = BasicEvent {
            content: IgnoredUserListEventContent {
                ignored_users: vec![user_id!("@carl:example.com")],
            },
        };

        let json = json!({
            "content": {
                "ignored_users": {
                    "@carl:example.com": {}
                }
            },
            "type": "m.ignored_user_list"
        });

        assert_eq!(to_json_value(ignored_user_list_event).unwrap(), json);
    }

    #[test]
    fn deserialization() {
        let json = json!({
            "content": {
                "ignored_users": {
                    "@carl:example.com": {}
                }
            },
            "type": "m.ignored_user_list"
        });

        assert_matches!(
            from_json_value::<Raw<BasicEvent<AnyBasicEventContent>>>(json)
                .unwrap()
                .deserialize()
                .unwrap(),
            BasicEvent {
                content: AnyBasicEventContent::IgnoredUserList(IgnoredUserListEventContent {
                    ignored_users,
                }),
            } if ignored_users == vec![user_id!("@carl:example.com")]
        );
    }
}
<|endoftext|>


<commit_before>use crate::common::BinarySerializable;
use std::io;
use std::io::Read;
use std::io::Write;

/// `Field` is actually a `u8` identifying a `Field`
/// The schema is in charge of holding mapping between field names
/// to `Field` objects.
///
/// Because the field id is a `u8`, tantivy can only have at most `255` fields.
/// Value 255 is reserved.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
pub struct Field(pub u32);

impl BinarySerializable for Field {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        self.0.serialize(writer)
    }

    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Field> {
        u32::deserialize(reader).map(Field)
    }
}
<commit_msg>Fixed #664 (#667)<commit_after>use crate::common::BinarySerializable;
use std::io;
use std::io::Read;
use std::io::Write;

/// `Field` is represented by an unsigned 32-bit integer type
/// The schema holds the mapping between field names and `Field` objects.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
pub struct Field(pub u32);

impl BinarySerializable for Field {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        self.0.serialize(writer)
    }

    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Field> {
        u32::deserialize(reader).map(Field)
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Keeping track of available plugins.

use std::collections::HashMap;
use std::fs;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
use std::sync::Arc;

use toml;

use super::{PluginDescription, PluginName};
use crate::config::table_from_toml_str;
use crate::syntax::Languages;

/// A catalog of all available plugins.
#[derive(Debug, Clone, Default)]
pub struct PluginCatalog {
    items: HashMap<PluginName, Arc<PluginDescription>>,
    locations: HashMap<PathBuf, Arc<PluginDescription>>,
}

/// Errors that can occur while trying to load a plugin.
#[derive(Debug)]
pub enum PluginLoadError {
    Io(io::Error),
    /// Malformed manifest
    Parse(toml::de::Error),
}

#[allow(dead_code)]
impl<'a> PluginCatalog {
    /// Loads any plugins discovered in these paths, replacing any existing
    /// plugins.
    pub fn reload_from_paths(&mut self, paths: &[PathBuf]) {
        self.items.clear();
        self.locations.clear();
        self.load_from_paths(paths);
    }

    /// Loads plugins from paths and adds them to existing plugins.
    pub fn load_from_paths(&mut self, paths: &[PathBuf]) {
        let all_manifests = find_all_manifests(paths);
        for manifest_path in &all_manifests {
            match load_manifest(manifest_path) {
                Err(e) => warn!("error loading plugin {:?}", e),
                Ok(manifest) => {
                    info!("loaded {}", manifest.name);
                    let manifest = Arc::new(manifest);
                    self.items.insert(manifest.name.clone(), manifest.clone());
                    self.locations.insert(manifest_path.clone(), manifest);
                }
            }
        }
    }

    pub fn make_languages_map(&self) -> Languages {
        let all_langs =
            self.items.values().flat_map(|plug| plug.languages.iter().cloned()).collect::<Vec<_>>();
        Languages::new(all_langs.as_slice())
    }

    /// Returns an iterator over all plugins in the catalog, in arbitrary order.
    pub fn iter(&'a self) -> impl Iterator<Item = Arc<PluginDescription>> + 'a {
        self.items.values().cloned()
    }

    /// Returns an iterator over all plugin names in the catalog,
    /// in arbitrary order.
    pub fn iter_names(&'a self) -> impl Iterator<Item = &'a PluginName> {
        self.items.keys()
    }

    /// Returns the plugin located at the provided file path.
    #[allow(clippy::map_clone)]
    pub fn get_from_path(&self, path: &PathBuf) -> Option<Arc<PluginDescription>> {
        self.items
            .values()
            .find(|&v| v.exec_path.to_str().unwrap().contains(path.to_str().unwrap()))
            .map(|plugin| plugin.clone())
    }

    /// Returns a reference to the named plugin if it exists in the catalog.
    pub fn get_named(&self, plugin_name: &str) -> Option<Arc<PluginDescription>> {
        self.items.get(plugin_name).map(Arc::clone)
    }

    /// Removes the named plugin.
    pub fn remove_named(&mut self, plugin_name: &str) {
        self.items.remove(plugin_name);
    }
}

fn find_all_manifests(paths: &[PathBuf]) -> Vec<PathBuf> {
    let mut manifest_paths = Vec::new();
    for path in paths.iter() {
        let manif_path = path.join("manifest.toml");
        if manif_path.exists() {
            manifest_paths.push(manif_path);
            continue;
        }

        let result = path.read_dir().map(|dir| {
            dir.flat_map(|item| item.map(|p| p.path()).ok())
                .map(|dir| dir.join("manifest.toml"))
                .filter(|f| f.exists())
                .for_each(|f| manifest_paths.push(f.to_owned()))
        });
        if let Err(e) = result {
            error!("error reading plugin path {:?}, {:?}", path, e);
        }
    }
    manifest_paths
}

fn load_manifest(path: &Path) -> Result<PluginDescription, PluginLoadError> {
    let mut file = fs::File::open(&path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    let mut manifest: PluginDescription = toml::from_str(&contents)?;
    // normalize relative paths
    if manifest.exec_path.starts_with("./") {
        manifest.exec_path = path.parent().unwrap().join(manifest.exec_path).canonicalize()?;
    }

    for lang in &mut manifest.languages {
        let lang_config_path =
            path.parent().unwrap().join(&lang.name.as_ref()).with_extension("toml");
        if !lang_config_path.exists() {
            continue;
        }
        let lang_defaults = fs::read_to_string(&lang_config_path)?;
        let lang_defaults = table_from_toml_str(&lang_defaults)?;
        lang.default_config = Some(lang_defaults);
    }
    Ok(manifest)
}

impl From<io::Error> for PluginLoadError {
    fn from(err: io::Error) -> PluginLoadError {
        PluginLoadError::Io(err)
    }
}

impl From<toml::de::Error> for PluginLoadError {
    fn from(err: toml::de::Error) -> PluginLoadError {
        PluginLoadError::Parse(err)
    }
}
<commit_msg>Use cloned() instead of map() and clone()<commit_after>// Copyright 2017 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Keeping track of available plugins.

use std::collections::HashMap;
use std::fs;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
use std::sync::Arc;

use toml;

use super::{PluginDescription, PluginName};
use crate::config::table_from_toml_str;
use crate::syntax::Languages;

/// A catalog of all available plugins.
#[derive(Debug, Clone, Default)]
pub struct PluginCatalog {
    items: HashMap<PluginName, Arc<PluginDescription>>,
    locations: HashMap<PathBuf, Arc<PluginDescription>>,
}

/// Errors that can occur while trying to load a plugin.
#[derive(Debug)]
pub enum PluginLoadError {
    Io(io::Error),
    /// Malformed manifest
    Parse(toml::de::Error),
}

#[allow(dead_code)]
impl<'a> PluginCatalog {
    /// Loads any plugins discovered in these paths, replacing any existing
    /// plugins.
    pub fn reload_from_paths(&mut self, paths: &[PathBuf]) {
        self.items.clear();
        self.locations.clear();
        self.load_from_paths(paths);
    }

    /// Loads plugins from paths and adds them to existing plugins.
    pub fn load_from_paths(&mut self, paths: &[PathBuf]) {
        let all_manifests = find_all_manifests(paths);
        for manifest_path in &all_manifests {
            match load_manifest(manifest_path) {
                Err(e) => warn!("error loading plugin {:?}", e),
                Ok(manifest) => {
                    info!("loaded {}", manifest.name);
                    let manifest = Arc::new(manifest);
                    self.items.insert(manifest.name.clone(), manifest.clone());
                    self.locations.insert(manifest_path.clone(), manifest);
                }
            }
        }
    }

    pub fn make_languages_map(&self) -> Languages {
        let all_langs =
            self.items.values().flat_map(|plug| plug.languages.iter().cloned()).collect::<Vec<_>>();
        Languages::new(all_langs.as_slice())
    }

    /// Returns an iterator over all plugins in the catalog, in arbitrary order.
    pub fn iter(&'a self) -> impl Iterator<Item = Arc<PluginDescription>> + 'a {
        self.items.values().cloned()
    }

    /// Returns an iterator over all plugin names in the catalog,
    /// in arbitrary order.
    pub fn iter_names(&'a self) -> impl Iterator<Item = &'a PluginName> {
        self.items.keys()
    }

    /// Returns the plugin located at the provided file path.
    pub fn get_from_path(&self, path: &PathBuf) -> Option<Arc<PluginDescription>> {
        self.items
            .values()
            .find(|&v| v.exec_path.to_str().unwrap().contains(path.to_str().unwrap()))
            .cloned()
    }

    /// Returns a reference to the named plugin if it exists in the catalog.
    pub fn get_named(&self, plugin_name: &str) -> Option<Arc<PluginDescription>> {
        self.items.get(plugin_name).map(Arc::clone)
    }

    /// Removes the named plugin.
    pub fn remove_named(&mut self, plugin_name: &str) {
        self.items.remove(plugin_name);
    }
}

fn find_all_manifests(paths: &[PathBuf]) -> Vec<PathBuf> {
    let mut manifest_paths = Vec::new();
    for path in paths.iter() {
        let manif_path = path.join("manifest.toml");
        if manif_path.exists() {
            manifest_paths.push(manif_path);
            continue;
        }

        let result = path.read_dir().map(|dir| {
            dir.flat_map(|item| item.map(|p| p.path()).ok())
                .map(|dir| dir.join("manifest.toml"))
                .filter(|f| f.exists())
                .for_each(|f| manifest_paths.push(f.to_owned()))
        });
        if let Err(e) = result {
            error!("error reading plugin path {:?}, {:?}", path, e);
        }
    }
    manifest_paths
}

fn load_manifest(path: &Path) -> Result<PluginDescription, PluginLoadError> {
    let mut file = fs::File::open(&path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    let mut manifest: PluginDescription = toml::from_str(&contents)?;
    // normalize relative paths
    if manifest.exec_path.starts_with("./") {
        manifest.exec_path = path.parent().unwrap().join(manifest.exec_path).canonicalize()?;
    }

    for lang in &mut manifest.languages {
        let lang_config_path =
            path.parent().unwrap().join(&lang.name.as_ref()).with_extension("toml");
        if !lang_config_path.exists() {
            continue;
        }
        let lang_defaults = fs::read_to_string(&lang_config_path)?;
        let lang_defaults = table_from_toml_str(&lang_defaults)?;
        lang.default_config = Some(lang_defaults);
    }
    Ok(manifest)
}

impl From<io::Error> for PluginLoadError {
    fn from(err: io::Error) -> PluginLoadError {
        PluginLoadError::Io(err)
    }
}

impl From<toml::de::Error> for PluginLoadError {
    fn from(err: toml::de::Error) -> PluginLoadError {
        PluginLoadError::Parse(err)
    }
}
<|endoftext|>


<commit_before>use crate::core::{trait_aliases::Id, Directed, Directedness, Edge};
use std::iter::Iterator;

#[macro_use]
mod macros
{
	#[macro_export]
	macro_rules! edges_between {
		($e:expr, $v1:expr, $v2:expr) => {{
			// Filter out any edge that is not connected to both vertices
			let relevant = $e.filter(move |edge| {
				(edge.source() == $v1 && edge.sink() == $v2)
					|| (edge.source() == $v2 && edge.sink() == $v1)
			});

			// Return the result
			Box::new(relevant)
			}};
	}
	#[macro_export]
	macro_rules! edges_incident_on {
		($e:expr, $v:expr, $i:ident) => {
			Box::new($e.into_iter().filter(move |e| e.$i() == $v))
		};
		($e:expr, $v:expr) => {
			Box::new(
				$e.into_iter()
					.filter(move |edge| (edge.source() == $v) || (edge.sink() == $v)),
				)
		};
	}
}

/// The basic graph interface. This is the main trait for all types of graphs.
///
/// For all graphs, vertices are identified by their
/// [value](#associatedType.Vertex), and must be unique in the graph. Edges are
/// identified by the two vertices they are incident on, the direction,
/// and their [Id](#associatedType.EdgeId); I.e. the triple `(v1,v2,e)` is an
/// edge from `v1` to `v2` with an edge id `e`. All edges are directed but need
/// not be unique. Therefore, multiple edges with the same source (`v1`), sink
/// (`v2`), and id (`e`) may be present in a graph at the same time. Edges with
/// the same source, sink, and id are identical and must be interchangeable.
/// E.g. if any one of two or more identical edges is to be removed, then any
/// one of them may be removed.
///
/// TODO: When Rust supports 'impl trait' consider having some of the iterators
/// be clone too (those that don't include mutable references). This allows
/// cloning the iterators mid-iteration, which can be useful when comparing each
/// item to the ones after it.
pub trait Graph
{
	/// Type of the graph's vertex value.
	type Vertex: Id;
	type VertexWeight;
	type EdgeWeight;
	type Directedness: Directedness;

	/// Returns copies of all current vertex values in the graph.
	fn all_vertices_weighted<'a>(
		&'a self,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, &'a Self::VertexWeight)>>;
	/// Returns copies of all current edges in the graph.
	fn all_edges<'a>(
		&'a self,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a Self::EdgeWeight)>>;

	// Optional methods

	fn all_vertices<'a>(&'a self) -> Box<dyn 'a + Iterator<Item = Self::Vertex>>
	{
		Box::new(self.all_vertices_weighted().map(|(v, _)| v))
	}
	fn vertex_weight(&self, v: Self::Vertex) -> Option<&Self::VertexWeight>
	{
		self.all_vertices_weighted()
			.find(|&(candidate, _)| candidate == v)
			.map(|(_, w)| w)
	}
	fn contains_vertex(&self, v: Self::Vertex) -> bool
	{
		self.vertex_weight(v).is_some()
	}
	fn all_vertex_weights<'a>(&'a self) -> Box<dyn 'a + Iterator<Item = &'a Self::VertexWeight>>
	{
		Box::new(self.all_vertices_weighted().map(|(_, w)| w))
	}

	/// Returns all edges that are incident on both of the given vertices,
	/// regardless of direction.
	///
	/// I.e. all edges where e == (v1,v2,_) or e == (v2,v1,_)
	fn edges_between<'a>(
		&'a self,
		v1: Self::Vertex,
		v2: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a Self::EdgeWeight)>>
	{
		edges_between!(self.all_edges(), v1, v2)
	}
	/// Returns all edges that are sourced in the given vertex.
	///
	/// I.e. all edges where `e == (v,_,_)`
	///
	/// Only available for directed graphs
	fn edges_sourced_in<'a>(
		&'a self,
		v: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a Self::EdgeWeight)>>
	where
		Self: Graph<Directedness = Directed>,
	{
		edges_incident_on!(self.all_edges(), v, source)
	}
	/// Returns all edges that are sinked in the given vertex.
	///
	/// I.e. all edges where `e == (_,v,_)`
	fn edges_sinked_in<'a>(
		&'a self,
		v: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a Self::EdgeWeight)>>
	where
		Self: Graph<Directedness = Directed>,
	{
		edges_incident_on!(self.all_edges(), v, sink)
	}
	fn edges_incident_on<'a>(
		&'a self,
		v: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a Self::EdgeWeight)>>
	{
		edges_incident_on!(self.all_edges(), v)
	}

	fn edge_valid<E>(&self, e: E) -> bool
	where
		E: Edge<Self::Vertex>,
	{
		self.contains_vertex(e.source()) && self.contains_vertex(e.sink())
	}
}

pub trait GraphMut: Graph
{
	fn all_vertices_weighted_mut<'a>(
		&'a mut self,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, &'a mut Self::VertexWeight)>>;

	fn all_edges_mut<'a>(
		&'a mut self,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a mut Self::EdgeWeight)>>;

	// Optional methods

	fn vertex_weight_mut(&mut self, v: Self::Vertex) -> Option<&mut Self::VertexWeight>
	{
		self.all_vertices_weighted_mut()
			.find(|&(candidate, _)| candidate == v)
			.map(|(_, w)| w)
	}

	fn edges_between_mut<'a>(
		&'a mut self,
		v1: Self::Vertex,
		v2: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a mut Self::EdgeWeight)>>
	{
		edges_between!(self.all_edges_mut(), v1, v2)
	}
	fn edges_sourced_in_mut<'a>(
		&'a mut self,
		v: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a mut Self::EdgeWeight)>>
	where
		Self: Graph<Directedness = Directed>,
	{
		edges_incident_on!(self.all_edges_mut(), v, source)
	}
	fn edges_sinked_in_mut<'a>(
		&'a mut self,
		v: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a mut Self::EdgeWeight)>>
	where
		Self: Graph<Directedness = Directed>,
	{
		edges_incident_on!(self.all_edges_mut(), v, sink)
	}
	fn edges_incident_on_mut<'a>(
		&'a mut self,
		v: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a mut Self::EdgeWeight)>>
	{
		edges_incident_on!(self.all_edges_mut(), v)
	}
}
<commit_msg>Documented core::{Graph, GraphMut}<commit_after>use crate::core::{trait_aliases::Id, Directed, Directedness, Edge};
use std::iter::Iterator;

#[macro_use]
mod macros
{
	#[macro_export]
	macro_rules! edges_between {
		($e:expr, $v1:expr, $v2:expr) => {{
			// Filter out any edge that is not connected to both vertices
			let relevant = $e.filter(move |edge| {
				(edge.source() == $v1 && edge.sink() == $v2)
					|| (edge.source() == $v2 && edge.sink() == $v1)
			});

			// Return the result
			Box::new(relevant)
			}};
	}
	#[macro_export]
	macro_rules! edges_incident_on {
		($e:expr, $v:expr, $i:ident) => {
			Box::new($e.into_iter().filter(move |e| e.$i() == $v))
		};
		($e:expr, $v:expr) => {
			Box::new(
				$e.into_iter()
					.filter(move |edge| (edge.source() == $v) || (edge.sink() == $v)),
				)
		};
	}
}

/// The basic graph trait, providing vertex and edge inspection.
///
/// A graphs vertices are identified by the unique value of the associated type
/// [`Vertex`](#associatedtype.Vertex).
/// For example, [`Vertex`] could be `usize`, in which case every vertex is
/// identified by a unique integer value.
/// In addition to its identifier, each vertex has a weight of type
/// [`VertexWeight`]. A vertex's weight can be anything or can be omitted by
/// using `()`.
///
/// Edges are identified primarily by which two vertices they connect. They can
/// also have a weight (of type [`EdgeWeight`]) that can be anything, but may
/// also in some circumstances be used to differentiate between two edges that
/// connect the same vertices. The associated type [`Directedness`] defined
/// whether a graph is directed or undirected. If it is assigned to
/// [`Directed`](struct.Directed.html), we say the graph is directed, meaning
/// the order of vertices in the edge matter. `(v1,v2)` would be an edge
/// "pointing" from `v1` to `v2` but not the other way around, which means
/// `(v2,v1)` will always be seen as a strictly different edge.
/// When [`Directedness`] is assigned to [`Undirected`](struct.Undirected.html)
/// we say the graph is undirected and the order of vertices in an edge is not
/// important. `(v1,v2)` therefore connects `v1` and `v2` and is synonymous with
/// `(v2,v1)`.
///
/// TODO: When Rust supports 'impl trait' consider having some of the iterators
/// be clone too (those that don't include mutable references). This allows
/// cloning the iterators mid-iteration, which can be useful when comparing each
/// item to the ones after it.
///
/// ### Related
///
/// - [`GraphMut`](trait.GraphMut.html):
/// Provides methods for accessing weights through mutable references.
/// - [`NewVertex`](property/trait.NewVertex.html):
/// Provides methods for adding vertices to a graph.
/// - [`RemoveVertex`](property/trait.RemoveVertex.html):
/// Provides methods for removing vertices from a graph.
/// - [`AddEdge`](property/trait.AddEdge.html):
/// Provides methods for adding edges to a graph.
/// - [`RemoveEdge`](property/trait.RemoveEdge.html):
/// Provides methods for removing edges to a graph.
///
/// [`Vertex`]: #associatedtype.Vertex
/// [`VertexWeight`]: #associatedtype.VertexWeight
/// [`EdgeWeight`]: #associatedtype.EdgeWeight
/// [`Directedness`]: #associatedtype.Directedness
pub trait Graph
{
	/// Type of the graphs vertices.
	///
	/// This type should be lightweight, as its passed around by-value
	/// (therefore must implement [`Copy`](https://doc.rust-lang.org/std/marker/trait.Copy.html)).
	/// Whether two vertices are equal is also a very common operation and
	/// should therefore also be light-weight.
	type Vertex: Id;

	/// The weight associated with each vertex.
	///
	/// `()` can be used if no weight is needed.
	type VertexWeight;

	/// The weight associated with each edge.
	///
	/// `()` can be used if no weight is needed.
	type EdgeWeight;

	/// Whether the graph is directed or not.
	///
	/// Only [`Directed`](struct.Directed.html) and
	/// [`Undirected`](struct.Undirected.html)
	/// are valid assignments. Using any other type is undefined behaviour.
	type Directedness: Directedness;

	/// Returns copies of all current vertex values in the graph.
	fn all_vertices_weighted<'a>(
		&'a self,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, &'a Self::VertexWeight)>>;
	/// Returns copies of all current edges in the graph.
	fn all_edges<'a>(
		&'a self,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a Self::EdgeWeight)>>;

	// Optional methods

	fn all_vertices<'a>(&'a self) -> Box<dyn 'a + Iterator<Item = Self::Vertex>>
	{
		Box::new(self.all_vertices_weighted().map(|(v, _)| v))
	}
	fn vertex_weight(&self, v: Self::Vertex) -> Option<&Self::VertexWeight>
	{
		self.all_vertices_weighted()
			.find(|&(candidate, _)| candidate == v)
			.map(|(_, w)| w)
	}
	fn contains_vertex(&self, v: Self::Vertex) -> bool
	{
		self.vertex_weight(v).is_some()
	}
	fn all_vertex_weights<'a>(&'a self) -> Box<dyn 'a + Iterator<Item = &'a Self::VertexWeight>>
	{
		Box::new(self.all_vertices_weighted().map(|(_, w)| w))
	}

	/// Returns all edges that are incident on both of the given vertices,
	/// regardless of direction.
	///
	/// I.e. all edges where e == (v1,v2,_) or e == (v2,v1,_)
	fn edges_between<'a>(
		&'a self,
		v1: Self::Vertex,
		v2: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a Self::EdgeWeight)>>
	{
		edges_between!(self.all_edges(), v1, v2)
	}
	/// Returns all edges that are sourced in the given vertex.
	///
	/// I.e. all edges where `e == (v,_,_)`
	///
	/// Only available for directed graphs
	fn edges_sourced_in<'a>(
		&'a self,
		v: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a Self::EdgeWeight)>>
	where
		Self: Graph<Directedness = Directed>,
	{
		edges_incident_on!(self.all_edges(), v, source)
	}
	/// Returns all edges that are sinked in the given vertex.
	///
	/// I.e. all edges where `e == (_,v,_)`
	fn edges_sinked_in<'a>(
		&'a self,
		v: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a Self::EdgeWeight)>>
	where
		Self: Graph<Directedness = Directed>,
	{
		edges_incident_on!(self.all_edges(), v, sink)
	}
	fn edges_incident_on<'a>(
		&'a self,
		v: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a Self::EdgeWeight)>>
	{
		edges_incident_on!(self.all_edges(), v)
	}

	fn edge_valid<E>(&self, e: E) -> bool
	where
		E: Edge<Self::Vertex>,
	{
		self.contains_vertex(e.source()) && self.contains_vertex(e.sink())
	}
}

/// A graph with mutable vertex and edge weights.
///
/// [`Graph`](trait.Graph.html) provides methods that return references to
/// vertex and edge weight. However, it can't provide mutable references to the.
/// This trait provides mutable variants of [`Graph`](trait.Graph.html)'s
/// methods plus some additional utilities.
pub trait GraphMut: Graph
{
	fn all_vertices_weighted_mut<'a>(
		&'a mut self,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, &'a mut Self::VertexWeight)>>;

	fn all_edges_mut<'a>(
		&'a mut self,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a mut Self::EdgeWeight)>>;

	// Optional methods

	fn vertex_weight_mut(&mut self, v: Self::Vertex) -> Option<&mut Self::VertexWeight>
	{
		self.all_vertices_weighted_mut()
			.find(|&(candidate, _)| candidate == v)
			.map(|(_, w)| w)
	}

	fn edges_between_mut<'a>(
		&'a mut self,
		v1: Self::Vertex,
		v2: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a mut Self::EdgeWeight)>>
	{
		edges_between!(self.all_edges_mut(), v1, v2)
	}
	fn edges_sourced_in_mut<'a>(
		&'a mut self,
		v: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a mut Self::EdgeWeight)>>
	where
		Self: Graph<Directedness = Directed>,
	{
		edges_incident_on!(self.all_edges_mut(), v, source)
	}
	fn edges_sinked_in_mut<'a>(
		&'a mut self,
		v: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a mut Self::EdgeWeight)>>
	where
		Self: Graph<Directedness = Directed>,
	{
		edges_incident_on!(self.all_edges_mut(), v, sink)
	}
	fn edges_incident_on_mut<'a>(
		&'a mut self,
		v: Self::Vertex,
	) -> Box<dyn 'a + Iterator<Item = (Self::Vertex, Self::Vertex, &'a mut Self::EdgeWeight)>>
	{
		edges_incident_on!(self.all_edges_mut(), v)
	}
}
<|endoftext|>


<commit_before>//! Semantic analyzer module.
//!
//! Usually a semantic analyzer checks if everything is in order (variables
//! are in scope, type inference...) before tying to compile the program.
//!
//! The aim with this one, for simplicity, is to walk dependencies (including
//! cyclic ones) to determine in what order they must be written.

use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;

use super::lexer::Token;
use super::parser::{Ast, Parser};

/// Value returned in [`Semantic::analyze`][0] if any errors are found.
///
/// In this analyzer, we only return error if we find any unexpected tokens.
/// Here we store all of them.
///
/// [0]: struct.Semantic.html#method.analyze
pub type UnexpectedTokens = Vec<Token>;

/// The semantic analyzer in our language.
///
/// Given an AST (from a [`Parser`][0]) determines the order in which all
/// definitions must go.
///
/// [0]: ../parser/struct.Parser.html
pub struct Semantic {
    /// All the type definitions. Since we consumed the AST, we have to store
    /// them somewhere.
    pub definitions: HashMap<String, Vec<(String, String)>>,
    /// The order in which to write the definitions.
    pub order: Vec<String>,
    /// If any cyclic dependency is found, all the types involved are stored
    /// here, so they can be handled accordingly.
    pub cycles: HashSet<String>,
}

impl Semantic {
    /// Builds the semantic analyzer and analyzes the AST.
    ///
    /// # Examples
    ///
    /// ```
    /// use simcom::lexer::Lexer;
    /// use simcom::parser::Parser;
    /// use simcom::semantic::Semantic;
    ///
    /// let content = "tipo A(x: X);";
    /// let ast = Parser::new(Lexer::new(content));
    ///
    /// if let Ok(s) = Semantic::analyze(ast) {
    ///     assert_eq!(s.order[0], String::from("X"));
    ///     assert_eq!(s.order[1], String::from("A"));
    /// } else {
    ///     panic!("Wrong if/else branch!");
    /// }
    /// ```
    ///
    /// ```
    /// use simcom::lexer::{Lexer, Token};
    /// use simcom::parser::Parser;
    /// use simcom::semantic::Semantic;
    ///
    /// // Note the two semicolons:
    /// let content = "tipo A(x: X);;";
    /// let s = Semantic::analyze(Parser::new(Lexer::new(content)));
    ///
    /// if let Err(ve) = s {
    ///     assert_eq!(ve[0], Token::Semicolon);
    /// } else {
    ///     panic!("Wrong if/else branch!");
    /// }
    /// ```
    pub fn analyze(ast: Parser) -> Result<Self, UnexpectedTokens> {
        let mut definitions = HashMap::new();
        let mut errors = Vec::new();

        for definition in ast {
            match definition {
                Ast::TypeDefinition(name, parameters) => {
                    definitions.insert(name, build_parameters(parameters));
                },
                Ast::Unexpected(token) => errors.push(token),
                _ => unreachable!(),
            }
        }

        match errors.is_empty() {
            true => SemanticBuilder::build(definitions),
            false => Err(errors),
        }
    }
}

struct SemanticBuilder {
    definitions: HashMap<String, Vec<(String, String)>>,

    order: Vec<String>,
    visited: HashSet<String>,
    cycles: HashSet<String>,
}

impl SemanticBuilder {
    fn build(definitions: HashMap<String, Vec<(String, String)>>) -> Result<Semantic, UnexpectedTokens> {
        let mut sb = Self {
            definitions,
            order: Vec::new(),
            visited: HashSet::new(),
            cycles: HashSet::new(),
        };

        for node in sb.definitions.clone().keys() {
            sb.visit(node);
        }

        Ok(Semantic {
            definitions: sb.definitions,
            order: sb.order,
            cycles: sb.cycles,
        })
    }

    fn visit(&mut self, node: &String) {
        if self.order.contains(node) {
            return;
        } else if self.visited.contains(node) {
            self.cycles = self.visited.clone();
            return;
        }

        self.visited.insert(node.clone());

        if let Some(d) = self.definitions.clone().get(node) {
            for &(_, ref v) in d {
                self.visit(v);
            }
        }

        self.order.push(node.clone());
        self.visited.remove(node);
    }
}

fn ast_to_parameter(ast: Ast) -> Option<(String, String)> {
    match ast {
        Ast::Parameter(name, typename) => Some((name, typename)),
        _ => None,
    }
}

fn build_parameters(ast: Vec<Ast>) -> Vec<(String, String)> {
    ast.into_iter()
        .filter_map(ast_to_parameter)
        .collect()
}

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

    fn get_semantic(content: &str) -> Result<Semantic, UnexpectedTokens> {
        Semantic::analyze(Parser::new(Lexer::new(content)))
    }

    #[test]
    fn order_ok() {
        let content = "tipo A(x: long);\
        tipo B(a: A);";

        let a = get_semantic(content).unwrap();

        assert_eq!(a.order[0], String::from("long"));
        assert_eq!(a.order[1], String::from("A"));
        assert_eq!(a.order[2], String::from("B"));
    }

    #[test]
    fn cycle() {
        let content = "tipo A(x: B);\
        tipo B (x: A);";

        let s = get_semantic(content).unwrap();

        assert!(s.cycles.contains("A"));
        assert!(s.cycles.contains("B"));
    }

    #[test]
    fn cycle_order_1() {
        let content = "tipo A(x: B);\
        tipo B(x: A);\
        tipo C(a: A, b: B);";

        let s = get_semantic(content).unwrap();

        assert_eq!(s.order[2], String::from("C"));
        assert!(s.cycles.contains("A"));
        assert!(s.cycles.contains("B"));
    }

    #[test]
    fn cycle_order_2() {
        let content = "tipo A(x: B, c: C);\
        tipo B(x: A);";

        let s = get_semantic(content).unwrap();

        let t_b = String::from("B");
        let t_c = String::from("C");

        let assert = s.order[0] == t_c || (s.order[0] == t_b && s.order[1] == t_c);

        assert!(assert);
        assert!(s.cycles.contains("A"));
        assert!(s.cycles.contains(&t_b));
    }

    #[test]
    fn cycle_order_3() {
        let content = "tipo C(a: A);\
        tipo A(b: B);\
        tipo B(a: A);";

        let s = get_semantic(content).unwrap();

        let t_a = String::from("A");
        let t_b = String::from("B");
        let t_c = String::from("C");

        let assert_1 = s.order == vec![t_a.clone(), t_b.clone(), t_c.clone()];
        let assert_2 = s.order == vec![t_a.clone(), t_c.clone(), t_b.clone()];
        let assert_3 = s.order == vec![t_b.clone(), t_a.clone(), t_c.clone()];

        assert!(assert_1 || assert_2 || assert_3);
        assert!(s.cycles.contains(&t_a));
        assert!(s.cycles.contains(&t_b));
    }
}
<commit_msg>Replace Vec::is_empty with Vec::len<commit_after>//! Semantic analyzer module.
//!
//! Usually a semantic analyzer checks if everything is in order (variables
//! are in scope, type inference...) before tying to compile the program.
//!
//! The aim with this one, for simplicity, is to walk dependencies (including
//! cyclic ones) to determine in what order they must be written.

use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;

use super::lexer::Token;
use super::parser::{Ast, Parser};

/// Value returned in [`Semantic::analyze`][0] if any errors are found.
///
/// In this analyzer, we only return error if we find any unexpected tokens.
/// Here we store all of them.
///
/// [0]: struct.Semantic.html#method.analyze
pub type UnexpectedTokens = Vec<Token>;

/// The semantic analyzer in our language.
///
/// Given an AST (from a [`Parser`][0]) determines the order in which all
/// definitions must go.
///
/// [0]: ../parser/struct.Parser.html
pub struct Semantic {
    /// All the type definitions. Since we consumed the AST, we have to store
    /// them somewhere.
    pub definitions: HashMap<String, Vec<(String, String)>>,
    /// The order in which to write the definitions.
    pub order: Vec<String>,
    /// If any cyclic dependency is found, all the types involved are stored
    /// here, so they can be handled accordingly.
    pub cycles: HashSet<String>,
}

impl Semantic {
    /// Builds the semantic analyzer and analyzes the AST.
    ///
    /// # Examples
    ///
    /// ```
    /// use simcom::lexer::Lexer;
    /// use simcom::parser::Parser;
    /// use simcom::semantic::Semantic;
    ///
    /// let content = "tipo A(x: X);";
    /// let ast = Parser::new(Lexer::new(content));
    ///
    /// if let Ok(s) = Semantic::analyze(ast) {
    ///     assert_eq!(s.order[0], String::from("X"));
    ///     assert_eq!(s.order[1], String::from("A"));
    /// } else {
    ///     panic!("Wrong if/else branch!");
    /// }
    /// ```
    ///
    /// ```
    /// use simcom::lexer::{Lexer, Token};
    /// use simcom::parser::Parser;
    /// use simcom::semantic::Semantic;
    ///
    /// // Note the two semicolons:
    /// let content = "tipo A(x: X);;";
    /// let s = Semantic::analyze(Parser::new(Lexer::new(content)));
    ///
    /// if let Err(ve) = s {
    ///     assert_eq!(ve[0], Token::Semicolon);
    /// } else {
    ///     panic!("Wrong if/else branch!");
    /// }
    /// ```
    pub fn analyze(ast: Parser) -> Result<Self, UnexpectedTokens> {
        let mut definitions = HashMap::new();
        let mut errors = Vec::new();

        for definition in ast {
            match definition {
                Ast::TypeDefinition(name, parameters) => {
                    definitions.insert(name, build_parameters(parameters));
                },
                Ast::Unexpected(token) => errors.push(token),
                _ => unreachable!(),
            }
        }

        match errors.len() {
            0 => SemanticBuilder::build(definitions),
            _ => Err(errors),
        }
    }
}

struct SemanticBuilder {
    definitions: HashMap<String, Vec<(String, String)>>,

    order: Vec<String>,
    visited: HashSet<String>,
    cycles: HashSet<String>,
}

impl SemanticBuilder {
    fn build(definitions: HashMap<String, Vec<(String, String)>>) -> Result<Semantic, UnexpectedTokens> {
        let mut sb = Self {
            definitions,
            order: Vec::new(),
            visited: HashSet::new(),
            cycles: HashSet::new(),
        };

        for node in sb.definitions.clone().keys() {
            sb.visit(node);
        }

        Ok(Semantic {
            definitions: sb.definitions,
            order: sb.order,
            cycles: sb.cycles,
        })
    }

    fn visit(&mut self, node: &String) {
        if self.order.contains(node) {
            return;
        } else if self.visited.contains(node) {
            self.cycles = self.visited.clone();
            return;
        }

        self.visited.insert(node.clone());

        if let Some(d) = self.definitions.clone().get(node) {
            for &(_, ref v) in d {
                self.visit(v);
            }
        }

        self.order.push(node.clone());
        self.visited.remove(node);
    }
}

fn ast_to_parameter(ast: Ast) -> Option<(String, String)> {
    match ast {
        Ast::Parameter(name, typename) => Some((name, typename)),
        _ => None,
    }
}

fn build_parameters(ast: Vec<Ast>) -> Vec<(String, String)> {
    ast.into_iter()
        .filter_map(ast_to_parameter)
        .collect()
}

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

    fn get_semantic(content: &str) -> Result<Semantic, UnexpectedTokens> {
        Semantic::analyze(Parser::new(Lexer::new(content)))
    }

    #[test]
    fn order_ok() {
        let content = "tipo A(x: long);\
        tipo B(a: A);";

        let a = get_semantic(content).unwrap();

        assert_eq!(a.order[0], String::from("long"));
        assert_eq!(a.order[1], String::from("A"));
        assert_eq!(a.order[2], String::from("B"));
    }

    #[test]
    fn cycle() {
        let content = "tipo A(x: B);\
        tipo B (x: A);";

        let s = get_semantic(content).unwrap();

        assert!(s.cycles.contains("A"));
        assert!(s.cycles.contains("B"));
    }

    #[test]
    fn cycle_order_1() {
        let content = "tipo A(x: B);\
        tipo B(x: A);\
        tipo C(a: A, b: B);";

        let s = get_semantic(content).unwrap();

        assert_eq!(s.order[2], String::from("C"));
        assert!(s.cycles.contains("A"));
        assert!(s.cycles.contains("B"));
    }

    #[test]
    fn cycle_order_2() {
        let content = "tipo A(x: B, c: C);\
        tipo B(x: A);";

        let s = get_semantic(content).unwrap();

        let t_b = String::from("B");
        let t_c = String::from("C");

        let assert = s.order[0] == t_c || (s.order[0] == t_b && s.order[1] == t_c);

        assert!(assert);
        assert!(s.cycles.contains("A"));
        assert!(s.cycles.contains(&t_b));
    }

    #[test]
    fn cycle_order_3() {
        let content = "tipo C(a: A);\
        tipo A(b: B);\
        tipo B(a: A);";

        let s = get_semantic(content).unwrap();

        let t_a = String::from("A");
        let t_b = String::from("B");
        let t_c = String::from("C");

        let assert_1 = s.order == vec![t_a.clone(), t_b.clone(), t_c.clone()];
        let assert_2 = s.order == vec![t_a.clone(), t_c.clone(), t_b.clone()];
        let assert_3 = s.order == vec![t_b.clone(), t_a.clone(), t_c.clone()];

        assert!(assert_1 || assert_2 || assert_3);
        assert!(s.cycles.contains(&t_a));
        assert!(s.cycles.contains(&t_b));
    }
}
<|endoftext|>


<commit_before>pub trait VectorTarget<T> {
    fn get_unchecked(v: &CxxVector<T>, pos: usize) -> &T
    where
        Self: Sized;
    fn vector_length(v: &CxxVector<T>) -> usize
    where
        Self: Sized;
    fn push_back(v: &CxxVector<T>, item: &T)
    where
        Self: Sized;
}

/// Binding to C++ `std::vector<T>`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `Vector` by value. C++'s vector
/// requires a move constructor and may hold internal pointers, which is not
/// compatible with Rust's move behavior. Instead in Rust code we will only ever
/// look at a Vector through a reference or smart pointer, as in `&Vector`
/// or `UniquePtr<Vector>`.
#[repr(C)]
pub struct CxxVector<T> {
    _private: [T; 0],
}

impl<T: VectorTarget<T>> CxxVector<T> {
    /// Returns the length of the vector in bytes.
    pub fn size(&self) -> usize {
        T::vector_length(self)
    }

    pub fn get_unchecked(&self, pos: usize) -> &T {
        T::get_unchecked(self, pos)
    }

    /// Returns true if `self` has a length of zero bytes.
    pub fn is_empty(&self) -> bool {
        self.size() == 0
    }

    pub fn get(&self, pos: usize) -> Option<&T> {
        if pos < self.size() {
            Some(self.get_unchecked(pos))
        } else {
            None
        }
    }

    pub fn push_back(&mut self, item: &T) {
        T::push_back(self, item);
    }
}

unsafe impl<T> Send for CxxVector<T> where T: Send + VectorTarget<T> {}

pub struct VectorIntoIterator<'a, T> {
    v: &'a CxxVector<T>,
    index: usize,
}

impl<'a, T: VectorTarget<T>> IntoIterator for &'a CxxVector<T> {
    type Item = &'a T;
    type IntoIter = VectorIntoIterator<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        VectorIntoIterator { v: self, index: 0 }
    }
}

impl<'a, T: VectorTarget<T>> Iterator for VectorIntoIterator<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        self.index = self.index + 1;
        self.v.get(self.index - 1)
    }
}

cxxbridge_macro::vector_builtin!(u8);
cxxbridge_macro::vector_builtin!(u16);
cxxbridge_macro::vector_builtin!(u32);
cxxbridge_macro::vector_builtin!(u64);
cxxbridge_macro::vector_builtin!(usize);
cxxbridge_macro::vector_builtin!(i8);
cxxbridge_macro::vector_builtin!(i16);
cxxbridge_macro::vector_builtin!(i32);
cxxbridge_macro::vector_builtin!(i64);
cxxbridge_macro::vector_builtin!(isize);
cxxbridge_macro::vector_builtin!(f32);
cxxbridge_macro::vector_builtin!(f64);
<commit_msg>Fix align of CxxVector<commit_after>use std::mem;

pub trait VectorTarget<T> {
    fn get_unchecked(v: &CxxVector<T>, pos: usize) -> &T
    where
        Self: Sized;
    fn vector_length(v: &CxxVector<T>) -> usize
    where
        Self: Sized;
    fn push_back(v: &CxxVector<T>, item: &T)
    where
        Self: Sized;
}

/// Binding to C++ `std::vector<T>`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `Vector` by value. C++'s vector
/// requires a move constructor and may hold internal pointers, which is not
/// compatible with Rust's move behavior. Instead in Rust code we will only ever
/// look at a Vector through a reference or smart pointer, as in `&Vector`
/// or `UniquePtr<Vector>`.
#[repr(C, packed)]
pub struct CxxVector<T> {
    _private: [T; 0],
}

impl<T: VectorTarget<T>> CxxVector<T> {
    /// Returns the length of the vector in bytes.
    pub fn size(&self) -> usize {
        T::vector_length(self)
    }

    pub fn get_unchecked(&self, pos: usize) -> &T {
        T::get_unchecked(self, pos)
    }

    /// Returns true if `self` has a length of zero bytes.
    pub fn is_empty(&self) -> bool {
        self.size() == 0
    }

    pub fn get(&self, pos: usize) -> Option<&T> {
        if pos < self.size() {
            Some(self.get_unchecked(pos))
        } else {
            None
        }
    }

    pub fn push_back(&mut self, item: &T) {
        T::push_back(self, item);
    }
}

unsafe impl<T> Send for CxxVector<T> where T: Send + VectorTarget<T> {}

pub struct VectorIntoIterator<'a, T> {
    v: &'a CxxVector<T>,
    index: usize,
}

impl<'a, T: VectorTarget<T>> IntoIterator for &'a CxxVector<T> {
    type Item = &'a T;
    type IntoIter = VectorIntoIterator<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        VectorIntoIterator { v: self, index: 0 }
    }
}

impl<'a, T: VectorTarget<T>> Iterator for VectorIntoIterator<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        self.index = self.index + 1;
        self.v.get(self.index - 1)
    }
}

cxxbridge_macro::vector_builtin!(u8);
cxxbridge_macro::vector_builtin!(u16);
cxxbridge_macro::vector_builtin!(u32);
cxxbridge_macro::vector_builtin!(u64);
cxxbridge_macro::vector_builtin!(usize);
cxxbridge_macro::vector_builtin!(i8);
cxxbridge_macro::vector_builtin!(i16);
cxxbridge_macro::vector_builtin!(i32);
cxxbridge_macro::vector_builtin!(i64);
cxxbridge_macro::vector_builtin!(isize);
cxxbridge_macro::vector_builtin!(f32);
cxxbridge_macro::vector_builtin!(f64);

const_assert_eq!(1, mem::align_of::<CxxVector<usize>>());
<|endoftext|>


<commit_before>// TODO: get num cols of terminal dynamically

use super::{Report, ReportKind, RemarkKind};
use code::{FileMap, LineIdx};
use term_painter::ToStyle;
use term_painter::Color::*;
use std::default::Default;

/// Options for printing
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct PrintOptions {
    /// Use of unicode allowed?
    pub unicode: bool,
    /// Use of colors allowed?
    pub color: bool,
    /// Is line wrapping allowed?
    pub line_wrap: bool,
}

impl Default for PrintOptions {
    fn default() -> Self {
        PrintOptions {
            unicode: true,
            color: true,
            line_wrap: true,
        }
    }
}

pub fn print(rep: &Report, src: &FileMap, _: PrintOptions) {
    // print header
    let title = match rep.kind {
        ReportKind::Error => White.bold().bg(Red).paint("ERROR"),
        ReportKind::Warning => White.bold().bg(Yellow).paint("WARNING"),
    };

    let line = if rep.span.is_dummy() {
        "<dummy-span>".into()
    } else {
        let start = src.get_loc(rep.span.lo);
        let end = src.get_loc(rep.span.hi);
        if start.line != end.line {
            format!("{}-{}", start.line, end.line)
        } else {
            start.line.to_string()
        }
    };

    println!("+---- {} in {} : {} ----+",
        title,
        src.filename(),
        Blue.paint(line)
    );

    for rem in &rep.remarks {
        // print message
        let (title, title_len) = match rem.kind {
            RemarkKind::Error => (Red.paint("error:"), 6),
            RemarkKind::Warning => (Yellow.paint("warning:"), 8),
            RemarkKind::Note => (Green.paint("note:"), 5),
        };

        print!("      =====>  {} ", title);
        // spaces + big arrow + spaces + title + space
        let indent = 6 + 6 + 2 + title_len + 1;
        let block_width = 80 - indent;

        let mut col = 0;
        for word in rem.desc.split_whitespace() {
            let word_len = word.chars().count();
            if col + word_len >= block_width && col != 0 {
                println!("");
                print!("           >  {0:>1$} ", " ", title_len);
                col = 0;
            }
            print!("{} ", White.bold().paint(word));
            col += word_len + 1;
        }
        println!("");

        // print code snippet
        if let Some(span) = rem.span {
            let start = src.get_loc(span.lo);
            let end = src.get_loc(span.hi);

            if span.is_dummy() {
                println!("!!! no snippet due to <dummy-span> !!!");
            } else if start.line == end.line {
                if let Some(line) = src.get_line(start.line) {
                    println!("{:>#4} {} {}",
                        Magenta.bold().paint(start.line),
                        Magenta.bold().paint("|"),
                        line
                    );

                    Yellow.with(|| {
                        println!("       {: <2$}{:-<3$}",
                            " ", "^",
                            start.col.0 as usize,
                            (end.col.0 - start.col.0) as usize
                        );
                    });
                }
            } else {
                for line_idx in start.line.0..end.line.0 + 1 {
                    let line_idx = LineIdx(line_idx);
                    if let Some(line) = src.get_line(line_idx) {
                        println!("{:>#4} {} {}",
                            Magenta.bold().paint(line_idx),
                            Magenta.bold().paint("|"),
                            line
                        );
                    }
                }
            }
            println!("");
        }

    }
    println!("");
}
<commit_msg>Improve readability of title line number<commit_after>// TODO: get num cols of terminal dynamically

use super::{Report, ReportKind, RemarkKind};
use code::{FileMap, LineIdx};
use term_painter::ToStyle;
use term_painter::Color::*;
use std::default::Default;

/// Options for printing
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct PrintOptions {
    /// Use of unicode allowed?
    pub unicode: bool,
    /// Use of colors allowed?
    pub color: bool,
    /// Is line wrapping allowed?
    pub line_wrap: bool,
}

impl Default for PrintOptions {
    fn default() -> Self {
        PrintOptions {
            unicode: true,
            color: true,
            line_wrap: true,
        }
    }
}

pub fn print(rep: &Report, src: &FileMap, _: PrintOptions) {
    // print header
    let title = match rep.kind {
        ReportKind::Error => White.bold().bg(Red).paint("ERROR"),
        ReportKind::Warning => White.bold().bg(Yellow).paint("WARNING"),
    };

    let line = if rep.span.is_dummy() {
        "<dummy-span>".into()
    } else {
        let start = src.get_loc(rep.span.lo);
        let end = src.get_loc(rep.span.hi);
        if start.line != end.line {
            format!("{}-{}", start.line, end.line)
        } else {
            start.line.to_string()
        }
    };

    println!("+---- {} in {} : {} ----+",
        title,
        src.filename(),
        Magenta.bold().paint(line)
    );

    for rem in &rep.remarks {
        // print message
        let (title, title_len) = match rem.kind {
            RemarkKind::Error => (Red.paint("error:"), 6),
            RemarkKind::Warning => (Yellow.paint("warning:"), 8),
            RemarkKind::Note => (Green.paint("note:"), 5),
        };

        print!("      =====>  {} ", title);
        // spaces + big arrow + spaces + title + space
        let indent = 6 + 6 + 2 + title_len + 1;
        let block_width = 80 - indent;

        let mut col = 0;
        for word in rem.desc.split_whitespace() {
            let word_len = word.chars().count();
            if col + word_len >= block_width && col != 0 {
                println!("");
                print!("           >  {0:>1$} ", " ", title_len);
                col = 0;
            }
            print!("{} ", White.bold().paint(word));
            col += word_len + 1;
        }
        println!("");

        // print code snippet
        if let Some(span) = rem.span {
            let start = src.get_loc(span.lo);
            let end = src.get_loc(span.hi);

            if span.is_dummy() {
                println!("!!! no snippet due to <dummy-span> !!!");
            } else if start.line == end.line {
                if let Some(line) = src.get_line(start.line) {
                    println!("{:>#4} {} {}",
                        Magenta.bold().paint(start.line),
                        Magenta.bold().paint("|"),
                        line
                    );

                    Yellow.with(|| {
                        println!("       {: <2$}{:-<3$}",
                            " ", "^",
                            start.col.0 as usize,
                            (end.col.0 - start.col.0) as usize
                        );
                    });
                }
            } else {
                for line_idx in start.line.0..end.line.0 + 1 {
                    let line_idx = LineIdx(line_idx);
                    if let Some(line) = src.get_line(line_idx) {
                        println!("{:>#4} {} {}",
                            Magenta.bold().paint(line_idx),
                            Magenta.bold().paint("|"),
                            line
                        );
                    }
                }
            }
            println!("");
        }

    }
    println!("");
}
<|endoftext|>


<commit_before>extern crate cc;
extern crate glob;

use std::env;
use std::process::Command;

use glob::glob;

#[path = "../../mkmain.rs"]
mod mkmain;

#[cfg(target_os = "macos")]
mod platform {
    pub const DYLIB_EXT: &'static str = "dylib";
    pub const DYLIB_FLAGS: [&'static str; 3] = ["-dynamiclib", "-undefined", "dynamic_lookup"];
    pub const DYLIB_LINK_START: &'static str = "";
    pub const DYLIB_LINK_END: &'static str = "";
}

#[cfg(target_os = "linux")]
mod platform {
    pub const DYLIB_EXT: &'static str = "so";
    pub const DYLIB_FLAGS: [&'static str; 1] = ["-shared"];
    pub const DYLIB_LINK_START: &'static str = "-Wl,--whole-archive";
    pub const DYLIB_LINK_END: &'static str = "-Wl,--no-whole-archive";
}

// FIXME: this entire thing is pretty fragile
fn main() {
    mkmain::main();

    let cc = env::var("CC").unwrap_or("gcc".to_string());

    let out_dir = env::var("OUT_DIR").unwrap();

    let entry = glob(&format!("{}/../../../deps/liblibstdbuf-*.a", out_dir)).unwrap()
                                                                            .next()
                                                                            .unwrap()
                                                                            .unwrap();

    cc::Build::new()
        .flag("-Wall")
        .flag("-Werror")
        .pic(true)
        .file("libstdbuf.c")
        .compile("libstdbuf.a");

    // XXX: we have to link manually because apparently cc-rs does not support shared libraries
    let mut link = Command::new(cc);
    for flag in platform::DYLIB_FLAGS.iter() {
        link.arg(flag);
    }
    link.arg("-o")
        .arg(format!("{}/libstdbuf.{}", out_dir, platform::DYLIB_EXT))
        .arg(format!("{}/libstdbuf.a", out_dir))
        .arg(entry);
    if !link.spawn().unwrap().wait().unwrap().success() {
        panic!("linking failed");
    }
}
<commit_msg>stdbuf: fix build warning<commit_after>extern crate cc;
extern crate glob;

use std::env;
use std::process::Command;

use glob::glob;

#[path = "../../mkmain.rs"]
mod mkmain;

#[cfg(target_os = "macos")]
mod platform {
    pub const DYLIB_EXT: &'static str = "dylib";
    pub const DYLIB_FLAGS: [&'static str; 3] = ["-dynamiclib", "-undefined", "dynamic_lookup"];
}

#[cfg(target_os = "linux")]
mod platform {
    pub const DYLIB_EXT: &'static str = "so";
    pub const DYLIB_FLAGS: [&'static str; 1] = ["-shared"];
}

// FIXME: this entire thing is pretty fragile
fn main() {
    mkmain::main();

    let cc = env::var("CC").unwrap_or("gcc".to_string());

    let out_dir = env::var("OUT_DIR").unwrap();

    let entry = glob(&format!("{}/../../../deps/liblibstdbuf-*.a", out_dir)).unwrap()
                                                                            .next()
                                                                            .unwrap()
                                                                            .unwrap();

    cc::Build::new()
        .flag("-Wall")
        .flag("-Werror")
        .pic(true)
        .file("libstdbuf.c")
        .compile("libstdbuf.a");

    // XXX: we have to link manually because apparently cc-rs does not support shared libraries
    let mut link = Command::new(cc);
    for flag in platform::DYLIB_FLAGS.iter() {
        link.arg(flag);
    }
    link.arg("-o")
        .arg(format!("{}/libstdbuf.{}", out_dir, platform::DYLIB_EXT))
        .arg(format!("{}/libstdbuf.a", out_dir))
        .arg(entry);
    if !link.spawn().unwrap().wait().unwrap().success() {
        panic!("linking failed");
    }
}
<|endoftext|>