<commit_before>//! Lettre is an email library that allows creating and sending messages. It provides:
//!
//! * An easy to use email builder
//! * Pluggable email transports
//! * Unicode support
//! * Secure defaults
//! * Async support
//!
//! Lettre requires Rust 1.56.0 or newer.
//!
//! ## Features
//!
//! This section lists each lettre feature and briefly explains it.
//! More info about each module can be found in the corresponding module page.
//!
//! Features with `📫` near them are enabled by default.
//!
//! ### Typed message builder
//!
//! _Strongly typed [`message`] builder_
//!
//! * **builder** 📫: Enable the [`Message`] builder
//! * **hostname** 📫: Try to use the actual system hostname in the `Message-ID` header
//!
//! ### SMTP transport
//!
//! _Send emails using [`SMTP`]_
//!
//! * **smtp-transport** 📫: Enable the SMTP transport
//! * **pool** 📫: Connection pool for SMTP transport
//! * **hostname** 📫: Try to use the actual system hostname for the SMTP `CLIENTID`
//!
//! #### SMTP over TLS via the native-tls crate
//!
//! _Secure SMTP connections using TLS from the `native-tls` crate_
//!
//! Uses schannel on Windows, Security-Framework on macOS, and OpenSSL on Linux.
//!
//! * **native-tls** 📫: TLS support for the synchronous version of the API
//! * **tokio1-native-tls**: TLS support for the `tokio1` async version of the API
//!
//! NOTE: native-tls isn't supported with `async-std`
//!
//! #### SMTP over TLS via the rustls crate
//!
//! _Secure SMTP connections using TLS from the `rustls-tls` crate_
//!
//! Rustls uses [ring] as the cryptography implementation. As a result, [not all Rust's targets are supported][ring-support].
//!
//! * **rustls-tls**: TLS support for the synchronous version of the API
//! * **tokio1-rustls-tls**: TLS support for the `tokio1` async version of the API
//! * **async-std1-rustls-tls**: TLS support for the `async-std1` async version of the API
//!
//! ### Sendmail transport
//!
//! _Send emails using the [`sendmail`] command_
//!
//! * **sendmail-transport**: Enable the `sendmail` transport
//!
//! ### File transport
//!
//! _Save emails as an `.eml` [`file`]_
//!
//! * **file-transport**: Enable the file transport (saves emails into an `.eml` file)
//! * **file-transport-envelope**: Allow writing the envelope into a JSON file (additionally saves envelopes into a `.json` file)
//!
//! ### Async execution runtimes
//!
//! _Use [tokio] or [async-std] as an async execution runtime for sending emails_
//!
//! The correct runtime version must be chosen in order for lettre to work correctly.
//! For example, when sending emails from a Tokio 1.x context, the Tokio 1.x executor
//! ([`Tokio1Executor`]) must be used. Using a different version (for example Tokio 0.2.x),
//! or async-std, would result in a runtime panic.
//!
//! * **tokio1**: Allow to asynchronously send emails using [Tokio 1.x]
//! * **async-std1**: Allow to asynchronously send emails using [async-std 1.x]
//!
//! NOTE: native-tls isn't supported with `async-std`
//!
//! ### Misc features
//!
//! _Additional features_
//!
//! * **serde**: Serialization/Deserialization of entities
//! * **tracing**: Logging using the `tracing` crate
//! * **mime03**: Allow creating a [`ContentType`] from an existing [mime 0.3] `Mime` struct
//! * **dkim**: Add support for signing email with DKIM
//!
//! [`SMTP`]: crate::transport::smtp
//! [`sendmail`]: crate::transport::sendmail
//! [`file`]: crate::transport::file
//! [`ContentType`]: crate::message::header::ContentType
//! [tokio]: https://docs.rs/tokio/1
//! [async-std]: https://docs.rs/async-std/1
//! [ring]: https://github.com/briansmith/ring#ring
//! [ring-support]: https://github.com/briansmith/ring#online-automated-testing
//! [Tokio 1.x]: https://docs.rs/tokio/1
//! [async-std 1.x]: https://docs.rs/async-std/1
//! [mime 0.3]: https://docs.rs/mime/0.3
//! [DKIM]: https://datatracker.ietf.org/doc/html/rfc6376

#![doc(html_root_url = "https://docs.rs/crate/lettre/0.10.0-rc.5")]
#![doc(html_favicon_url = "https://lettre.rs/favicon.ico")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/15113230?v=4")]
#![forbid(unsafe_code)]
#![deny(
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unstable_features,
    unused_import_braces,
    rust_2018_idioms,
    clippy::string_add,
    clippy::string_add_assign
)]
#![cfg_attr(docsrs, feature(doc_cfg))]

#[cfg(not(lettre_ignore_tls_mismatch))]
mod compiletime_checks {
    #[cfg(all(
        feature = "tokio1",
        feature = "native-tls",
        not(feature = "tokio1-native-tls")
    ))]
    compile_error!("Lettre is being built with the `tokio1` and the `native-tls` features, but the `tokio1-native-tls` feature hasn't been turned on.
If you'd like to use rustls make sure that the `native-tls` hasn't been enabled by mistake (you may need to import lettre without default features)
If you're building a library which depends on lettre import it without default features and enable just the features you need.");

    #[cfg(all(
        feature = "tokio1",
        feature = "rustls-tls",
        not(feature = "tokio1-rustls-tls")
    ))]
    compile_error!("Lettre is being built with the `tokio1` and the `rustls-tls` features, but the `tokio1-rustls-tls` feature hasn't been turned on.
If you'd like to use native-tls make sure that the `rustls-tls` hasn't been enabled by mistake.
If you're building a library which depends on lettre import it without default features and enable just the features you need.");

    /*
    #[cfg(all(
        feature = "async-std1",
        feature = "native-tls",
        not(feature = "async-std1-native-tls")
    ))]
    compile_error!("Lettre is being built with the `async-std1` and the `native-tls` features, but the `async-std1-native-tls` feature hasn't been turned on.
    If you'd like to use rustls make sure that the `native-tls` hasn't been enabled by mistake (you may need to import lettre without default features)
    If you're building a library which depends on lettre import it without default features and enable just the features you need.");
    */
    #[cfg(all(
        feature = "async-std1",
        feature = "native-tls",
        not(feature = "async-std1-native-tls")
    ))]
    compile_error!("Lettre is being built with the `async-std1` and the `native-tls` features, but the async-std integration doesn't support native-tls yet.
If you'd like to work on the issue please take a look at https://github.com/lettre/lettre/issues/576.
If you'd like to use rustls make sure that the `native-tls` hasn't been enabled by mistake (you may need to import lettre without default features)
If you're building a library which depends on lettre import lettre without default features and enable just the features you need.");

    #[cfg(all(
        feature = "async-std1",
        feature = "rustls-tls",
        not(feature = "async-std1-rustls-tls")
    ))]
    compile_error!("Lettre is being built with the `async-std1` and the `rustls-tls` features, but the `async-std1-rustls-tls` feature hasn't been turned on.
If you'd like to use native-tls make sure that the `rustls-tls` hasn't been enabled by mistake (you may need to import lettre without default features)
If you're building a library which depends on lettre import it without default features and enable just the features you need.");
}

pub mod address;
pub mod error;
#[cfg(any(feature = "tokio1", feature = "async-std1"))]
mod executor;
#[cfg(feature = "builder")]
#[cfg_attr(docsrs, doc(cfg(feature = "builder")))]
pub mod message;
pub mod transport;

use std::error::Error as StdError;

#[cfg(feature = "async-std1")]
pub use self::executor::AsyncStd1Executor;
#[cfg(all(any(feature = "tokio1", feature = "async-std1")))]
pub use self::executor::Executor;
#[cfg(feature = "tokio1")]
pub use self::executor::Tokio1Executor;
#[cfg(all(any(feature = "tokio1", feature = "async-std1")))]
#[doc(inline)]
pub use self::transport::AsyncTransport;
pub use crate::address::Address;
#[cfg(feature = "builder")]
#[doc(inline)]
pub use crate::message::Message;
#[cfg(all(
    feature = "file-transport",
    any(feature = "tokio1", feature = "async-std1")
))]
#[doc(inline)]
pub use crate::transport::file::AsyncFileTransport;
#[cfg(feature = "file-transport")]
#[doc(inline)]
pub use crate::transport::file::FileTransport;
#[cfg(all(
    feature = "sendmail-transport",
    any(feature = "tokio1", feature = "async-std1")
))]
#[doc(inline)]
pub use crate::transport::sendmail::AsyncSendmailTransport;
#[cfg(feature = "sendmail-transport")]
#[doc(inline)]
pub use crate::transport::sendmail::SendmailTransport;
#[cfg(all(
    feature = "smtp-transport",
    any(feature = "tokio1", feature = "async-std1")
))]
pub use crate::transport::smtp::AsyncSmtpTransport;
#[cfg(feature = "smtp-transport")]
pub use crate::transport::smtp::SmtpTransport;
#[doc(inline)]
pub use crate::transport::Transport;
use crate::{address::Envelope, error::Error};

pub(crate) type BoxError = Box<dyn StdError + Send + Sync>;

#[cfg(test)]
#[cfg(feature = "builder")]
mod test {
    use super::*;
    use crate::message::{header, header::Headers, Mailbox, Mailboxes};

    #[test]
    fn envelope_from_headers() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let to = Mailboxes::new().with("amousset@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From(from));
        headers.set(header::To(to));

        assert_eq!(
            Envelope::try_from(&headers).unwrap(),
            Envelope::new(
                Some(Address::new("kayo", "example.com").unwrap()),
                vec![Address::new("amousset", "example.com").unwrap()]
            )
            .unwrap()
        );
    }

    #[test]
    fn envelope_from_headers_sender() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let sender = Mailbox::new(None, "kayo2@example.com".parse().unwrap());
        let to = Mailboxes::new().with("amousset@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From::from(from));
        headers.set(header::Sender::from(sender));
        headers.set(header::To::from(to));

        assert_eq!(
            Envelope::try_from(&headers).unwrap(),
            Envelope::new(
                Some(Address::new("kayo2", "example.com").unwrap()),
                vec![Address::new("amousset", "example.com").unwrap()]
            )
            .unwrap()
        );
    }

    #[test]
    fn envelope_from_headers_no_to() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let sender = Mailbox::new(None, "kayo2@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From::from(from));
        headers.set(header::Sender::from(sender));

        assert!(Envelope::try_from(&headers).is_err(),);
    }
}
<commit_msg>Improve compiler error messages (#754)<commit_after>//! Lettre is an email library that allows creating and sending messages. It provides:
//!
//! * An easy to use email builder
//! * Pluggable email transports
//! * Unicode support
//! * Secure defaults
//! * Async support
//!
//! Lettre requires Rust 1.56.0 or newer.
//!
//! ## Features
//!
//! This section lists each lettre feature and briefly explains it.
//! More info about each module can be found in the corresponding module page.
//!
//! Features with `📫` near them are enabled by default.
//!
//! ### Typed message builder
//!
//! _Strongly typed [`message`] builder_
//!
//! * **builder** 📫: Enable the [`Message`] builder
//! * **hostname** 📫: Try to use the actual system hostname in the `Message-ID` header
//!
//! ### SMTP transport
//!
//! _Send emails using [`SMTP`]_
//!
//! * **smtp-transport** 📫: Enable the SMTP transport
//! * **pool** 📫: Connection pool for SMTP transport
//! * **hostname** 📫: Try to use the actual system hostname for the SMTP `CLIENTID`
//!
//! #### SMTP over TLS via the native-tls crate
//!
//! _Secure SMTP connections using TLS from the `native-tls` crate_
//!
//! Uses schannel on Windows, Security-Framework on macOS, and OpenSSL on Linux.
//!
//! * **native-tls** 📫: TLS support for the synchronous version of the API
//! * **tokio1-native-tls**: TLS support for the `tokio1` async version of the API
//!
//! NOTE: native-tls isn't supported with `async-std`
//!
//! #### SMTP over TLS via the rustls crate
//!
//! _Secure SMTP connections using TLS from the `rustls-tls` crate_
//!
//! Rustls uses [ring] as the cryptography implementation. As a result, [not all Rust's targets are supported][ring-support].
//!
//! * **rustls-tls**: TLS support for the synchronous version of the API
//! * **tokio1-rustls-tls**: TLS support for the `tokio1` async version of the API
//! * **async-std1-rustls-tls**: TLS support for the `async-std1` async version of the API
//!
//! ### Sendmail transport
//!
//! _Send emails using the [`sendmail`] command_
//!
//! * **sendmail-transport**: Enable the `sendmail` transport
//!
//! ### File transport
//!
//! _Save emails as an `.eml` [`file`]_
//!
//! * **file-transport**: Enable the file transport (saves emails into an `.eml` file)
//! * **file-transport-envelope**: Allow writing the envelope into a JSON file (additionally saves envelopes into a `.json` file)
//!
//! ### Async execution runtimes
//!
//! _Use [tokio] or [async-std] as an async execution runtime for sending emails_
//!
//! The correct runtime version must be chosen in order for lettre to work correctly.
//! For example, when sending emails from a Tokio 1.x context, the Tokio 1.x executor
//! ([`Tokio1Executor`]) must be used. Using a different version (for example Tokio 0.2.x),
//! or async-std, would result in a runtime panic.
//!
//! * **tokio1**: Allow to asynchronously send emails using [Tokio 1.x]
//! * **async-std1**: Allow to asynchronously send emails using [async-std 1.x]
//!
//! NOTE: native-tls isn't supported with `async-std`
//!
//! ### Misc features
//!
//! _Additional features_
//!
//! * **serde**: Serialization/Deserialization of entities
//! * **tracing**: Logging using the `tracing` crate
//! * **mime03**: Allow creating a [`ContentType`] from an existing [mime 0.3] `Mime` struct
//! * **dkim**: Add support for signing email with DKIM
//!
//! [`SMTP`]: crate::transport::smtp
//! [`sendmail`]: crate::transport::sendmail
//! [`file`]: crate::transport::file
//! [`ContentType`]: crate::message::header::ContentType
//! [tokio]: https://docs.rs/tokio/1
//! [async-std]: https://docs.rs/async-std/1
//! [ring]: https://github.com/briansmith/ring#ring
//! [ring-support]: https://github.com/briansmith/ring#online-automated-testing
//! [Tokio 1.x]: https://docs.rs/tokio/1
//! [async-std 1.x]: https://docs.rs/async-std/1
//! [mime 0.3]: https://docs.rs/mime/0.3
//! [DKIM]: https://datatracker.ietf.org/doc/html/rfc6376

#![doc(html_root_url = "https://docs.rs/crate/lettre/0.10.0-rc.5")]
#![doc(html_favicon_url = "https://lettre.rs/favicon.ico")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/15113230?v=4")]
#![forbid(unsafe_code)]
#![deny(
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unstable_features,
    unused_import_braces,
    rust_2018_idioms,
    clippy::string_add,
    clippy::string_add_assign
)]
#![cfg_attr(docsrs, feature(doc_cfg))]

#[cfg(not(lettre_ignore_tls_mismatch))]
mod compiletime_checks {
    #[cfg(all(
        feature = "tokio1",
        feature = "native-tls",
        not(feature = "tokio1-native-tls")
    ))]
    compile_error!("Lettre is being built with the `tokio1` and the `native-tls` features, but the `tokio1-native-tls` feature hasn't been turned on.
    If you were trying to opt into `rustls-tls` and did not activate `native-tls`, disable the default-features of lettre in `Cargo.toml` and manually add the required features.
    Make sure to apply the same to any of your crate dependencies that use the `lettre` crate.");

    #[cfg(all(
        feature = "tokio1",
        feature = "rustls-tls",
        not(feature = "tokio1-rustls-tls")
    ))]
    compile_error!("Lettre is being built with the `tokio1` and the `rustls-tls` features, but the `tokio1-rustls-tls` feature hasn't been turned on.
    If you'd like to use `native-tls` make sure that the `rustls-tls` feature hasn't been enabled by mistake.
    Make sure to apply the same to any of your crate dependencies that use the `lettre` crate.");

    /*
    #[cfg(all(
        feature = "async-std1",
        feature = "native-tls",
        not(feature = "async-std1-native-tls")
    ))]
    compile_error!("Lettre is being built with the `async-std1` and the `native-tls` features, but the `async-std1-native-tls` feature hasn't been turned on.
    If you'd like to use rustls make sure that the `native-tls` hasn't been enabled by mistake (you may need to import lettre without default features)
    If you're building a library which depends on lettre import it without default features and enable just the features you need.");
    */
    #[cfg(all(
        feature = "async-std1",
        feature = "native-tls",
        not(feature = "async-std1-native-tls")
    ))]
    compile_error!("Lettre is being built with the `async-std1` and the `native-tls` features, but the async-std integration doesn't support native-tls yet.
If you'd like to work on the issue please take a look at https://github.com/lettre/lettre/issues/576.
If you were trying to opt into `rustls-tls` and did not activate `native-tls`, disable the default-features of lettre in `Cargo.toml` and manually add the required features.
Make sure to apply the same to any of your crate dependencies that use the `lettre` crate.");

    #[cfg(all(
        feature = "async-std1",
        feature = "rustls-tls",
        not(feature = "async-std1-rustls-tls")
    ))]
    compile_error!("Lettre is being built with the `async-std1` and the `rustls-tls` features, but the `async-std1-rustls-tls` feature hasn't been turned on.
If you'd like to use `native-tls` make sure that the `rustls-tls` hasn't been enabled by mistake.
Make sure to apply the same to any of your crate dependencies that use the `lettre` crate.");
}

pub mod address;
pub mod error;
#[cfg(any(feature = "tokio1", feature = "async-std1"))]
mod executor;
#[cfg(feature = "builder")]
#[cfg_attr(docsrs, doc(cfg(feature = "builder")))]
pub mod message;
pub mod transport;

use std::error::Error as StdError;

#[cfg(feature = "async-std1")]
pub use self::executor::AsyncStd1Executor;
#[cfg(all(any(feature = "tokio1", feature = "async-std1")))]
pub use self::executor::Executor;
#[cfg(feature = "tokio1")]
pub use self::executor::Tokio1Executor;
#[cfg(all(any(feature = "tokio1", feature = "async-std1")))]
#[doc(inline)]
pub use self::transport::AsyncTransport;
pub use crate::address::Address;
#[cfg(feature = "builder")]
#[doc(inline)]
pub use crate::message::Message;
#[cfg(all(
    feature = "file-transport",
    any(feature = "tokio1", feature = "async-std1")
))]
#[doc(inline)]
pub use crate::transport::file::AsyncFileTransport;
#[cfg(feature = "file-transport")]
#[doc(inline)]
pub use crate::transport::file::FileTransport;
#[cfg(all(
    feature = "sendmail-transport",
    any(feature = "tokio1", feature = "async-std1")
))]
#[doc(inline)]
pub use crate::transport::sendmail::AsyncSendmailTransport;
#[cfg(feature = "sendmail-transport")]
#[doc(inline)]
pub use crate::transport::sendmail::SendmailTransport;
#[cfg(all(
    feature = "smtp-transport",
    any(feature = "tokio1", feature = "async-std1")
))]
pub use crate::transport::smtp::AsyncSmtpTransport;
#[cfg(feature = "smtp-transport")]
pub use crate::transport::smtp::SmtpTransport;
#[doc(inline)]
pub use crate::transport::Transport;
use crate::{address::Envelope, error::Error};

pub(crate) type BoxError = Box<dyn StdError + Send + Sync>;

#[cfg(test)]
#[cfg(feature = "builder")]
mod test {
    use super::*;
    use crate::message::{header, header::Headers, Mailbox, Mailboxes};

    #[test]
    fn envelope_from_headers() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let to = Mailboxes::new().with("amousset@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From(from));
        headers.set(header::To(to));

        assert_eq!(
            Envelope::try_from(&headers).unwrap(),
            Envelope::new(
                Some(Address::new("kayo", "example.com").unwrap()),
                vec![Address::new("amousset", "example.com").unwrap()]
            )
            .unwrap()
        );
    }

    #[test]
    fn envelope_from_headers_sender() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let sender = Mailbox::new(None, "kayo2@example.com".parse().unwrap());
        let to = Mailboxes::new().with("amousset@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From::from(from));
        headers.set(header::Sender::from(sender));
        headers.set(header::To::from(to));

        assert_eq!(
            Envelope::try_from(&headers).unwrap(),
            Envelope::new(
                Some(Address::new("kayo2", "example.com").unwrap()),
                vec![Address::new("amousset", "example.com").unwrap()]
            )
            .unwrap()
        );
    }

    #[test]
    fn envelope_from_headers_no_to() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let sender = Mailbox::new(None, "kayo2@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From::from(from));
        headers.set(header::Sender::from(sender));

        assert!(Envelope::try_from(&headers).is_err(),);
    }
}
<|endoftext|>


<commit_before>/*! Basic sorting algorithms, just for fun.

Note that the exported `Sortable` and `Sorted` traits provide all necessary functionality.
`Sortable` provides functions for in-place sorting, and `Sorted` provides copy-sorting.

Some benchmarks, all performed on a `Vec` of 2000 random `uint`s:

```ignore
test benchmarks::bench_bubblesort ... bench:   1197517 ns/iter (+/- 154803)
test benchmarks::bench_heapsort   ... bench:     54756 ns/iter (+/- 1863)
test benchmarks::bench_mergesort  ... bench:    132263 ns/iter (+/- 15198)
test benchmarks::bench_quicksort  ... bench:     44623 ns/iter (+/- 9263)
test benchmarks::bench_selsort    ... bench:    699363 ns/iter (+/- 36305)
test benchmarks::bench_shellsort  ... bench:     59090 ns/iter (+/- 3630)
test benchmarks::bench_slice_sort ... bench:     66509 ns/iter (+/- 3064)
```

`bubblesort` is by far the slowest, followed by `selsort`; both unsurprisingly slow.

Interestingly, `quicksort`, `heapsort`, and possibly `shellsort` outperform
`std::slice::MutableOrdSlice::sort()`, at least on this benchmark; the `std` one is, as I understand
it, an optimized mergesort, and is probably faster on more general benchmarks. Here are some things
this benchmark doesn't cover:

  * Comparing with a `compare` function instead of comparision by-value
  * Sorting a partially-sorted list
  * Sorting something with expensive copy operations
  * Sorting a reverse-sorted list

*/

#[warn(non_camel_case_types)]
#[warn(non_snake_case)]
#[warn(unused_qualifications)]
#[warn(non_upper_case_globals)]
#[warn(missing_docs)]

pub mod algorithms;

#[cfg(test)]
mod benchmarks;

// Public traits, for export

/// In-place sorting methods
pub trait Sortable<T : Ord> for Sized? : MutableSlice<T> {
	/// Quicksort, in-place
	fn quicksort(&mut self){algorithms::quicksort(self.as_mut_slice())}
	/// heapsort, in-place
	fn heapsort(&mut self){algorithms::heapsort(self.as_mut_slice())}
	/// bubblesort, in-place
	fn bubblesort(&mut self){algorithms::bubblesort(self.as_mut_slice())}
	/// selection sort, in-place
	fn selsort(&mut self) {algorithms::selsort(self.as_mut_slice())}
	/// shell sort, in-place
	fn shellsort(&mut self) {algorithms::shellsort(self.as_mut_slice())}
}

/// Copy-and-sort methods (i.e., mergesort)
pub trait Sorted<T : Ord + Clone> for Sized? : ImmutableSlice<T> {
	/// merge sort, returning a sorted version
	fn mergesorted(&self) -> Vec<T> {algorithms::mergesort(self.slice_from(0))}
}

impl<T: Ord> Sortable<T> for [T]{}

impl<T: Ord + Clone> Sorted<T> for [T]{}

<commit_msg>Updated to use std::slice::SlicePrelude, std::slice::AsSlice<commit_after>/*! Basic sorting algorithms, just for fun.

Note that the exported `Sortable` and `Sorted` traits provide all necessary functionality.
`Sortable` provides functions for in-place sorting, and `Sorted` provides copy-sorting.

Some benchmarks, all performed on a `Vec` of 2000 random `uint`s:

```ignore
test benchmarks::bench_bubblesort ... bench:   1197517 ns/iter (+/- 154803)
test benchmarks::bench_heapsort   ... bench:     54756 ns/iter (+/- 1863)
test benchmarks::bench_mergesort  ... bench:    132263 ns/iter (+/- 15198)
test benchmarks::bench_quicksort  ... bench:     44623 ns/iter (+/- 9263)
test benchmarks::bench_selsort    ... bench:    699363 ns/iter (+/- 36305)
test benchmarks::bench_shellsort  ... bench:     59090 ns/iter (+/- 3630)
test benchmarks::bench_slice_sort ... bench:     66509 ns/iter (+/- 3064)
```

`bubblesort` is by far the slowest, followed by `selsort`; both unsurprisingly slow.

Interestingly, `quicksort`, `heapsort`, and possibly `shellsort` outperform
`std::slice::MutableOrdSlice::sort()`, at least on this benchmark; the `std` one is, as I understand
it, an optimized mergesort, and is probably faster on more general benchmarks. Here are some things
this benchmark doesn't cover:

  * Comparing with a `compare` function instead of comparision by-value
  * Sorting a partially-sorted list
  * Sorting something with expensive copy operations
  * Sorting a reverse-sorted list

*/

#[warn(non_camel_case_types)]
#[warn(non_snake_case)]
#[warn(unused_qualifications)]
#[warn(non_upper_case_globals)]
#[warn(missing_docs)]

pub mod algorithms;

#[cfg(test)]
mod benchmarks;

// Public traits, for export

/// In-place sorting methods
pub trait Sortable<T : Ord> for Sized? : std::slice::SlicePrelude<T> {
	/// Quicksort, in-place
	fn quicksort(&mut self){algorithms::quicksort(self.as_mut_slice())}
	/// heapsort, in-place
	fn heapsort(&mut self){algorithms::heapsort(self.as_mut_slice())}
	/// bubblesort, in-place
	fn bubblesort(&mut self){algorithms::bubblesort(self.as_mut_slice())}
	/// selection sort, in-place
	fn selsort(&mut self) {algorithms::selsort(self.as_mut_slice())}
	/// shell sort, in-place
	fn shellsort(&mut self) {algorithms::shellsort(self.as_mut_slice())}
}

/// Copy-and-sort methods (i.e., mergesort)
pub trait Sorted<T : Ord + Clone> : std::slice::AsSlice<T> {
	/// merge sort, returning a sorted version
	fn mergesorted(&self) -> Vec<T> {algorithms::mergesort(self.as_slice())}
}

impl<T: Ord> Sortable<T> for [T]{}

impl<'a, T: Ord + Clone> Sorted<T> for &'a [T]{}

<|endoftext|>


<commit_before>//! # RdxSort
//!
//! This crate implements [Radix Sort](https://en.wikipedia.org/wiki/Radix_sort) for slices of
//! different data types, either directly or by exploiting the implementation of other data types.
//!
//! The main reason for implementing yet another sorting algorithm is that most sorting algorithms
//! are comparative methods. To sort data, they rely on a function that compares data elements. It
//! can be proven that this leads to a runtime complexity of `O(n*log(n))` in avarage and `O(n^2)`
//! in the worst case. In contrast to that, Radix Sort exploits that fact that many data types have
//! a limited range of possible values and within that range a limited resolution (that also holds
//! for floating point numbers). For a detailed explaination see the
//! [Wikipedia article](https://en.wikipedia.org/wiki/Radix_sort). The result of this special
//! treatment is a lowered and constant complexity of `O(n*k)` where `k` is the number of fixed
//! rounds required to sort a specific data type.
//!
//!
//! ## Supported Data Types
//!
//! Currently, the following data types are supported:
//!
//! - **bool:** native implementation
//! - **char:** native implementation
//! - **unsigned integers:** native implementation
//! - **signed integers:** splitting into positive and negative parts and using the unsigned
//!   implementation
//! - **floats:** splits data into `-∞`, `(-∞,-0)`, `-0`, `+0`, `(+0,+∞)`, `+∞` and treating the two
//!   ranges as unsigned integer values. [Subnormals](https://en.wikipedia.org/wiki/Denormal_number)
//!   and `NaN`s are not supported!
//!
//!
//! ## Example
//!
//! ```
//! use rdxsort::*;
//!
//! fn main() {
//!     let mut data = vec![2, 10, 0, 1];
//!     data.rdxsort();
//!     assert!(data == vec![0, 1, 2, 10]);
//! }
//! ```
//!
//!
//! ## Performance
//!
//! Of course the lower runtime complexity of Radix Sort shows its power when sorting certain data
//! types. The advantage depends on the size and complexity of the type. While short unsigned
//! integers benifit the most, long types do not show that huge improvements. The following listing
//! shows the runtime in ns required for sorting data sets of different sizes. The data sets are
//! sampled using an uniform distribution. The best algorithm out of the following is marked:
//!
//! - [quicksort](https://crates.io/crates/quicksort)
//! - rdxsort (this crate)
//! - [standard library](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.sort_by)
//!
//! Keep in mind that the results may vary depending on the hardware, compiler version, operating
//! system version and configuration and the weather.
//!
//!
//! ### Small (1'000 elements)
//!
//! For small data sets Radix Sort can be an advantage for data types with up to 32 bits size. For
//! 64 bits, standard library sorting should be preferred.
//!
//! | type | quicksort | rdxsort | std |
//! |-----:|----------:|--------:|----:|
//! | `bool` | `4,070` | **`2,246`** | `26,068` |
//! | `char` | `31,121` | **`20,204`** | `34,051` |
//! | `f32` | `79,714` | **`25,825`** | `77,774` |
//! | `f64` | `80,954` | **`52,262`** | `79,431` |
//! | `i16` | `32,896` | **`12,496`** | `31,167` |
//! | `i32` | `32,854` | **`22,009`** | `30,713` |
//! | `i64` | `33,064` | `53,366` | **`31,669`** |
//! | `i8` | `24,819` | **`8,190`** | `46,281` |
//! | `u16` | `35,252` | **`9,937`** | `33,946` |
//! | `u32` | `33,002` | **`19,202`** | `33,627` |
//! | `u64` | **`32,986`** | `47,739` | `33,204` |
//! | `u8` | `25,425` | **`5,170`** | `47,369` |
//!
//!
//! ### Medium (10'000 elements)
//!
//! For medium data sets Radix Sort could be blindly used for all data types since the disadvantage
//! for types with 64 bits is quite small.
//!
//! | type | quicksort | rdxsort | std |
//! |-----:|----------:|--------:|----:|
//! | `bool` | `52,211` | **`22,083`** | `400,111` |
//! | `char` | `655,553` | **`192,328`** | `508,557` |
//! | `f32` | `1,086,882` | **`230,670`** | `1,117,565` |
//! | `f64` | `1,095,529` | **`417,104`** | `1,152,340` |
//! | `i16` | `665,131` | **`108,128`** | `455,047` |
//! | `i32` | `650,501` | **`202,533`** | `460,097` |
//! | `i64` | `669,643` | **`378,480`** | `470,572` |
//! | `i8` | `383,545` | **`65,521`** | `617,405` |
//! | `u16` | `675,060` | **`78,424`** | `508,264` |
//! | `u32` | `670,348` | **`177,068`** | `511,134` |
//! | `u64` | `664,549` | **`342,935`** | `517,176` |
//! | `u8` | `386,572` | **`37,012`** | `655,377` |
//!
//!
//! ### Large (100'000 elements)
//!
//! For large data sets, Radix Sort is great for all data types.
//!
//! | type | quicksort | rdxsort | std |
//! |-----:|----------:|--------:|----:|
//! | `bool` | `815,653` | **`216,809`** | `4,900,426` |
//! | `char` | `8,131,402` | **`2,538,064`** | `6,333,865` |
//! | `f32` | `13,554,291` | **`3,264,657`** | `14,340,082` |
//! | `f64` | `13,746,190` | **`7,122,334`** | `15,563,206` |
//! | `i16` | `8,235,642` | **`1,248,289`** | `5,575,196` |
//! | `i32` | `8,184,902` | **`2,494,882`** | `5,852,913` |
//! | `i64` | `8,222,482` | **`5,446,507`** | `6,561,292` |
//! | `i8` | `3,664,532` | **`703,288`** | `7,118,816` |
//! | `u16` | `8,272,903` | **`866,833`** | `6,291,101` |
//! | `u32` | `8,193,408` | **`2,051,413`** | `6,395,163` |
//! | `u64` | `8,179,078` | **`4,393,579`** | `7,216,868` |
//! | `u8` | `3,681,361` | **`367,240`** | `7,816,775` |
//!
//!
//! ## Implementing New Types
//!
//! This crate enables you to add support for new types by implementing `RdxSortTemplate`. It
//! describes how data is sorted into buckets and how many rounds of sorting are scheduled.
//!
//! ```
//! use rdxsort::*;
//!
//! // `Clone` is required for `RdxSort`
//! // `PartialEq` is only required for the equality assert, not for the actual sorting
//! #[derive(Clone, PartialEq)]
//! struct Foo {
//!     a: u8,
//!     b: u8,
//! }
//!
//! impl RdxSortTemplate for Foo {
//!     fn cfg_nbuckets() -> usize {
//!         // usually too high, but works as a simple demonstration
//!         // `256 = 2^8`
//!         256
//!     }
//!
//!     fn cfg_nrounds() -> usize {
//!         // one per sub-type
//!         2
//!     }
//!
//!     fn get_bucket(&self, round: usize) -> usize {
//!         // return the least significant digit first
//!         if round == 0 {
//!             self.b as usize
//!         } else {
//!             self.a as usize
//!         }
//!     }
//!
//!     fn reverse(_round: usize, _bucket: usize) -> bool {
//!         // not required in our case
//!         false
//!     }
//! }
//!
//! fn main() {
//!     let mut data = vec![
//!         Foo{a: 5, b: 2},
//!         Foo{a: 0, b: 1},
//!         Foo{a: 5, b: 1},
//!         Foo{a: 0, b: 2},
//!     ];
//!     data.rdxsort();
//!
//!     let reference = vec![
//!         Foo{a: 0, b: 1},
//!         Foo{a: 0, b: 2},
//!         Foo{a: 5, b: 1},
//!         Foo{a: 5, b: 2},
//!     ];
//!     assert!(data == reference);
//! }
//! ```

extern crate core;

/// Radix Sort implementation for some type
pub trait RdxSort {
    /// Execute Radix Sort, overwrites (unsorted) content of the type.
    fn rdxsort(&mut self);
}

#[macro_use] mod template;

mod array;
mod bool;
mod char;
mod floats;
mod signed_integer;
mod tuple;
mod unsigned_integer;

pub use template::RdxSortTemplate;
<commit_msg>extend docs, fix typos<commit_after>//! # RdxSort
//!
//! This crate implements [Radix Sort](https://en.wikipedia.org/wiki/Radix_sort) for slices of
//! different data types, either directly or by exploiting the implementation of other data types.
//!
//! The main reason for implementing yet another sorting algorithm is that most sorting algorithms
//! are comparative methods. To sort data, they rely on a function that compares data elements. It
//! can be proven that this leads to a runtime complexity of `O(n*log(n))` in average and `O(n^2)`
//! in the worst case. In contrast to that, Radix Sort exploits that fact that many data types have
//! a limited range of possible values and within that range a limited resolution (that also holds
//! for floating point numbers). For a detailed explanation see the
//! [Wikipedia article](https://en.wikipedia.org/wiki/Radix_sort). The result of this special
//! treatment is a lowered and constant complexity of `O(n*k)` where `k` is the number of fixed
//! rounds required to sort a specific data type.
//!
//!
//! ## Supported Data Types
//!
//! Currently, the following data types are supported:
//!
//! - **bool:** simple split into 2 junks
//! - **char:** behaves like `u32`
//! - **unsigned integers:** native implementation, depending on the width
//! - **signed integers:** splitting into positive and negative parts and using the unsigned
//!   implementation
//! - **floats:** splits data into `-∞`, `(-∞,-0)`, `-0`, `+0`, `(+0,+∞)`, `+∞` and treating the two
//!   ranges as unsigned integer values. [Subnormals](https://en.wikipedia.org/wiki/Denormal_number)
//!   and `NaN`s are not supported!
//! - **arrays, tuples:** use the implementation of the inner data types
//! - *custom data types...: fill in the provided template trait*
//!
//!
//! ## Example
//!
//! ```
//! use rdxsort::*;
//!
//! fn main() {
//!     let mut data = vec![2, 10, 0, 1];
//!     data.rdxsort();
//!     assert!(data == vec![0, 1, 2, 10]);
//! }
//! ```
//!
//!
//! ## Performance
//!
//! Of course the lower runtime complexity of Radix Sort shows its power when sorting certain data
//! types. The advantage depends on the size and complexity of the type. While short unsigned
//! integers benefit the most, long types do not show that huge improvements. The following listing
//! shows the runtime in ns required for sorting data sets of different sizes. The data sets are
//! sampled using an uniform distribution. The best algorithm out of the following is marked:
//!
//! - [quicksort](https://crates.io/crates/quicksort)
//! - rdxsort (this crate)
//! - [standard library](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.sort_by)
//!
//! Keep in mind that the results may vary depending on the hardware, compiler version, operating
//! system version and configuration and the weather.
//!
//!
//! ### Small (1'000 elements)
//!
//! For small data sets Radix Sort can be an advantage for data types with up to 32 bits size. For
//! 64 bits, standard library sorting should be preferred.
//!
//! | type | quicksort | rdxsort | std |
//! |-----:|----------:|--------:|----:|
//! | `bool` | `4,070` | **`2,246`** | `26,068` |
//! | `char` | `31,121` | **`20,204`** | `34,051` |
//! | `f32` | `79,714` | **`25,825`** | `77,774` |
//! | `f64` | `80,954` | **`52,262`** | `79,431` |
//! | `i16` | `32,896` | **`12,496`** | `31,167` |
//! | `i32` | `32,854` | **`22,009`** | `30,713` |
//! | `i64` | `33,064` | `53,366` | **`31,669`** |
//! | `i8` | `24,819` | **`8,190`** | `46,281` |
//! | `u16` | `35,252` | **`9,937`** | `33,946` |
//! | `u32` | `33,002` | **`19,202`** | `33,627` |
//! | `u64` | **`32,986`** | `47,739` | `33,204` |
//! | `u8` | `25,425` | **`5,170`** | `47,369` |
//!
//!
//! ### Medium (10'000 elements)
//!
//! For medium data sets Radix Sort could be blindly used for all data types since the disadvantage
//! for types with 64 bits is quite small.
//!
//! | type | quicksort | rdxsort | std |
//! |-----:|----------:|--------:|----:|
//! | `bool` | `52,211` | **`22,083`** | `400,111` |
//! | `char` | `655,553` | **`192,328`** | `508,557` |
//! | `f32` | `1,086,882` | **`230,670`** | `1,117,565` |
//! | `f64` | `1,095,529` | **`417,104`** | `1,152,340` |
//! | `i16` | `665,131` | **`108,128`** | `455,047` |
//! | `i32` | `650,501` | **`202,533`** | `460,097` |
//! | `i64` | `669,643` | **`378,480`** | `470,572` |
//! | `i8` | `383,545` | **`65,521`** | `617,405` |
//! | `u16` | `675,060` | **`78,424`** | `508,264` |
//! | `u32` | `670,348` | **`177,068`** | `511,134` |
//! | `u64` | `664,549` | **`342,935`** | `517,176` |
//! | `u8` | `386,572` | **`37,012`** | `655,377` |
//!
//!
//! ### Large (100'000 elements)
//!
//! For large data sets, Radix Sort is great for all data types.
//!
//! | type | quicksort | rdxsort | std |
//! |-----:|----------:|--------:|----:|
//! | `bool` | `815,653` | **`216,809`** | `4,900,426` |
//! | `char` | `8,131,402` | **`2,538,064`** | `6,333,865` |
//! | `f32` | `13,554,291` | **`3,264,657`** | `14,340,082` |
//! | `f64` | `13,746,190` | **`7,122,334`** | `15,563,206` |
//! | `i16` | `8,235,642` | **`1,248,289`** | `5,575,196` |
//! | `i32` | `8,184,902` | **`2,494,882`** | `5,852,913` |
//! | `i64` | `8,222,482` | **`5,446,507`** | `6,561,292` |
//! | `i8` | `3,664,532` | **`703,288`** | `7,118,816` |
//! | `u16` | `8,272,903` | **`866,833`** | `6,291,101` |
//! | `u32` | `8,193,408` | **`2,051,413`** | `6,395,163` |
//! | `u64` | `8,179,078` | **`4,393,579`** | `7,216,868` |
//! | `u8` | `3,681,361` | **`367,240`** | `7,816,775` |
//!
//!
//! ## Implementing New Types
//!
//! This crate enables you to add support for new types by implementing `RdxSortTemplate`. It
//! describes how data is sorted into buckets and how many rounds of sorting are scheduled.
//!
//! ```
//! use rdxsort::*;
//!
//! // `Clone` is required for `RdxSort`
//! // `PartialEq` is only required for the equality assert, not for the actual sorting
//! #[derive(Clone, PartialEq)]
//! struct Foo {
//!     a: u8,
//!     b: u8,
//! }
//!
//! impl RdxSortTemplate for Foo {
//!     // using `#[inline]` is generally recommended since it helps
//!     // the compiler to optimize the sorting algorithm
//!     #[inline]
//!     fn cfg_nbuckets() -> usize {
//!         // usually too high, but works as a simple demonstration
//!         // `256 = 2^8`
//!         256
//!     }
//!
//!     #[inline]
//!     fn cfg_nrounds() -> usize {
//!         // one per sub-type
//!         2
//!     }
//!
//!     #[inline]
//!     fn get_bucket(&self, round: usize) -> usize {
//!         // return the least significant digit first
//!         if round == 0 {
//!             self.b as usize
//!         } else {
//!             self.a as usize
//!         }
//!     }
//!
//!     #[inline]
//!     fn reverse(_round: usize, _bucket: usize) -> bool {
//!         // not required in our case
//!         false
//!     }
//! }
//!
//! fn main() {
//!     let mut data = vec![
//!         Foo{a: 5, b: 2},
//!         Foo{a: 0, b: 1},
//!         Foo{a: 5, b: 1},
//!         Foo{a: 0, b: 2},
//!     ];
//!     data.rdxsort();
//!
//!     let reference = vec![
//!         Foo{a: 0, b: 1},
//!         Foo{a: 0, b: 2},
//!         Foo{a: 5, b: 1},
//!         Foo{a: 5, b: 2},
//!     ];
//!     assert!(data == reference);
//! }
//! ```

extern crate core;

/// Radix Sort implementation for some type
pub trait RdxSort {
    /// Execute Radix Sort, overwrites (unsorted) content of the type.
    fn rdxsort(&mut self);
}

#[macro_use] mod template;

mod array;
mod bool;
mod char;
mod floats;
mod signed_integer;
mod tuple;
mod unsigned_integer;

pub use template::RdxSortTemplate;
<|endoftext|>


<commit_before>extern crate libc;
extern crate glib;
extern crate libsecret_sys;

mod secret_service;
mod secret_collection;
mod secret_item;
mod secret_value;

pub use self::libsecret_sys as ffi;
pub use self::secret_service::SecretService;
pub use self::secret_collection::SecretCollection;
pub use self::secret_item::SecretItem;
pub use self::secret_value::SecretValue;

use std::ptr;
use glib::Error;
use libc::{c_void};
use glib::ffi::{GList};
use glib::object::{Wrapper};
use glib::translate::{ToGlibPtr, FromGlibPtrContainer};
use glib::glib_container::GlibContainer;

pub type SecretResult<T> = Result<T, Error>;

/// This Trait is implemented by objects which can be locked and unlocked
pub trait Lock {
    /// Lock the object.
    fn lock(&self) -> SecretResult<Vec<Self>>;
    /// Unlock the object
    fn unlock(&self) -> SecretResult<Vec<Self>>;
}

impl<W: Wrapper> Lock for W{
    fn lock(&self) -> SecretResult<Vec<Self>>{
        let mut err = ptr::null_mut();
        let mut res = ptr::null_mut();
        //TODO: We can definitely solve this with ToGlibPtrContainer somehow
        let mut arr = GList{
            data: self.as_ref().to_glib_none() as *mut c_void,
            next: ptr::null_mut(),
            prev: ptr::null_mut()
        };
        unsafe {
            let no_locked = ffi::secret_service_lock_sync(ptr::null_mut(), &mut arr, ptr::null_mut(), &mut res, &mut err);
            println!("{}", no_locked);
            if err.is_null() {
                Ok(FromGlibPtrContainer::from_glib_none(res))
            } else {
                Err(Error::wrap(err))
            }
        }
    }

    fn unlock(&self) -> SecretResult<Vec<Self>>{
        let mut err = ptr::null_mut();
        let mut res = ptr::null_mut();
        //TODO: We can definitely solve this with ToGlibPtrContainer somehow
        let mut arr = GList{
            data: self.as_ref().to_glib_none() as *mut c_void,
            next: ptr::null_mut(),
            prev: ptr::null_mut()
        };
        unsafe {
            let no_locked = ffi::secret_service_unlock_sync(ptr::null_mut(), &mut arr, ptr::null_mut(), &mut res, &mut err);
            println!("{}", no_locked);
            if err.is_null() {
                Ok(FromGlibPtrContainer::from_glib_none(res))
            } else {
                Err(Error::wrap(err))
            }
        }
    }
}
<commit_msg>Remove console output from lock and unlock<commit_after>extern crate libc;
extern crate glib;
extern crate libsecret_sys;

mod secret_service;
mod secret_collection;
mod secret_item;
mod secret_value;

pub use self::libsecret_sys as ffi;
pub use self::secret_service::SecretService;
pub use self::secret_collection::SecretCollection;
pub use self::secret_item::SecretItem;
pub use self::secret_value::SecretValue;

use std::ptr;
use glib::Error;
use libc::{c_void};
use glib::ffi::{GList};
use glib::object::{Wrapper};
use glib::translate::{ToGlibPtr, FromGlibPtrContainer};
use glib::glib_container::GlibContainer;

pub type SecretResult<T> = Result<T, Error>;

/// This Trait is implemented by objects which can be locked and unlocked
pub trait Lock {
    /// Lock the object.
    fn lock(&self) -> SecretResult<Vec<Self>>;
    /// Unlock the object
    fn unlock(&self) -> SecretResult<Vec<Self>>;
}

impl<W: Wrapper> Lock for W{
    fn lock(&self) -> SecretResult<Vec<Self>>{
        let mut err = ptr::null_mut();
        let mut res = ptr::null_mut();
        //TODO: We can definitely solve this with ToGlibPtrContainer somehow
        let mut arr = GList{
            data: self.as_ref().to_glib_none() as *mut c_void,
            next: ptr::null_mut(),
            prev: ptr::null_mut()
        };
        unsafe {
            ffi::secret_service_lock_sync(ptr::null_mut(), &mut arr, ptr::null_mut(), &mut res, &mut err);
            if err.is_null() {
                Ok(FromGlibPtrContainer::from_glib_none(res))
            } else {
                Err(Error::wrap(err))
            }
        }
    }

    fn unlock(&self) -> SecretResult<Vec<Self>>{
        let mut err = ptr::null_mut();
        let mut res = ptr::null_mut();
        //TODO: We can definitely solve this with ToGlibPtrContainer somehow
        let mut arr = GList{
            data: self.as_ref().to_glib_none() as *mut c_void,
            next: ptr::null_mut(),
            prev: ptr::null_mut()
        };
        unsafe {
            ffi::secret_service_unlock_sync(ptr::null_mut(), &mut arr, ptr::null_mut(), &mut res, &mut err);
            if err.is_null() {
                Ok(FromGlibPtrContainer::from_glib_none(res))
            } else {
                Err(Error::wrap(err))
            }
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate diesel_codegen;
#[macro_use]
extern crate diesel;
extern crate dotenv;
extern crate r2d2;
extern crate r2d2_diesel;
extern crate rand;
extern crate rocket;

pub mod schema;
pub mod models;

use diesel::pg::PgConnection;
use diesel::Connection;
use r2d2::{Pool, Config};
use r2d2_diesel::ConnectionManager;
use dotenv::dotenv;
use std::env;

pub fn create_db_pool() -> Pool<ConnectionManager<PgConnection>> {
    dotenv().ok();

    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let config = Config::default();
    let manager = ConnectionManager::<PgConnection>::new(database_url);
    Pool::new(config, manager).expect("Failed to create pool.")
}

pub fn establish_connection() -> PgConnection {
    dotenv().ok();
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    PgConnection::establish(&database_url).expect(&format!("Error connecting to {}", database_url))
}
<commit_msg>started to try implementing a pooled connection<commit_after>#[macro_use]
extern crate diesel_codegen;
#[macro_use]
extern crate diesel;
extern crate dotenv;
extern crate r2d2;
extern crate r2d2_diesel;
extern crate rand;
extern crate rocket;

pub mod schema;
pub mod models;

use diesel::pg::PgConnection;
use diesel::Connection;
use r2d2::{Pool, Config};
use r2d2_diesel::ConnectionManager;
use dotenv::dotenv;
use std::env;
use std::borrow::Borrow;

pub fn create_db_pool() -> Pool<ConnectionManager<PgConnection>> {
    dotenv().ok();

    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let config = Config::default();
    let manager = ConnectionManager::<PgConnection>::new(database_url);
    Pool::new(config, manager).expect("Failed to create pool.")
}

pub fn establish_connection() -> PgConnection {
    dotenv().ok();
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    PgConnection::establish(&database_url).expect(&format!("Error connecting to {}", database_url))
}

// pub fn get_connection<'a>(pool: Pool<ConnectionManager<PgConnection>>) -> &'a PgConnection {
//     // TODO lifetime of borrowed value does not fit!
//     let conn: &'a PgConnection = pool.get().expect("Problem accessing db!").borrow();
//     conn
// }
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate comrak;
#[cfg(feature="csv")]
extern crate csv;
extern crate svgbob;
extern crate typed_arena;
use typed_arena::Arena;
use comrak::{format_html, parse_document, ComrakOptions};
use comrak::nodes::{AstNode, NodeHtmlBlock, NodeValue};
use std::collections::HashMap;
use errors::Error;
use svgbob::Grid;

mod errors {
    use std::string::FromUtf8Error;
    #[derive(Debug)]
    pub enum Error {
        ParseError,
        PluginError,
        Utf8Error(FromUtf8Error),
    }
    impl From<FromUtf8Error> for Error {
        fn from(e: FromUtf8Error) -> Self {
            Error::Utf8Error(e)
        }
    }
}

/// convert bob ascii diagrams to svg
fn bob_handler(s: &str, _settings: &Settings) -> Result<String, Error> {
    let grid = Grid::from_str(s, &svgbob::Settings::compact());
    let (width, height) = grid.get_size();
    let svg = grid.get_svg();
    let bob_container = format!(
        "
{}
",
        width, height, svg
    );
    Ok(bob_container)
}

/// convert csv content into html table
#[cfg(feature="csv")]
fn csv_handler(s: &str, settings: &Settings) -> Result<String>{
    let now = std::time::SystemTime::now();
    let mut buff = String::new();
    let mut rdr = csv::Reader::from_string(s);
    buff.push_str("
");
    buff.push_str("
");
    for header in rdr.byte_headers() {
        buff.push_str("
");
        for h in header {
            buff.push_str(&format!("{}	", String::from_utf8(h)?));
        }
        buff.push_str("
");
    }
    buff.push_str("
");
    buff.push_str("
");
    buff.push_str("
");
    for record in rdr.byte_records().filter_map(|r| r.ok()) {
        buff.push_str("
");
        for r in record {
            buff.push_str(&format!("{}	", String::from_utf8(r)?));
        }
        buff.push_str("
");
    }
    buff.push_str("
");
    buff.push_str("
");
    Ok(buff)
}

pub struct Settings {
}

impl Default for Settings {
    fn default() -> Self {
        Settings{}
    }
}

pub fn parse(arg: &str) -> Result<String, Error> {
    parse_with_settings(arg, &Settings::default())
}

pub fn parse_with_settings(arg: &str, settings: &Settings) -> Result<String, Error> {
    let mut plugins: HashMap<String, Box<Fn(&str, &Settings) -> Result<String, Error>>> =
        HashMap::new();
    plugins.insert("bob".into(), Box::new(bob_handler));
    #[cfg(feature="csv")]
    plugins.insert("csv".into(), Box::new(csv_handler));
    let html = parse_via_comrak(arg, &plugins, settings);
    html
}

pub fn parse_bob(arg: &str) -> Result<String, Error> {
    bob_handler(arg, &Settings::default())
}

#[cfg(feature="csv")]
pub fn parse_csv(arg: &str) -> Result<String> {
    csv_handler(arg, &Settings::default())
}

/// Plugin info, format:
/// [<selector>] <plugin_name>[@version][://<URI>]
/// example:
/// #table1 csv://data_file.csv
#[allow(dead_code)]
struct PluginInfo {
    selector: Option<String>,
    plugin_name: String,
    version: Option<String>,
    uri: Option<String>,
}

fn parse_via_comrak(
    arg: &str,
    plugins: &HashMap<String, Box<Fn(&str, &Settings) -> Result<String, Error>>>,
    settings: &Settings,
) -> Result<String, Error> {
    // The returned nodes are created in the supplied Arena, and are bound by its lifetime.
    let arena = Arena::new();
    let option = ComrakOptions {
        hardbreaks: true,
        github_pre_lang: true,
        default_info_string: None,
        width: 0,
        ext_strikethrough: true,
        ext_tagfilter: true,
        ext_table: true,
        ext_autolink: true,
        ext_tasklist: true,
        ext_superscript: false,
        ext_header_ids: None,
        ext_footnotes: true,
        ext_description_lists: true,
        smart: false,
        safe: true,
    };

    let root = parse_document(&arena, arg, &option);

    fn iter_nodes<'a, F>(node: &'a AstNode<'a>, f: &F)
    where
        F: Fn(&'a AstNode<'a>),
    {
        f(node);
        for c in node.children() {
            iter_nodes(c, f);
        }
    }

    iter_nodes(root, &|node| {
        let ref mut value = node.data.borrow_mut().value;
        let new_value = match value {
            &mut NodeValue::CodeBlock(ref codeblock) => {
                let codeblock_info = String::from_utf8(codeblock.info.to_owned()).unwrap();
                match plugins.get(&codeblock_info) {
                    Some(handler) => {
                        let codeblock_literal =
                            String::from_utf8(codeblock.literal.to_owned()).unwrap();
                        match handler(&codeblock_literal, settings) {
                            Ok(out) => NodeValue::HtmlBlock(NodeHtmlBlock {
                                literal: out.as_bytes().to_vec(),
                                block_type: 0,
                            }),
                            Err(_) => NodeValue::CodeBlock(codeblock.clone()),
                        }
                    }
                    None => NodeValue::CodeBlock(codeblock.clone()),
                }
            }
            _ => value.to_owned(),
        };
        *value = new_value;
    });

    let mut html = vec![];

    if let Ok(()) = format_html(root, &ComrakOptions::default(), &mut html) {
        Ok(String::from_utf8(html)?)
    } else {
        Err(Error::ParseError)
    }
}
<commit_msg>Manipulating urls<commit_after>#![deny(warnings)]

extern crate comrak;
#[cfg(feature="csv")]
extern crate csv;
extern crate svgbob;
extern crate typed_arena;
use typed_arena::Arena;
use comrak::{format_html, parse_document, ComrakOptions};
use comrak::nodes::{AstNode, NodeHtmlBlock, NodeValue};
use std::collections::HashMap;
use errors::Error;
use svgbob::Grid;

mod errors {
    use std::string::FromUtf8Error;
    #[derive(Debug)]
    pub enum Error {
        ParseError,
        PluginError,
        Utf8Error(FromUtf8Error),
    }
    impl From<FromUtf8Error> for Error {
        fn from(e: FromUtf8Error) -> Self {
            Error::Utf8Error(e)
        }
    }
}

/// convert bob ascii diagrams to svg
fn bob_handler(s: &str, _settings: &Settings) -> Result<String, Error> {
    let grid = Grid::from_str(s, &svgbob::Settings::compact());
    let (width, height) = grid.get_size();
    let svg = grid.get_svg();
    let bob_container = format!(
        "
{}
",
        width, height, svg
    );
    Ok(bob_container)
}

/// convert csv content into html table
#[cfg(feature="csv")]
fn csv_handler(s: &str, settings: &Settings) -> Result<String>{
    let now = std::time::SystemTime::now();
    let mut buff = String::new();
    let mut rdr = csv::Reader::from_string(s);
    buff.push_str("
");
    buff.push_str("
");
    for header in rdr.byte_headers() {
        buff.push_str("
");
        for h in header {
            buff.push_str(&format!("{}	", String::from_utf8(h)?));
        }
        buff.push_str("
");
    }
    buff.push_str("
");
    buff.push_str("
");
    buff.push_str("
");
    for record in rdr.byte_records().filter_map(|r| r.ok()) {
        buff.push_str("
");
        for r in record {
            buff.push_str(&format!("{}	", String::from_utf8(r)?));
        }
        buff.push_str("
");
    }
    buff.push_str("
");
    buff.push_str("
");
    Ok(buff)
}

pub struct Settings {
}

impl Default for Settings {
    fn default() -> Self {
        Settings{}
    }
}

pub fn parse(arg: &str) -> Result<String, Error> {
    parse_with_settings(arg, &Settings::default())
}

pub fn parse_with_settings(arg: &str, settings: &Settings) -> Result<String, Error> {
    let mut plugins: HashMap<String, Box<Fn(&str, &Settings) -> Result<String, Error>>> =
        HashMap::new();
    plugins.insert("bob".into(), Box::new(bob_handler));
    #[cfg(feature="csv")]
    plugins.insert("csv".into(), Box::new(csv_handler));
    let html = parse_via_comrak(arg, &plugins, settings);
    html
}

pub fn parse_bob(arg: &str) -> Result<String, Error> {
    bob_handler(arg, &Settings::default())
}

#[cfg(feature="csv")]
pub fn parse_csv(arg: &str) -> Result<String> {
    csv_handler(arg, &Settings::default())
}

/// Plugin info, format:
/// [<selector>] <plugin_name>[@version][://<URI>]
/// example:
/// #table1 csv://data_file.csv
#[allow(dead_code)]
struct PluginInfo {
    selector: Option<String>,
    plugin_name: String,
    version: Option<String>,
    uri: Option<String>,
}

fn parse_via_comrak(
    arg: &str,
    plugins: &HashMap<String, Box<Fn(&str, &Settings) -> Result<String, Error>>>,
    settings: &Settings,
) -> Result<String, Error> {
    // The returned nodes are created in the supplied Arena, and are bound by its lifetime.
    let arena = Arena::new();
    let option = ComrakOptions {
        hardbreaks: true,
        github_pre_lang: true,
        default_info_string: None,
        width: 0,
        ext_strikethrough: true,
        ext_tagfilter: true,
        ext_table: true,
        ext_autolink: true,
        ext_tasklist: true,
        ext_superscript: false,
        ext_header_ids: None,
        ext_footnotes: true,
        ext_description_lists: true,
        smart: false,
        safe: true,
    };

    let root = parse_document(&arena, arg, &option);

    fn iter_nodes<'a, F>(node: &'a AstNode<'a>, f: &F)
    where
        F: Fn(&'a AstNode<'a>),
    {
        f(node);
        for c in node.children() {
            iter_nodes(c, f);
        }
    }

    iter_nodes(root, &|node| {
        let ref mut value = node.data.borrow_mut().value;
        let new_value = match value {
            &mut NodeValue::CodeBlock(ref codeblock) => {
                let codeblock_info = String::from_utf8(codeblock.info.to_owned()).unwrap();
                if let Some(handler) =  plugins.get(&codeblock_info) {
                    let codeblock_literal =
                        String::from_utf8(codeblock.literal.to_owned()).unwrap();
                    match handler(&codeblock_literal, settings) {
                        Ok(out) => NodeValue::HtmlBlock(NodeHtmlBlock {
                            literal: out.as_bytes().to_vec(),
                            block_type: 0,
                        }),
                        Err(_) => NodeValue::CodeBlock(codeblock.clone()),
                    }
                }else{
                    value.clone()
                }
            }
            &mut NodeValue::Link(ref nodelink) => {
                if let Ok(url) = String::from_utf8(nodelink.url.clone()){
                    let new_url = format!("/#/md/{}",url);
                    let mut new_nodelink = nodelink.clone();
                    new_nodelink.url = new_url.into_bytes();
                    NodeValue::Link(new_nodelink)
                }else{
                    value.clone()
                }
            }
            _ => value.clone(),
        };
        *value = new_value;
    });

    let mut html = vec![];

    if let Ok(()) = format_html(root, &ComrakOptions::default(), &mut html) {
        Ok(String::from_utf8(html)?)
    } else {
        Err(Error::ParseError)
    }
}
<|endoftext|>


<commit_before>extern crate termion;

pub mod computer;
mod sixel;
pub mod compiler;
<commit_msg>Link to the original paper describing the Chifir virtual computer.<commit_after>//! Chifir is a virtual computer based on the Tien Nguyen and Alan Kay's paper,
//! ["The Cuneiform Tablets of 2015"][paper].
//!
//!
//! [paper]: http://www.vpri.org/pdf/tr2015004_cuneiform.pdf "Tien Nguyen and Alan Kay (Viewpoints Research Insitute): The Cuneiform Tablets of 2015"
extern crate termion;

pub mod computer;
mod sixel;
pub mod compiler;
<|endoftext|>


<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

use std::io::Cursor;
use std::mem;
use std::result;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use kvm;
use kvm_sys::kvm_lapic_state;
use sys_util;

#[derive(Debug)]
pub enum Error {
    GetLapic(sys_util::Error),
    SetLapic(sys_util::Error),
}

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

// Defines poached from apicdef.h kernel header.
const APIC_LVT0: usize = 0x350;
const APIC_LVT1: usize = 0x360;
const APIC_MODE_NMI: u32 = 0x4;
const APIC_MODE_EXTINT: u32 = 0x7;

fn get_klapic_reg(klapic: &kvm_lapic_state, reg_offset: usize) -> u32 {
    let sliceu8 = unsafe {
        // This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
        // Cursors are only readable on arrays of u8, not i8(c_char).
        mem::transmute::<&[i8], &[u8]>(&klapic.regs[reg_offset..])
    };
    let mut reader = Cursor::new(sliceu8);
    // Following call can't fail if the offsets defined above are correct.
    reader.read_u32::<LittleEndian>().unwrap()
}

fn set_klapic_reg(klapic: &mut kvm_lapic_state, reg_offset: usize, value: u32) {
    let sliceu8 = unsafe {
        // This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
        // Cursors are only readable on arrays of u8, not i8(c_char).
        mem::transmute::<&mut [i8], &mut [u8]>(&mut klapic.regs[reg_offset..])
    };
    let mut writer = Cursor::new(sliceu8);
    // Following call can't fail if the offsets defined above are correct.
    writer.write_u32::<LittleEndian>(value).unwrap()
}

fn set_apic_delivery_mode(reg: u32, mode: u32) -> u32 {
    (((reg) & !0x700) | ((mode) << 8))
}

/// Configures LAPICs.  LAPIC0 is set for external interrupts, LAPIC1 is set for NMI.
///
/// # Arguments
/// * `vcpu` - The VCPU object to configure.
pub fn set_lint(vcpu: &kvm::VcpuFd) -> Result<()> {
    let mut klapic = vcpu.get_lapic().map_err(Error::GetLapic)?;

    let lvt_lint0 = get_klapic_reg(&klapic, APIC_LVT0);
    set_klapic_reg(
        &mut klapic,
        APIC_LVT0,
        set_apic_delivery_mode(lvt_lint0, APIC_MODE_EXTINT),
    );
    let lvt_lint1 = get_klapic_reg(&klapic, APIC_LVT1);
    set_klapic_reg(
        &mut klapic,
        APIC_LVT1,
        set_apic_delivery_mode(lvt_lint1, APIC_MODE_NMI),
    );

    vcpu.set_lapic(&klapic).map_err(Error::SetLapic)
}

#[cfg(test)]
mod tests {
    extern crate rand;
    use self::rand::Rng;

    use super::*;
    use kvm::Kvm;

    const KVM_APIC_REG_SIZE: usize = 0x400;

    #[test]
    fn test_set_and_get_klapic_reg() {
        let reg_offset = 0x340;
        let mut klapic = kvm_lapic_state::default();
        set_klapic_reg(&mut klapic, reg_offset, 3);
        let value = get_klapic_reg(&klapic, reg_offset);
        assert_eq!(value, 3);
    }

    #[test]
    #[should_panic]
    fn test_set_and_get_klapic_out_of_bounds() {
        let reg_offset = KVM_APIC_REG_SIZE + 10;
        let mut klapic = kvm_lapic_state::default();
        set_klapic_reg(&mut klapic, reg_offset, 3);
    }

    #[test]
    fn test_apic_delivery_mode() {
        let mut rng = rand::thread_rng();
        let mut v: Vec<u32> = (0..20).map(|_| rng.gen::<u32>()).collect();

        v.iter_mut()
            .for_each(|x| *x = set_apic_delivery_mode(*x, 2));
        let after: Vec<u32> = v.iter().map(|x| ((*x & !0x700) | ((2) << 8))).collect();
        assert_eq!(v, after);
    }

    #[test]
    fn test_setlint() {
        let kvm = Kvm::new().unwrap();
        assert!(kvm.check_extension(kvm::Cap::Irqchip));
        let vm = kvm.create_vm().unwrap();
        //the get_lapic ioctl will fail if there is no irqchip created beforehand.
        assert!(vm.create_irq_chip().is_ok());
        let vcpu = vm.create_vcpu(0).unwrap();
        let klapic_before: kvm_lapic_state = vcpu.get_lapic().unwrap();

        // Compute the value that is expected to represent LVT0 and LVT1.
        let lint0 = get_klapic_reg(&klapic_before, APIC_LVT0);
        let lint1 = get_klapic_reg(&klapic_before, APIC_LVT1);
        let lint0_mode_expected = set_apic_delivery_mode(lint0, APIC_MODE_EXTINT);
        let lint1_mode_expected = set_apic_delivery_mode(lint1, APIC_MODE_NMI);

        set_lint(&vcpu).unwrap();

        // Compute the value that represents LVT0 and LVT1 after set_lint.
        let klapic_actual: kvm_lapic_state = vcpu.get_lapic().unwrap();
        let lint0_mode_actual = get_klapic_reg(&klapic_actual, APIC_LVT0);
        let lint1_mode_actual = get_klapic_reg(&klapic_actual, APIC_LVT1);
        assert_eq!(lint0_mode_expected, lint0_mode_actual);
        assert_eq!(lint1_mode_expected, lint1_mode_actual);
    }

    #[test]
    fn test_setlint_fails() {
        let kvm = Kvm::new().unwrap();
        let vm = kvm.create_vm().unwrap();
        let vcpu = vm.create_vcpu(0).unwrap();
        // 'get_lapic' ioctl triggered by the 'set_lint' function will fail if there is no
        // irqchip created beforehand.
        assert!(set_lint(&vcpu).is_err());
    }
}
<commit_msg>x86_64: replace unwrap with expect<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

use std::io::Cursor;
use std::mem;
use std::result;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use kvm;
use kvm_sys::kvm_lapic_state;
use sys_util;

#[derive(Debug)]
pub enum Error {
    GetLapic(sys_util::Error),
    SetLapic(sys_util::Error),
}

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

// Defines poached from apicdef.h kernel header.
const APIC_LVT0: usize = 0x350;
const APIC_LVT1: usize = 0x360;
const APIC_MODE_NMI: u32 = 0x4;
const APIC_MODE_EXTINT: u32 = 0x7;

fn get_klapic_reg(klapic: &kvm_lapic_state, reg_offset: usize) -> u32 {
    let sliceu8 = unsafe {
        // This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
        // Cursors are only readable on arrays of u8, not i8(c_char).
        mem::transmute::<&[i8], &[u8]>(&klapic.regs[reg_offset..])
    };
    let mut reader = Cursor::new(sliceu8);
    // Following call can't fail if the offsets defined above are correct.
    reader
        .read_u32::<LittleEndian>()
        .expect("Failed to read klapic register")
}

fn set_klapic_reg(klapic: &mut kvm_lapic_state, reg_offset: usize, value: u32) {
    let sliceu8 = unsafe {
        // This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
        // Cursors are only readable on arrays of u8, not i8(c_char).
        mem::transmute::<&mut [i8], &mut [u8]>(&mut klapic.regs[reg_offset..])
    };
    let mut writer = Cursor::new(sliceu8);
    // Following call can't fail if the offsets defined above are correct.
    writer
        .write_u32::<LittleEndian>(value)
        .expect("Failed to write klapic register")
}

fn set_apic_delivery_mode(reg: u32, mode: u32) -> u32 {
    (((reg) & !0x700) | ((mode) << 8))
}

/// Configures LAPICs.  LAPIC0 is set for external interrupts, LAPIC1 is set for NMI.
///
/// # Arguments
/// * `vcpu` - The VCPU object to configure.
pub fn set_lint(vcpu: &kvm::VcpuFd) -> Result<()> {
    let mut klapic = vcpu.get_lapic().map_err(Error::GetLapic)?;

    let lvt_lint0 = get_klapic_reg(&klapic, APIC_LVT0);
    set_klapic_reg(
        &mut klapic,
        APIC_LVT0,
        set_apic_delivery_mode(lvt_lint0, APIC_MODE_EXTINT),
    );
    let lvt_lint1 = get_klapic_reg(&klapic, APIC_LVT1);
    set_klapic_reg(
        &mut klapic,
        APIC_LVT1,
        set_apic_delivery_mode(lvt_lint1, APIC_MODE_NMI),
    );

    vcpu.set_lapic(&klapic).map_err(Error::SetLapic)
}

#[cfg(test)]
mod tests {
    extern crate rand;
    use self::rand::Rng;

    use super::*;
    use kvm::Kvm;

    const KVM_APIC_REG_SIZE: usize = 0x400;

    #[test]
    fn test_set_and_get_klapic_reg() {
        let reg_offset = 0x340;
        let mut klapic = kvm_lapic_state::default();
        set_klapic_reg(&mut klapic, reg_offset, 3);
        let value = get_klapic_reg(&klapic, reg_offset);
        assert_eq!(value, 3);
    }

    #[test]
    #[should_panic]
    fn test_set_and_get_klapic_out_of_bounds() {
        let reg_offset = KVM_APIC_REG_SIZE + 10;
        let mut klapic = kvm_lapic_state::default();
        set_klapic_reg(&mut klapic, reg_offset, 3);
    }

    #[test]
    fn test_apic_delivery_mode() {
        let mut rng = rand::thread_rng();
        let mut v: Vec<u32> = (0..20).map(|_| rng.gen::<u32>()).collect();

        v.iter_mut()
            .for_each(|x| *x = set_apic_delivery_mode(*x, 2));
        let after: Vec<u32> = v.iter().map(|x| ((*x & !0x700) | ((2) << 8))).collect();
        assert_eq!(v, after);
    }

    #[test]
    fn test_setlint() {
        let kvm = Kvm::new().unwrap();
        assert!(kvm.check_extension(kvm::Cap::Irqchip));
        let vm = kvm.create_vm().unwrap();
        //the get_lapic ioctl will fail if there is no irqchip created beforehand.
        assert!(vm.create_irq_chip().is_ok());
        let vcpu = vm.create_vcpu(0).unwrap();
        let klapic_before: kvm_lapic_state = vcpu.get_lapic().unwrap();

        // Compute the value that is expected to represent LVT0 and LVT1.
        let lint0 = get_klapic_reg(&klapic_before, APIC_LVT0);
        let lint1 = get_klapic_reg(&klapic_before, APIC_LVT1);
        let lint0_mode_expected = set_apic_delivery_mode(lint0, APIC_MODE_EXTINT);
        let lint1_mode_expected = set_apic_delivery_mode(lint1, APIC_MODE_NMI);

        set_lint(&vcpu).unwrap();

        // Compute the value that represents LVT0 and LVT1 after set_lint.
        let klapic_actual: kvm_lapic_state = vcpu.get_lapic().unwrap();
        let lint0_mode_actual = get_klapic_reg(&klapic_actual, APIC_LVT0);
        let lint1_mode_actual = get_klapic_reg(&klapic_actual, APIC_LVT1);
        assert_eq!(lint0_mode_expected, lint0_mode_actual);
        assert_eq!(lint1_mode_expected, lint1_mode_actual);
    }

    #[test]
    fn test_setlint_fails() {
        let kvm = Kvm::new().unwrap();
        let vm = kvm.create_vm().unwrap();
        let vcpu = vm.create_vcpu(0).unwrap();
        // 'get_lapic' ioctl triggered by the 'set_lint' function will fail if there is no
        // irqchip created beforehand.
        assert!(set_lint(&vcpu).is_err());
    }
}
<|endoftext|>


<commit_before>use serial::Serial;
use timer::Timer;
use std::io::File;

//mod serial;
//mod timer;

static WRAM_SIZE: uint = 0x2000;
//static ZRAM_SIZE: uint = 0x7F;
static ZRAM_SIZE: uint = 0x100;

pub struct MMU {
	priv rom: ~[u8],
	priv ram: ~[u8],
	priv wram: ~[u8, ..WRAM_SIZE],
	priv zram: ~[u8, ..ZRAM_SIZE],
	inte: u8,
	intf: u8,
	priv serial: Serial,
	priv timer: Timer,
}

impl MMU {
	pub fn new(romname: &str) -> MMU {
		let mut res = MMU {
			wram: ~([0, ..WRAM_SIZE]),
			zram: ~([0, ..ZRAM_SIZE]),
			rom: ~[],
			ram: ~[],
			inte: 0,
			intf: 0,
			serial: Serial::new(),
			timer: Timer::new(),
		};

		res.rom = File::open(&Path::new(romname)).read_to_end();

		res.wb(0xFF05, 0);
		res.wb(0xFF06, 0);
		res.wb(0xFF07, 0);
		res.wb(0xFF40, 0x91);
		res.wb(0xFF42, 0);
		res.wb(0xFF43, 0);
		res.wb(0xFF45, 0);
		res.wb(0xFF47, 0xFC);
		res.wb(0xFF48, 0xFF);
		res.wb(0xFF49, 0xFF);
		res.wb(0xFF4A, 0);
		res.wb(0xFF4B, 0);

		return res;
	}

	pub fn cycle(&mut self, ticks: uint) {
		self.timer.step(ticks);
		self.intf |= self.timer.interrupt;
		self.timer.interrupt = 0;
	}

	pub fn rb(&self, address: u16) -> u8 {
		match address {
			0x0000 .. 0x7FFF => self.readrom(address),
			//0x8000 .. 0x9FFF => { 0 }, // VRAM
			//0xA000 .. 0xBFFF => { 0 }, // ext ram
			0xC000 .. 0xFDFF => self.wram[address & 0x1FFF],
			//0xFF00 => { 0 }, // Keypad
			0xFF01 .. 0xFF02 => self.serial.rb(address),
			0xFF04 .. 0xFF07 => self.timer.rb(address),
			0xFF0F => self.intf,
			//0xFF40 .. 0xFF4B => { 0 }, // GPU
			//0xFF80 .. 0xFFFE => self.zram[address - 0xFF80],
			0xFFFF => self.inte,
			0xFF00 .. 0xFFFE => self.zram[address - 0xFF00],
			_ => fail!("rb not implemented for {:X}", address),
		}
	}

	pub fn rw(&self, address: u16) -> u16 {
		(self.rb(address) as u16) | (self.rb(address + 1) as u16 << 8)
	}

	fn readrom(&self, address: u16) -> u8 {
		// TODO: MBC
		return self.rom[address & 0x7FFF];
	}

	pub fn wb(&mut self, address: u16, value: u8) {
		match address {
			0x0000 .. 0x7FFF => self.writerom(address, value),
			0x8000 .. 0x9FFF => {}, // VRAM
			0xA000 .. 0xBFFF => {}, // ext ram
			0xC000 .. 0xFDFF => self.wram[address & 0x1FFF] = value,
			//0xFF00 => {}, // Keypad
			0xFF01 .. 0xFF02 => { self.serial.wb(address, value); }, // Serial console
			0xFF04 .. 0xFF07 => { self.timer.wb(address, value); }, // Timer
			//0xFF40 .. 0xFF4B => {}, // GPU
			0xFF4D => {}, // CGB speed switch
			//0xFF10 .. 0xFF26 => {}, // Sound
			0xFF0F => self.intf = value,
			//0xFF80 .. 0xFFFE => self.zram[address - 0xFF80] = value,
			0xFFFF => self.inte = value,
			0xFF00 .. 0xFFFE => self.zram[address - 0xFF00] = value,
			_ => fail!("wb not implemented for {:X}", address),
		};
	}

	pub fn ww(&mut self, address: u16, value: u16) {
		self.wb(address, (value & 0xFF) as u8);
		self.wb(address + 1, (value >> 8) as u8);
	}

	fn writerom(&mut self, _address: u16, _value: u8) {
		// TODO
	}
}

<commit_msg>Implemented part of MBC1<commit_after>use serial::Serial;
use timer::Timer;
use std::io::File;

static WRAM_SIZE: uint = 0x2000;
//static ZRAM_SIZE: uint = 0x7F;
static ZRAM_SIZE: uint = 0x100;

pub struct MMU {
	priv rom: ~[u8],
	priv ram: ~[u8],
	priv wram: ~[u8, ..WRAM_SIZE],
	priv zram: ~[u8, ..ZRAM_SIZE],
	inte: u8,
	intf: u8,
	priv serial: Serial,
	priv timer: Timer,
	priv mbc: MBC,
	priv rombank: u16,
	priv rambank: u16,
	priv mbcmode: bool,
	priv ramon: bool,
}

enum MBC {
	Direct,
	MBC1,
	Unknown,
}

impl MMU {
	pub fn new(romname: &str) -> MMU {
		let mut res = MMU {
			wram: ~([0, ..WRAM_SIZE]),
			zram: ~([0, ..ZRAM_SIZE]),
			rom: ~[],
			ram: ~[],
			inte: 0,
			intf: 0,
			serial: Serial::new(),
			timer: Timer::new(),
			mbc: Unknown,
			rombank: 1,
			rambank: 0,
			mbcmode: false,
			ramon: false,
		};

		res.rom = File::open(&Path::new(romname)).read_to_end();
		res.setmbc();
		match res.mbc {
			Unknown => { fail!("Unsupported MBC detected"); },
			_ => {},
		};

		res.setram();

		res.wb(0xFF05, 0);
		res.wb(0xFF06, 0);
		res.wb(0xFF07, 0);
		res.wb(0xFF40, 0x91);
		res.wb(0xFF42, 0);
		res.wb(0xFF43, 0);
		res.wb(0xFF45, 0);
		res.wb(0xFF47, 0xFC);
		res.wb(0xFF48, 0xFF);
		res.wb(0xFF49, 0xFF);
		res.wb(0xFF4A, 0);
		res.wb(0xFF4B, 0);

		return res;
	}

	fn setmbc(&mut self) {
		self.mbc =
		if self.rom.len() < 0x147 { Unknown }
		else {
			match self.rom[0x147] {
				0x00 => Direct,
				0x01 => MBC1,
				_ => Unknown,
			}
		};
	}

	fn setram(&mut self) {
		if self.rom.len() < 0x149 { fail!("Rom size to small"); };
		let ramsize = match self.rom[0x149] {
			0 => 0,
			1 => 0x800,
			2 => 0x2000,
			3 => 0x8000,
			_ => 0,
		};
		self.ram.grow(ramsize, &0);
	}

	pub fn cycle(&mut self, ticks: uint) {
		self.timer.step(ticks);
		self.intf |= self.timer.interrupt;
		self.timer.interrupt = 0;
	}

	pub fn rb(&self, address: u16) -> u8 {
		match address {
			0x0000 .. 0x3FFF => self.rom[address],
			0x4000 .. 0x7FFF => self.readrombank(address),
			//0x8000 .. 0x9FFF => { 0 }, // VRAM
			0xA000 .. 0xBFFF => self.readram(address),
			0xC000 .. 0xFDFF => self.wram[address & 0x1FFF],
			//0xFF00 => { 0 }, // Keypad
			0xFF01 .. 0xFF02 => self.serial.rb(address),
			0xFF04 .. 0xFF07 => self.timer.rb(address),
			0xFF0F => self.intf,
			//0xFF40 .. 0xFF4B => { 0 }, // GPU
			//0xFF80 .. 0xFFFE => self.zram[address - 0xFF80],
			0xFFFF => self.inte,
			0xFF00 .. 0xFFFE => self.zram[address - 0xFF00],
			_ => fail!("rb not implemented for {:X}", address),
		}
	}

	pub fn rw(&self, address: u16) -> u16 {
		(self.rb(address) as u16) | (self.rb(address + 1) as u16 << 8)
	}

	fn readrombank(&self, address: u16) -> u8 {
		match self.mbc {
			Unknown => { 0 },
			Direct => self.rom[address],
			MBC1 =>   self.rom[(self.rombank * 0x4000) | (address & 0x3FFF)],
		}
	}

	fn ramaddress(&self, address: u16) -> Option<u16> {
		match self.mbc {
			Unknown => None,
			Direct => Some(address),
			MBC1 => if !self.ramon || !self.mbcmode { None } else {
				Some(self.rambank * 0x2000 | address)
			},
		}
	}

	fn readram(&self, address: u16) -> u8 {
		match self.ramaddress(address) {
			None => 0,
			Some(n) => self.ram[n],
		}
	}

	pub fn wb(&mut self, address: u16, value: u8) {
		match address {
			0x0000 .. 0x7FFF => self.writerom(address, value),
			0x8000 .. 0x9FFF => {}, // VRAM
			0xA000 .. 0xBFFF => self.writeram(address, value),
			0xC000 .. 0xFDFF => self.wram[address & 0x1FFF] = value,
			//0xFF00 => {}, // Keypad
			0xFF01 .. 0xFF02 => { self.serial.wb(address, value); }, // Serial console
			0xFF04 .. 0xFF07 => { self.timer.wb(address, value); }, // Timer
			//0xFF40 .. 0xFF4B => {}, // GPU
			0xFF4D => {}, // CGB speed switch
			//0xFF10 .. 0xFF26 => {}, // Sound
			0xFF0F => self.intf = value,
			//0xFF80 .. 0xFFFE => self.zram[address - 0xFF80] = value,
			0xFFFF => self.inte = value,
			0xFF00 .. 0xFFFE => self.zram[address - 0xFF00] = value,
			_ => fail!("wb not implemented for {:X}", address),
		};
	}

	pub fn ww(&mut self, address: u16, value: u16) {
		self.wb(address, (value & 0xFF) as u8);
		self.wb(address + 1, (value >> 8) as u8);
	}

	fn writerom(&mut self, address: u16, value: u8) {
		match self.mbc {
			Unknown => {},
			Direct => {},
			MBC1 => {
				match address {
					0x0000 .. 0x1FFF => { self.ramon = (value == 0xA); },
					0x2000 .. 0x3FFF => {
						self.rombank = (self.rombank & 0x60) | (match value as u16 & 0x1F { 0 => 1, n => n });
					},
					0x4000 .. 0x5FFF => {
						if !self.mbcmode { (self.rombank & 0x1F) | (((value as u16) & 0x03) << 5); }
						else { self.rambank = value as u16 & 0x03; }
					},
					0x6000 .. 0x7FFF => { self.mbcmode = ((value & 1) == 1); }
					_ => { fail!(""); },
				}
			}
		}
	}

	fn writeram(&mut self, address: u16, value: u8) {
		match self.ramaddress(address) {
			None => {},
			Some(n) => self.ram[n] = value,
		};
	}
}

<|endoftext|>