<commit_before>extern crate nasm_rs;
use std::env;
use std::path::PathBuf;

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

    let target = env::var("TARGET").unwrap();

    let arch_name = target.split("-").next()
                          .expect("Couldn't parse target triple!");

    let src_path = env::var("CARGO_MANIFEST_DIR")
                    .map(|path| PathBuf::from(path).join("src") )
                    .unwrap();

    let asm_dir = src_path.as_path()
                    .join("arch")
                    .join(arch_name);

    let asm_files = asm_dir.read_dir().unwrap()
                        .filter(|entry| match entry {
                            &Ok(ref file) =>
                                if let Some(ext) = file.path().extension() {
                                    "asm" == ext
                                } else {
                                    false
                                }
                          , &Err(_) => false
                        })
                        .map(|entry| entry.unwrap().path())
                        .collect::<Vec<PathBuf>>();

    nasm_rs::compile_library_args( "libboot.a"
                                 , asm_files.iter()
                                            .map(|path| path.to_str().unwrap())
                                            .collect::<Vec<&str>>()
                                            .as_slice()
                                 , &[ "-felf64" ]);

    println!("cargo:rustc-link-search=native={}", out_dir);
    println!("cargo:rustc-link-lib=static=boot");

    for asm_file in asm_files {
        println!("cargo:rerun-if-changed={}", asm_file.to_str().unwrap());
    }

}
<commit_msg>[build] document build.rs<commit_after>extern crate nasm_rs;
use std::env;
use std::path::PathBuf;

fn main() {

    let out_dir // the output directory for compiled binaries
        = env::var("OUT_DIR").unwrap();

    let src_path // path to the source code directory
        = env::var("CARGO_MANIFEST_DIR")
            .map(|path| PathBuf::from(path).join("src") )
            .unwrap();

    let target // target triple
        = env::var("TARGET").unwrap();

    let arch_name // extract the architecture name from the target triple
        = target.split("-").next()
                .expect("Couldn't parse target triple!");

    let asm_dir // construct the path to the arch-specific source directory...
        = src_path.as_path()        //...by concatenating the source path...
                  .join("arch")     // ...the "arch" dir...
                  .join(arch_name); //...and the name of the arch we're building

    let asm_files // get the name of each assembly file in the arch dir
        = asm_dir.read_dir().unwrap()
                 .filter(|entry| match entry {
                        &Ok(ref file) =>
                            if let Some(ext) = file.path().extension() {
                                "asm" == ext
                            } else {
                                false
                            }
                      , &Err(_) => false
                    })
                 .map(|entry| entry.unwrap().path())
                 .collect::<Vec<PathBuf>>();

    // invoke NASM to compile and archive the assembly files
    nasm_rs::compile_library_args( "libboot.a"
                                 , // convert asm paths into &str
                                    asm_files.iter()
                                             .map(|path| path.to_str().unwrap())
                                             .collect::<Vec<&str>>()
                                             .as_slice()
                                 , // TODO: determine this from target triple
                                   &[ "-felf64" ]);

    println!("cargo:rustc-link-search=native={}", out_dir);
    println!("cargo:rustc-link-lib=static=boot");

    // for each assembly file detected, tell cargo to re-run
    // if that file has changed
    for asm_file in asm_files {
        println!("cargo:rerun-if-changed={}", asm_file.to_str().unwrap());
    }

}
<|endoftext|>


<commit_before>extern crate gcc;

fn main() {
    gcc::Config::new()
        .include("decNumber")
        .file("decNumber/decContext.c")
        .file("decNumber/decDouble.c")
        .file("decNumber/decNumber.c")
        .file("decNumber/decPacked.c")
        .file("decNumber/decQuad.c")
        .file("decNumber/decSingle.c")
        .file("decNumber/decimal128.c")
        .file("decNumber/decimal32.c")
        .file("decNumber/decimal64.c")
        .define("DECNUMDIGITS", Some("34"))
        .compile("libdecNumber.a");
}
<commit_msg>Add correct endianess support.<commit_after>extern crate gcc;

fn main() {
    let litend = if cfg!(target_endian = "little") {
        "1"
    } else {
        "0"
    };
    gcc::Config::new()
        .include("decNumber")
        .file("decNumber/decContext.c")
        .file("decNumber/decDouble.c")
        .file("decNumber/decNumber.c")
        .file("decNumber/decPacked.c")
        .file("decNumber/decQuad.c")
        .file("decNumber/decSingle.c")
        .file("decNumber/decimal128.c")
        .file("decNumber/decimal32.c")
        .file("decNumber/decimal64.c")
        .define("DECNUMDIGITS", Some("34"))
        .define("DECLITEND", Some(litend))
        .compile("libdecNumber.a");
}
<|endoftext|>


<commit_before>use rustc_cfg::Cfg;
use std::env;

#[cfg(not(target_arch = "x86_64"))]
fn asm(_out_dir: &str) {}

#[cfg(target_arch = "x86_64")]
fn asm(out_dir: &str) {
    use std::process::Command;

    println!("cargo:rerun-if-changed=src/asm/x86_64/trampoline.asm");

    let status = Command::new("nasm")
        .arg("-f").arg("bin")
        .arg("-o").arg(format!("{}/trampoline", out_dir))
        .arg("src/asm/x86_64/trampoline.asm")
        .status()
        .expect("failed to run nasm");
    if ! status.success() {
        panic!("nasm failed with exit status {}", status);
    }
}

fn main() {
    println!("cargo:rustc-env=TARGET={}", env::var("TARGET").unwrap());

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

    // Build pre kstart init asm code for aarch64
    let cfg = Cfg::new(env::var_os("TARGET").unwrap()).unwrap();
    if cfg.target_arch == "aarch64" {
        println!("cargo:rerun-if-changed=src/arch/aarch64/init/pre_kstart/early_init.S");
        cc::Build::new()
            .file("src/arch/aarch64/init/pre_kstart/early_init.S")
            .target("aarch64-unknown-redox")
            .compile("early_init");
    }
}
<commit_msg>Disable building aarch64 asm<commit_after>use rustc_cfg::Cfg;
use std::env;

#[cfg(not(target_arch = "x86_64"))]
fn asm(_out_dir: &str) {}

#[cfg(target_arch = "x86_64")]
fn asm(out_dir: &str) {
    use std::process::Command;

    println!("cargo:rerun-if-changed=src/asm/x86_64/trampoline.asm");

    let status = Command::new("nasm")
        .arg("-f").arg("bin")
        .arg("-o").arg(format!("{}/trampoline", out_dir))
        .arg("src/asm/x86_64/trampoline.asm")
        .status()
        .expect("failed to run nasm");
    if ! status.success() {
        panic!("nasm failed with exit status {}", status);
    }
}

fn main() {
    println!("cargo:rustc-env=TARGET={}", env::var("TARGET").unwrap());

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

    // Build pre kstart init asm code for aarch64
    /*TODO: do we need any of this?
    let cfg = Cfg::new(env::var_os("TARGET").unwrap()).unwrap();
    if cfg.target_arch == "aarch64" {
        println!("cargo:rerun-if-changed=src/arch/aarch64/init/pre_kstart/early_init.S");
        cc::Build::new()
            .file("src/arch/aarch64/init/pre_kstart/early_init.S")
            .target("aarch64-unknown-redox")
            .compile("early_init");
    }
    */
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("hello.rs");
    let mut f = File::create(&dest_path).unwrap();

    f.write_all(b"
        pub fn message() -> &'static str {
            \"Hello, World!\"
        }
    ").unwrap();
}
<commit_msg>remove build script<commit_after><|endoftext|>


<commit_before>use futures::task::{ArcWake, Context, Poll, Waker};
use futures::Stream;
use std::cmp::Ordering;
use std::collections::{BinaryHeap, HashMap};
use std::pin::Pin;
use std::sync::atomic;
use std::sync::{Arc, Mutex};

struct QueueInner<S, K> {
    ready_queue: BinaryHeap<PriorityStream<S, K>>,
    pending_streams: HashMap<usize, PriorityStream<S, K>>,
    waker: Option<Waker>,
}

pub struct FairQueue<S, K> {
    counter: atomic::AtomicUsize,
    inner: Arc<Mutex<QueueInner<S, K>>>,
}

struct StreamWaker<S, K> {
    inner: Arc<Mutex<QueueInner<S, K>>>,
    index: usize,
}

impl<S, K> ArcWake for StreamWaker<S, K>
where
    S: Send,
    K: Send,
{
    fn wake_by_ref(arc_self: &Arc<Self>) {
        let mut inner = arc_self.inner.lock().unwrap();
        let s = inner
            .pending_streams
            .remove(&arc_self.index)
            .expect("Corrupted index given to waker");
        inner.ready_queue.push(s);
        if let Some(waker) = inner.waker.take() {
            waker.wake_by_ref();
        }
    }
}

struct PriorityStream<S, K> {
    priority: usize,
    key: K,
    stream: Pin<Box<S>>,
}

impl<S, K> PartialEq for PriorityStream<S, K> {
    fn eq(&self, other: &Self) -> bool {
        self.priority.eq(&other.priority)
    }
}
impl<S, K> Eq for PriorityStream<S, K> {}

impl<S, K> PartialOrd for PriorityStream<S, K> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        other.priority.partial_cmp(&self.priority)
    }
}
impl<S, K> Ord for PriorityStream<S, K> {
    fn cmp(&self, other: &Self) -> Ordering {
        other.priority.cmp(&self.priority)
    }
}

impl<S, T, K> Stream for FairQueue<S, K>
where
    T: Send,
    S: Stream<Item = T> + Send,
    K: Unpin + Clone + Send,
{
    type Item = (K, T);

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let stream = self.get_mut();
        loop {
            let mut s = {
                let mut inner = stream.inner.lock().unwrap();
                inner.waker = Some(cx.waker().clone());
                match inner.ready_queue.pop() {
                    Some(s) => s,
                    None => {
                        return if !inner.pending_streams.is_empty() {
                            Poll::Pending
                        } else {
                            Poll::Ready(None)
                        }
                    }
                }
            };

            let waker = Arc::new(StreamWaker {
                inner: stream.inner.clone(),
                index: s.priority,
            });
            let waker_ref = futures::task::waker_ref(&waker);
            let mut cx = Context::from_waker(&waker_ref);
            match s.stream.as_mut().poll_next(&mut cx) {
                Poll::Ready(Some(res)) => {
                    s.priority = stream.counter.fetch_add(1, atomic::Ordering::Relaxed);
                    let item = Some((s.key.clone(), res));
                    stream.inner.lock().unwrap().ready_queue.push(s);
                    return Poll::Ready(item);
                }
                Poll::Ready(None) => continue,
                Poll::Pending => {
                    stream
                        .inner
                        .lock()
                        .unwrap()
                        .pending_streams
                        .insert(s.priority, s);
                    return Poll::Pending;
                }
            }
        }
    }
}

impl<S, K> FairQueue<S, K> {
    pub fn new() -> Self {
        Self {
            counter: atomic::AtomicUsize::new(0),
            inner: Arc::new(Mutex::new(QueueInner {
                ready_queue: BinaryHeap::new(),
                pending_streams: HashMap::new(),
                waker: None,
            })),
        }
    }

    pub fn insert(&mut self, k: K, s: S) {
        let mut inner = self.inner.lock().unwrap();
        inner.ready_queue.push(PriorityStream {
            priority: self.counter.fetch_add(1, atomic::Ordering::Relaxed),
            key: k,
            stream: Box::pin(s),
        });
        match &inner.waker {
            Some(w) => w.wake_by_ref(),
            None => (),
        };
    }
}

#[cfg(test)]
mod test {
    use crate::fair_queue::FairQueue;
    use futures::StreamExt;

    #[tokio::test]
    async fn test_fair_queue_ready() {
        let a = futures::stream::iter(vec!["a1", "a2", "a3"]);
        let b = futures::stream::iter(vec!["b1", "b2", "b3"]);
        let c = futures::stream::iter(vec!["c1", "c2", "c3"]);

        let mut f_queue: FairQueue<_, u64> = FairQueue::new();
        f_queue.insert(1, a);
        f_queue.insert(2, b);
        f_queue.insert(3, c);

        let mut results = Vec::new();
        while let Some(i) = f_queue.next().await {
            results.push(i);
        }
        assert_eq!(
            results,
            vec![
                (1, "a1"),
                (2, "b1"),
                (3, "c1"),
                (1, "a2"),
                (2, "b2"),
                (3, "c2"),
                (1, "a3"),
                (2, "b3"),
                (3, "c3")
            ]
        );
    }

    #[tokio::test]
    async fn test_fair_queue_different_size() {
        let a = futures::stream::iter(vec!["a1", "a2", "a3"]);
        let b = futures::stream::iter(vec!["b1"]);
        let c = futures::stream::iter(vec!["c1", "c2"]);

        let mut f_queue: FairQueue<_, u64> = FairQueue::new();
        f_queue.insert(1, a);
        f_queue.insert(2, b);
        f_queue.insert(3, c);

        let mut results = Vec::new();
        while let Some(i) = f_queue.next().await {
            results.push(i);
        }
        assert_eq!(
            results,
            vec![
                (1, "a1"),
                (2, "b1"),
                (3, "c1"),
                (1, "a2"),
                (3, "c2"),
                (1, "a3")
            ]
        );
    }
}
<commit_msg>Fixed concurrency logic issue in FairQueue<commit_after>use futures::task::{ArcWake, Context, Poll, Waker};
use futures::Stream;
use std::cmp::Ordering;
use std::collections::{BinaryHeap, HashMap};
use std::pin::Pin;
use std::sync::atomic;
use std::sync::{Arc, Mutex};

struct QueueInner<S, K> {
    ready_queue: BinaryHeap<PriorityStream<S, K>>,
    pending_streams: HashMap<usize, PriorityStream<S, K>>,
    // See wake_by_ref for details
    weak_up_processing: Option<usize>,
    waker: Option<Waker>,
}

pub struct FairQueue<S, K> {
    counter: atomic::AtomicUsize,
    inner: Arc<Mutex<QueueInner<S, K>>>,
}

struct StreamWaker<S, K> {
    inner: Arc<Mutex<QueueInner<S, K>>>,
    index: usize,
}

impl<S, K> ArcWake for StreamWaker<S, K>
where
    S: Send,
    K: Send,
{
    fn wake_by_ref(arc_self: &Arc<Self>) {
        let mut inner = arc_self.inner.lock().unwrap();
        match inner.pending_streams.remove(&arc_self.index) {
            None => {
                // This is a tricky part..
                // Some streams call waker inside the poll_next method.
                // At that moment stream is neither ready or pending.
                // We leave it's priority hang for the moment.
                // It's responsibility of the FairQueue::poll_next to take this into account.
                // In such case it will put stream as ready (cause it explicitly asked for it)
                inner.weak_up_processing = Some(arc_self.index);
            }
            Some(s) => {
                inner.ready_queue.push(s);
            }
        };
        if let Some(waker) = inner.waker.take() {
            waker.wake_by_ref();
        }
    }
}

struct PriorityStream<S, K> {
    priority: usize,
    key: K,
    stream: Pin<Box<S>>,
}

impl<S, K> PartialEq for PriorityStream<S, K> {
    fn eq(&self, other: &Self) -> bool {
        self.priority.eq(&other.priority)
    }
}
impl<S, K> Eq for PriorityStream<S, K> {}

impl<S, K> PartialOrd for PriorityStream<S, K> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        other.priority.partial_cmp(&self.priority)
    }
}
impl<S, K> Ord for PriorityStream<S, K> {
    fn cmp(&self, other: &Self) -> Ordering {
        other.priority.cmp(&self.priority)
    }
}

impl<S, T, K> Stream for FairQueue<S, K>
where
    T: Send,
    S: Stream<Item = T> + Send,
    K: Unpin + Clone + Send,
{
    type Item = (K, T);

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let stream = self.get_mut();
        loop {
            let mut s = {
                let mut inner = stream.inner.lock().unwrap();
                inner.waker = Some(cx.waker().clone());
                match inner.ready_queue.pop() {
                    Some(s) => s,
                    None => {
                        return if !inner.pending_streams.is_empty() {
                            Poll::Pending
                        } else {
                            Poll::Ready(None)
                        }
                    }
                }
            };

            let waker = Arc::new(StreamWaker {
                inner: stream.inner.clone(),
                index: s.priority,
            });
            let waker_ref = futures::task::waker_ref(&waker);
            let mut cx = Context::from_waker(&waker_ref);
            match s.stream.as_mut().poll_next(&mut cx) {
                Poll::Ready(Some(res)) => {
                    s.priority = stream.counter.fetch_add(1, atomic::Ordering::Relaxed);
                    let item = Some((s.key.clone(), res));
                    let mut inner = stream.inner.lock().unwrap();
                    inner.ready_queue.push(s);
                    inner.weak_up_processing = None;
                    return Poll::Ready(item);
                }
                Poll::Ready(None) => continue,
                Poll::Pending => {
                    let mut inner = stream.inner.lock().unwrap();
                    match inner.weak_up_processing.take() {
                        None => {
                            inner.pending_streams.insert(s.priority, s);
                        }
                        Some(prio) => {
                            assert_eq!(prio, s.priority);
                            inner.ready_queue.push(s);
                        }
                    };
                    return Poll::Pending;
                }
            }
        }
    }
}

impl<S, K> FairQueue<S, K> {
    pub fn new() -> Self {
        Self {
            counter: atomic::AtomicUsize::new(0),
            inner: Arc::new(Mutex::new(QueueInner {
                ready_queue: BinaryHeap::new(),
                pending_streams: HashMap::new(),
                weak_up_processing: None,
                waker: None,
            })),
        }
    }

    pub fn insert(&mut self, k: K, s: S) {
        let mut inner = self.inner.lock().unwrap();
        inner.ready_queue.push(PriorityStream {
            priority: self.counter.fetch_add(1, atomic::Ordering::Relaxed),
            key: k,
            stream: Box::pin(s),
        });
        match &inner.waker {
            Some(w) => w.wake_by_ref(),
            None => (),
        };
    }
}

#[cfg(test)]
mod test {
    use crate::fair_queue::FairQueue;
    use futures::StreamExt;

    #[tokio::test]
    async fn test_fair_queue_ready() {
        let a = futures::stream::iter(vec!["a1", "a2", "a3"]);
        let b = futures::stream::iter(vec!["b1", "b2", "b3"]);
        let c = futures::stream::iter(vec!["c1", "c2", "c3"]);

        let mut f_queue: FairQueue<_, u64> = FairQueue::new();
        f_queue.insert(1, a);
        f_queue.insert(2, b);
        f_queue.insert(3, c);

        let mut results = Vec::new();
        while let Some(i) = f_queue.next().await {
            results.push(i);
        }
        assert_eq!(
            results,
            vec![
                (1, "a1"),
                (2, "b1"),
                (3, "c1"),
                (1, "a2"),
                (2, "b2"),
                (3, "c2"),
                (1, "a3"),
                (2, "b3"),
                (3, "c3")
            ]
        );
    }

    #[tokio::test]
    async fn test_fair_queue_different_size() {
        let a = futures::stream::iter(vec!["a1", "a2", "a3"]);
        let b = futures::stream::iter(vec!["b1"]);
        let c = futures::stream::iter(vec!["c1", "c2"]);

        let mut f_queue: FairQueue<_, u64> = FairQueue::new();
        f_queue.insert(1, a);
        f_queue.insert(2, b);
        f_queue.insert(3, c);

        let mut results = Vec::new();
        while let Some(i) = f_queue.next().await {
            results.push(i);
        }
        assert_eq!(
            results,
            vec![
                (1, "a1"),
                (2, "b1"),
                (3, "c1"),
                (1, "a2"),
                (3, "c2"),
                (1, "a3")
            ]
        );
    }
}
<|endoftext|>


<commit_before>use reqwest::{
    Error as ReqwestError,
    header::InvalidHeaderValue,
    Response,
    StatusCode,
    Url,
    UrlError,
};
use std::{
    error::Error as StdError,
    fmt::{
        Display,
        Formatter,
        Result as FmtResult
    }
};

#[derive(Clone, Serialize, Deserialize, PartialEq)]
pub struct DiscordJsonError {
    pub code: isize,
    pub message: String,
    #[serde(skip)]
    non_exhaustive: (),
}

impl std::fmt::Debug for DiscordJsonError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "\"{}\"", self.message)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct ErrorResponse {
    pub status_code: StatusCode,
    pub url: Url,
    pub error: DiscordJsonError,
}

impl From<Response> for ErrorResponse {
    fn from(mut r: Response) -> Self {
        ErrorResponse {
            status_code: r.status(),
            url: r.url().clone(),
            error: r.json().unwrap_or_else(|_| DiscordJsonError {
                code: -1,
                message: "[Serenity] No correct json was recieved!".to_string(),
                non_exhaustive: (),
            }),
        }
    }
}

#[derive(Debug)]
pub enum Error {
    /// When a non-successful status code was received for a request.
    UnsuccessfulRequest(ErrorResponse),
    /// When the decoding of a ratelimit header could not be properly decoded
    /// into an `i64`.
    RateLimitI64,
    /// When the decoding of a ratelimit header could not be properly decoded
    /// from UTF-8.
    RateLimitUtf8,
    /// When parsing an URL failed due to invalid input.
    Url(UrlError),
    /// Header value contains invalid input.
    InvalidHeader(InvalidHeaderValue),
    /// Reqwest's Error contain information on why sending a request failed.
    Request(ReqwestError),
    #[doc(hidden)]
    __Nonexhaustive,
}

impl From<ReqwestError> for Error {
    fn from(error: ReqwestError) -> Error {
        Error::Request(error)
    }
}

impl From<UrlError> for Error {
    fn from(error: UrlError) -> Error {
        Error::Url(error)
    }
}

impl From<InvalidHeaderValue> for Error {
    fn from(error: InvalidHeaderValue) -> Error {
        Error::InvalidHeader(error)
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.write_str(self.description()) }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self {
            Error::UnsuccessfulRequest(ref e) => &e.error.message,
            Error::RateLimitI64 => "Error decoding a header into an i64",
            Error::RateLimitUtf8 => "Error decoding a header from UTF-8",
            Error::Url(_) => "Provided URL is incorrect.",
            Error::InvalidHeader(_) => "Provided value is an invalid header value.",
            Error::Request(_) => "Error while sending HTTP request.",
            Error::__Nonexhaustive => unreachable!(),
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use http_crate::response::Builder;
    use reqwest::r#async::ResponseBuilderExt;

    #[test]
    fn test_error_response_into() {
        let error = DiscordJsonError {
            code: 43121215,
            message: String::from("This is a Ferris error"),
            non_exhaustive: (),
        };

        let mut builder = Builder::new();
        builder.status(403);
        builder.url(String::from("https://ferris.crab").parse().unwrap());
        let body_string = serde_json::to_string(&error).unwrap();
        let response = builder.body(body_string.into_bytes()).unwrap();

        let reqwest_response: reqwest::Response = response.into();
        let error_response: ErrorResponse = reqwest_response.into();

        let known = ErrorResponse {
            status_code: reqwest::StatusCode::from_u16(403).unwrap(),
            url: String::from("https://ferris.crab").parse().unwrap(),
            error,
        };

        assert_eq!(error_response, known);
    }
}
<commit_msg>Fix typo<commit_after>use reqwest::{
    Error as ReqwestError,
    header::InvalidHeaderValue,
    Response,
    StatusCode,
    Url,
    UrlError,
};
use std::{
    error::Error as StdError,
    fmt::{
        Display,
        Formatter,
        Result as FmtResult
    }
};

#[derive(Clone, Serialize, Deserialize, PartialEq)]
pub struct DiscordJsonError {
    pub code: isize,
    pub message: String,
    #[serde(skip)]
    non_exhaustive: (),
}

impl std::fmt::Debug for DiscordJsonError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "\"{}\"", self.message)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct ErrorResponse {
    pub status_code: StatusCode,
    pub url: Url,
    pub error: DiscordJsonError,
}

impl From<Response> for ErrorResponse {
    fn from(mut r: Response) -> Self {
        ErrorResponse {
            status_code: r.status(),
            url: r.url().clone(),
            error: r.json().unwrap_or_else(|_| DiscordJsonError {
                code: -1,
                message: "[Serenity] No correct json was received!".to_string(),
                non_exhaustive: (),
            }),
        }
    }
}

#[derive(Debug)]
pub enum Error {
    /// When a non-successful status code was received for a request.
    UnsuccessfulRequest(ErrorResponse),
    /// When the decoding of a ratelimit header could not be properly decoded
    /// into an `i64`.
    RateLimitI64,
    /// When the decoding of a ratelimit header could not be properly decoded
    /// from UTF-8.
    RateLimitUtf8,
    /// When parsing an URL failed due to invalid input.
    Url(UrlError),
    /// Header value contains invalid input.
    InvalidHeader(InvalidHeaderValue),
    /// Reqwest's Error contain information on why sending a request failed.
    Request(ReqwestError),
    #[doc(hidden)]
    __Nonexhaustive,
}

impl From<ReqwestError> for Error {
    fn from(error: ReqwestError) -> Error {
        Error::Request(error)
    }
}

impl From<UrlError> for Error {
    fn from(error: UrlError) -> Error {
        Error::Url(error)
    }
}

impl From<InvalidHeaderValue> for Error {
    fn from(error: InvalidHeaderValue) -> Error {
        Error::InvalidHeader(error)
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.write_str(self.description()) }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self {
            Error::UnsuccessfulRequest(ref e) => &e.error.message,
            Error::RateLimitI64 => "Error decoding a header into an i64",
            Error::RateLimitUtf8 => "Error decoding a header from UTF-8",
            Error::Url(_) => "Provided URL is incorrect.",
            Error::InvalidHeader(_) => "Provided value is an invalid header value.",
            Error::Request(_) => "Error while sending HTTP request.",
            Error::__Nonexhaustive => unreachable!(),
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use http_crate::response::Builder;
    use reqwest::r#async::ResponseBuilderExt;

    #[test]
    fn test_error_response_into() {
        let error = DiscordJsonError {
            code: 43121215,
            message: String::from("This is a Ferris error"),
            non_exhaustive: (),
        };

        let mut builder = Builder::new();
        builder.status(403);
        builder.url(String::from("https://ferris.crab").parse().unwrap());
        let body_string = serde_json::to_string(&error).unwrap();
        let response = builder.body(body_string.into_bytes()).unwrap();

        let reqwest_response: reqwest::Response = response.into();
        let error_response: ErrorResponse = reqwest_response.into();

        let known = ErrorResponse {
            status_code: reqwest::StatusCode::from_u16(403).unwrap(),
            url: String::from("https://ferris.crab").parse().unwrap(),
            error,
        };

        assert_eq!(error_response, known);
    }
}
<|endoftext|>


<commit_before>use core::num::Wrapping;
use core::ops::{Add, Mul};

/// Defines an additive identity element for `Self`.
///
/// # Laws
///
/// ```{.text}
/// a + 0 = a       ∀ a ∈ Self
/// 0 + a = a       ∀ a ∈ Self
/// ```
pub trait Zero: Sized + Add<Self, Output = Self> {
    /// Returns the additive identity element of `Self`, `0`.
    /// # Purity
    ///
    /// This function should return the same result at all times regardless of
    /// external mutable state, for example values stored in TLS or in
    /// `static mut`s.
    // This cannot be an associated constant, because of bignums.
    fn zero() -> Self;

    /// Sets `self` to the additive identity element of `Self`, `0`.
    /// Returns `&mut self` to enable method chaining.
    fn set_zero(&mut self) {
        *self = Zero::zero();
    }

    /// Returns `true` if `self` is equal to the additive identity.
    #[inline]
    fn is_zero(&self) -> bool;
}

macro_rules! zero_impl {
    ($t:ty, $v:expr) => {
        impl Zero for $t {
            #[inline]
            fn zero() -> $t {
                $v
            }
            #[inline]
            fn is_zero(&self) -> bool {
                *self == $v
            }
        }
    };
}

zero_impl!(usize, 0);
zero_impl!(u8, 0);
zero_impl!(u16, 0);
zero_impl!(u32, 0);
zero_impl!(u64, 0);
#[cfg(has_i128)]
zero_impl!(u128, 0);

zero_impl!(isize, 0);
zero_impl!(i8, 0);
zero_impl!(i16, 0);
zero_impl!(i32, 0);
zero_impl!(i64, 0);
#[cfg(has_i128)]
zero_impl!(i128, 0);

zero_impl!(f32, 0.0);
zero_impl!(f64, 0.0);

impl<T: Zero> Zero for Wrapping<T>
where
    Wrapping<T>: Add<Output = Wrapping<T>>,
{
    fn is_zero(&self) -> bool {
        self.0.is_zero()
    }

    fn set_zero(&mut self) {
        self.0.set_zero();
    }

    fn zero() -> Self {
        Wrapping(T::zero())
    }
}

/// Defines a multiplicative identity element for `Self`.
///
/// # Laws
///
/// ```{.text}
/// a * 1 = a       ∀ a ∈ Self
/// 1 * a = a       ∀ a ∈ Self
/// ```
pub trait One: Sized + Mul<Self, Output = Self> {
    /// Returns the multiplicative identity element of `Self`, `1`.
    ///
    /// # Purity
    ///
    /// This function should return the same result at all times regardless of
    /// external mutable state, for example values stored in TLS or in
    /// `static mut`s.
    // This cannot be an associated constant, because of bignums.
    fn one() -> Self;

    /// Sets `self` to the multiplicative identity element of `Self`, `1`.
    fn set_one(&mut self) {
        *self = One::one();
    }

    /// Returns `true` if `self` is equal to the multiplicative identity.
    ///
    /// For performance reasons, it's best to implement this manually.
    /// After a semver bump, this method will be required, and the
    /// `where Self: PartialEq` bound will be removed.
    #[inline]
    fn is_one(&self) -> bool
    where
        Self: PartialEq,
    {
        *self == Self::one()
    }
}

macro_rules! one_impl {
    ($t:ty, $v:expr) => {
        impl One for $t {
            #[inline]
            fn one() -> $t {
                $v
            }
            #[inline]
            fn is_one(&self) -> bool {
                *self == $v
            }
        }
    };
}

one_impl!(usize, 1);
one_impl!(u8, 1);
one_impl!(u16, 1);
one_impl!(u32, 1);
one_impl!(u64, 1);
#[cfg(has_i128)]
one_impl!(u128, 1);

one_impl!(isize, 1);
one_impl!(i8, 1);
one_impl!(i16, 1);
one_impl!(i32, 1);
one_impl!(i64, 1);
#[cfg(has_i128)]
one_impl!(i128, 1);

one_impl!(f32, 1.0);
one_impl!(f64, 1.0);

impl<T: One> One for Wrapping<T>
where
    Wrapping<T>: Mul<Output = Wrapping<T>>,
{
    fn set_one(&mut self) {
        self.0.set_one();
    }

    fn one() -> Self {
        Wrapping(T::one())
    }
}

// Some helper functions provided for backwards compatibility.

/// Returns the additive identity, `0`.
#[inline(always)]
pub fn zero<T: Zero>() -> T {
    Zero::zero()
}

/// Returns the multiplicative identity, `1`.
#[inline(always)]
pub fn one<T: One>() -> T {
    One::one()
}

#[test]
fn wrapping_identities() {
    macro_rules! test_wrapping_identities {
        ($($t:ty)+) => {
            $(
                assert_eq!(zero::<$t>(), zero::<Wrapping<$t>>().0);
                assert_eq!(one::<$t>(), one::<Wrapping<$t>>().0);
                assert_eq!((0 as $t).is_zero(), Wrapping(0 as $t).is_zero());
                assert_eq!((1 as $t).is_zero(), Wrapping(1 as $t).is_zero());
            )+
        };
    }

    test_wrapping_identities!(isize i8 i16 i32 i64 usize u8 u16 u32 u64);
}

#[test]
fn wrapping_is_zero() {
    fn require_zero<T: Zero>(_: &T) {}
    require_zero(&Wrapping(42));
}
#[test]
fn wrapping_is_one() {
    fn require_one<T: One>(_: &T) {}
    require_one(&Wrapping(42));
}
<commit_msg>Remove a stale doc comment on `set_zero()`<commit_after>use core::num::Wrapping;
use core::ops::{Add, Mul};

/// Defines an additive identity element for `Self`.
///
/// # Laws
///
/// ```{.text}
/// a + 0 = a       ∀ a ∈ Self
/// 0 + a = a       ∀ a ∈ Self
/// ```
pub trait Zero: Sized + Add<Self, Output = Self> {
    /// Returns the additive identity element of `Self`, `0`.
    /// # Purity
    ///
    /// This function should return the same result at all times regardless of
    /// external mutable state, for example values stored in TLS or in
    /// `static mut`s.
    // This cannot be an associated constant, because of bignums.
    fn zero() -> Self;

    /// Sets `self` to the additive identity element of `Self`, `0`.
    fn set_zero(&mut self) {
        *self = Zero::zero();
    }

    /// Returns `true` if `self` is equal to the additive identity.
    #[inline]
    fn is_zero(&self) -> bool;
}

macro_rules! zero_impl {
    ($t:ty, $v:expr) => {
        impl Zero for $t {
            #[inline]
            fn zero() -> $t {
                $v
            }
            #[inline]
            fn is_zero(&self) -> bool {
                *self == $v
            }
        }
    };
}

zero_impl!(usize, 0);
zero_impl!(u8, 0);
zero_impl!(u16, 0);
zero_impl!(u32, 0);
zero_impl!(u64, 0);
#[cfg(has_i128)]
zero_impl!(u128, 0);

zero_impl!(isize, 0);
zero_impl!(i8, 0);
zero_impl!(i16, 0);
zero_impl!(i32, 0);
zero_impl!(i64, 0);
#[cfg(has_i128)]
zero_impl!(i128, 0);

zero_impl!(f32, 0.0);
zero_impl!(f64, 0.0);

impl<T: Zero> Zero for Wrapping<T>
where
    Wrapping<T>: Add<Output = Wrapping<T>>,
{
    fn is_zero(&self) -> bool {
        self.0.is_zero()
    }

    fn set_zero(&mut self) {
        self.0.set_zero();
    }

    fn zero() -> Self {
        Wrapping(T::zero())
    }
}

/// Defines a multiplicative identity element for `Self`.
///
/// # Laws
///
/// ```{.text}
/// a * 1 = a       ∀ a ∈ Self
/// 1 * a = a       ∀ a ∈ Self
/// ```
pub trait One: Sized + Mul<Self, Output = Self> {
    /// Returns the multiplicative identity element of `Self`, `1`.
    ///
    /// # Purity
    ///
    /// This function should return the same result at all times regardless of
    /// external mutable state, for example values stored in TLS or in
    /// `static mut`s.
    // This cannot be an associated constant, because of bignums.
    fn one() -> Self;

    /// Sets `self` to the multiplicative identity element of `Self`, `1`.
    fn set_one(&mut self) {
        *self = One::one();
    }

    /// Returns `true` if `self` is equal to the multiplicative identity.
    ///
    /// For performance reasons, it's best to implement this manually.
    /// After a semver bump, this method will be required, and the
    /// `where Self: PartialEq` bound will be removed.
    #[inline]
    fn is_one(&self) -> bool
    where
        Self: PartialEq,
    {
        *self == Self::one()
    }
}

macro_rules! one_impl {
    ($t:ty, $v:expr) => {
        impl One for $t {
            #[inline]
            fn one() -> $t {
                $v
            }
            #[inline]
            fn is_one(&self) -> bool {
                *self == $v
            }
        }
    };
}

one_impl!(usize, 1);
one_impl!(u8, 1);
one_impl!(u16, 1);
one_impl!(u32, 1);
one_impl!(u64, 1);
#[cfg(has_i128)]
one_impl!(u128, 1);

one_impl!(isize, 1);
one_impl!(i8, 1);
one_impl!(i16, 1);
one_impl!(i32, 1);
one_impl!(i64, 1);
#[cfg(has_i128)]
one_impl!(i128, 1);

one_impl!(f32, 1.0);
one_impl!(f64, 1.0);

impl<T: One> One for Wrapping<T>
where
    Wrapping<T>: Mul<Output = Wrapping<T>>,
{
    fn set_one(&mut self) {
        self.0.set_one();
    }

    fn one() -> Self {
        Wrapping(T::one())
    }
}

// Some helper functions provided for backwards compatibility.

/// Returns the additive identity, `0`.
#[inline(always)]
pub fn zero<T: Zero>() -> T {
    Zero::zero()
}

/// Returns the multiplicative identity, `1`.
#[inline(always)]
pub fn one<T: One>() -> T {
    One::one()
}

#[test]
fn wrapping_identities() {
    macro_rules! test_wrapping_identities {
        ($($t:ty)+) => {
            $(
                assert_eq!(zero::<$t>(), zero::<Wrapping<$t>>().0);
                assert_eq!(one::<$t>(), one::<Wrapping<$t>>().0);
                assert_eq!((0 as $t).is_zero(), Wrapping(0 as $t).is_zero());
                assert_eq!((1 as $t).is_zero(), Wrapping(1 as $t).is_zero());
            )+
        };
    }

    test_wrapping_identities!(isize i8 i16 i32 i64 usize u8 u16 u32 u64);
}

#[test]
fn wrapping_is_zero() {
    fn require_zero<T: Zero>(_: &T) {}
    require_zero(&Wrapping(42));
}
#[test]
fn wrapping_is_one() {
    fn require_one<T: One>(_: &T) {}
    require_one(&Wrapping(42));
}
<|endoftext|>


<commit_before>use std::sync::{Mutex, Arc};
use std::net::{SocketAddr, ToSocketAddrs};
use std::collections::VecDeque;
use std::error::Error;
use std::mem;
use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;
use piston::input::{Button, Key, MouseButton, RenderArgs, UpdateArgs};

use std::{thread, time};
use std::net::TcpStream;
use network::{Command, Message};

use bincode::{serialize_into, deserialize_from, Infinite};

use state::{UnitId, ClientId, WorldState, GameState, UNIT_SIZE};
use shapes::Shape;
use colors;
use colors::{BLACK, ORANGE, WHITE};

pub mod menu;
pub mod error;

use self::menu::Menu;

pub struct NetworkClient {
    pub game_state: Arc<Mutex<Option<GameState>>>,
    server_addr: SocketAddr,
    stream: Option<TcpStream>,
    commands: Arc<Mutex<VecDeque<Command>>>,
}

impl NetworkClient {
    pub fn new<T: ToSocketAddrs>(server_addrs: T,
                                 game_state: Arc<Mutex<Option<GameState>>>,
                                 commands: Arc<Mutex<VecDeque<Command>>>) -> NetworkClient {
        let server_addr = server_addrs.to_socket_addrs().unwrap().next().unwrap();
        NetworkClient {
            game_state: game_state,
            server_addr: server_addr,
            stream: None,
            commands: commands,
        }
    }

    pub fn connect(&mut self) -> Result<(ClientId, WorldState), Box<Error>>  {
        let mut stream = TcpStream::connect(self.server_addr)?;
        serialize_into(&mut stream, &Message::ClientHello, Infinite)?;
        let server_hello = deserialize_from(&mut stream, Infinite);

        self.stream = Some(stream);
        if let Ok(Message::ServerHello(client_id, world_state)) = server_hello {
            Ok((client_id, world_state))
        } else {
            Err("Could not connect to server".into())
        }
    }

    pub fn update(&self) {
        let stream = self.stream.as_ref().expect("Stream not here :(");
        let mut command_stream = stream.try_clone().unwrap();
        let commands = self.commands.clone();

        // Command sender loop
        thread::spawn(move || {
            loop {
                let command = {
                    let mut commands = commands.lock().unwrap();
                    commands.pop_front()
                };
                command.map(|cmd| {
                    println!("Got command: {:?}", cmd);
                    //let cmd = Message::Command(Command::Move(0.into(), [100f64, 100f64]));
                    serialize_into(&mut command_stream, &Message::Command(cmd), Infinite)
                        .unwrap_or_else(|e|println!("Sending command failed: {}", e));
                });
                thread::sleep(time::Duration::from_millis(10));
            }
        });

        let mut game_state_stream = stream.try_clone().unwrap();
        let game_state = self.game_state.clone();
        thread::spawn(move || {
            loop {
                let game_state_server: Result<GameState,_> = deserialize_from(
                    &mut game_state_stream,
                    Infinite);
                match game_state_server {
                    Ok(game) => {
                        //println!("{:?}", game);
                        let mut game_state_lock = game_state.lock().unwrap();
                        *game_state_lock = Some(game);

                    }
                    Err(e) => {
                        println!("{:?}", e);
                        thread::sleep(time::Duration::from_millis(200));
                    }
                }
            }
        });
    }
}

#[derive(Clone, Debug)]
pub enum State {
    Menu,
    Error(error::Message),
    Running,
}

pub struct App {
    pub gl: GlGraphics, // OpenGL drawing backend.
    pub world_state: Option<WorldState>,
    pub game_state_server: Arc<Mutex<Option<GameState>>>,
    pub game_state: GameState,
    pub selected_units: Vec<UnitId>,
    pub commands: Arc<Mutex<VecDeque<Command>>>,
    pub cursor: [f64; 2],
    pub state: State,
    zoom: f64,
    scroll: [f64; 2],
    menu: Menu,
    client_id: Option<ClientId>,
}

impl App {
    pub fn new(gl: GlGraphics) -> App {
        App {
            gl: gl,
            world_state: None,
            game_state_server: Arc::new(Mutex::new(None)),
            game_state: GameState::new(),
            selected_units: vec![],
            commands: Arc::new(Mutex::new(VecDeque::new())),
            cursor: [0.0, 0.0],
            state: State::Menu,
            zoom: 1.0,
            scroll: [0.0, 0.0],
            menu: Menu::new(),
            client_id: None,
        }
    }

    pub fn start(&mut self) -> Result<(), Box<Error>> {
        let mut network_client = NetworkClient::new(
            ("127.0.0.1", 8080),
            self.game_state_server.clone(),
            self.commands.clone());
        let (client_id, world_state) = network_client.connect()?;
        self.client_id = Some(client_id);
        self.world_state = Some(world_state);
        network_client.update();
        Ok(())
    }

    pub fn select(&mut self, position: [f64;2]) {

        let player = {
            let index = self.client_id.unwrap_or(ClientId(0)).0 as usize;
            self.game_state.players.get(index).map(|v| v.clone())
        };

        self.selected_units.truncate(0);
        if let Some(player) = player {
            for unit in player.units.iter() {
                if unit.is_hit(UNIT_SIZE, position) {
                    self.selected_units.push(unit.id);
                }
            }
        }
    }

    fn render_game(&mut self, args: &RenderArgs, _: &mut GlyphCache) {
        use graphics::{polygon, line, clear, ellipse};
        use graphics::Transformed;
        use graphics::types::{Polygon, Line};

        const FRONT_THICKNESS: f64 = 5.0;

        let game_state = &self.game_state;
        let world = self.world_state.as_ref().unwrap();
        let (wx, wy) = (world.x, world.y);
        let zoom = self.zoom;
        let scroll = self.scroll;
        let selected_units = self.selected_units.clone();

        self.gl.draw(args.viewport(), |c, gl| {

            let transform = c.transform
                .scale(zoom, zoom)
                .trans(scroll[0], scroll[1]);

            // Clear the screen.
            clear(BLACK, gl);

            let world: [Line; 4] = [
                [0.0, 0.0, wx,  0.0],
                [wx,  0.0, wx,  wy],
                [wx,  wy,  0.0, wy],
                [0.0, wy,  0.0, 0.0],
            ];

            for l in world.iter() {
                line(ORANGE, 1.0, *l, transform, gl);
            }

            for i in 0..game_state.players.len() {
                let ref player = game_state.players[i];
                let color = &colors::PLAYERS[i % colors::PLAYERS.len()];
                for s in player.units.iter() {
                    // Create a triangle polygon. The initial orientation is facing east.
                    let triangle: Polygon = &s.get_shape(UNIT_SIZE);

                    // Create a border on the front of the polygon. This is a trapezoid.
                    // Because the angle of the trapezoid side is 22.5°, we know that `dx` is always `2 * dy`.
                    let front: Polygon = &[
                        [UNIT_SIZE, UNIT_SIZE],                                           // Top right
                        [UNIT_SIZE, 0.0],                                                 // Bottom right
                        [UNIT_SIZE - FRONT_THICKNESS, FRONT_THICKNESS / 2.0],             // Bottom left
                        [UNIT_SIZE - FRONT_THICKNESS, UNIT_SIZE - FRONT_THICKNESS / 2.0], // Top left
                    ];

                    // Rotate the front to match the unit
                    let transform_front = transform.trans(s.position[0], s.position[1])
                        .rot_rad(s.angle)
                        .trans(-0.5 * UNIT_SIZE, -0.5 * UNIT_SIZE);

                    // We don't need to apply any transformation to the units
                    let transform_triangle = transform;

                    // Draw the unit ORANGE if selected
                    let selected = selected_units.iter().any(|id| id == &s.id);
                    if selected {
                        polygon(color.primary, triangle, transform_triangle, gl);
                        polygon(color.secondary, front, transform_front, gl);
                    } else {
                        polygon(color.secondary, triangle, transform_triangle, gl);
                        polygon(color.primary, front, transform_front, gl);
                    }

                }
            }
            for b in game_state.bullets.iter() {
                let transform = transform.trans(b.position[0], b.position[1]);
                ellipse(WHITE, [0.0, 0.0, 1.0, 1.0], transform, gl);
            }
        });
    }

    pub fn render(&mut self, args: &RenderArgs, cache: &mut GlyphCache) {
        match self.state {
            State::Menu => self.menu.render(args, &mut self.gl, cache),
            State::Running => self.render_game(args, cache),
            State::Error(ref msg) => msg.render(args, &mut self.gl, cache),
        }
    }

    pub fn update(&mut self, args: &UpdateArgs) {
        // grab updated server state if it is available
        let game_state_option = {
            let mut game_state_lock = self.game_state_server.lock().unwrap();
            mem::replace(&mut *game_state_lock, None)
        };
        if let Some(game_state) = game_state_option {
            self.game_state = game_state;
        } else {
            if let Some(ref world) = self.world_state {
                self.game_state.update(world, args.dt*1000.0);
            }
        }
    }

    pub fn on_button_press(&mut self, button: &Button) -> bool {
        match self.state {
            State::Menu => {
                match button {
                    &Button::Keyboard(Key::Up) => {
                        self.menu.previous();
                    }
                    &Button::Keyboard(Key::Down) => {
                        self.menu.next();
                    }
                    &Button::Keyboard(Key::Return) => {
                        match self.menu.get_selected_entry() {
                            menu::Entries::Start => {
                                match self.start() {
                                    Ok(_) => {
                                        self.state = State::Running;
                                    }
                                    Err(err) => {
                                        self.state = State::Error(error::Message::new(err.description().into()));
                                    }
                                }
                            }
                            menu::Entries::Exit => {
                                return true;
                            }
                        }
                    }
                    _ => { }
                }
            }
            State::Running => {
                match button {
                    &Button::Keyboard(Key::Up) => {
                        self.scroll[1] += 10.0;
                    }
                    &Button::Keyboard(Key::Down) => {
                        self.scroll[1] -= 10.0;
                    }
                    &Button::Keyboard(Key::Left) => {
                        self.scroll[0] += 10.0;
                    }
                    &Button::Keyboard(Key::Right) => {
                        self.scroll[0] -= 10.0;
                    }
                    &Button::Keyboard(Key::F) => {
                        self.shoot();
                    }
                    &Button::Keyboard(_) => { }
                    &Button::Mouse(button) => {
                        self.on_mouse_click(&button);
                    }
                    &Button::Controller(_) => { }
                }
            }
            State::Error(_) => {
                match button {
                    &Button::Keyboard(_) => { self.state = State::Menu; }
                    _ => { }
                }
            }
        };
        false
    }

    pub fn on_mouse_click(&mut self, button: &MouseButton) {
        let cursor = [
            self.cursor[0] / self.zoom - self.scroll[0],
            self.cursor[1] / self.zoom - self.scroll[1],
        ];
        match *button {
            MouseButton::Left  => self.select(cursor),
            MouseButton::Right => self.move_selected(cursor),
            _ => println!("Pressed mouse button '{:?}'", button),
        }
    }

    pub fn on_mouse_move(&mut self, cursor: [f64; 2]) {
        self.cursor = cursor;
    }

    pub fn on_mouse_scroll(&mut self, scroll: [f64; 2]) {
        if scroll[1] > 0.0 {
            self.zoom *= 1.5 * scroll[1];
        } else {
            self.zoom /= 1.5 * -scroll[1];
        }
        println!("zoom: {}", self.zoom);
    }

    pub fn move_selected(&mut self, position: [f64;2]) {
        for u in self.selected_units.iter() {
            let mut commands = self.commands.lock().unwrap();
            commands.push_back(Command::Move(*u, position));
        }
    }

    pub fn shoot(&mut self) {
        for u in self.selected_units.iter() {
            let mut commands = self.commands.lock().unwrap();
            commands.push_back(Command::Shoot(*u));
        }
    }
}
<commit_msg>client/mod.rs: Reorganize imports<commit_after>use std::thread;
use std::time;
use std::mem;
use std::sync::{Mutex, Arc};
use std::net::{SocketAddr, ToSocketAddrs, TcpStream};
use std::collections::VecDeque;
use std::error::Error;

use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;
use piston::input::{Button, Key, MouseButton, RenderArgs, UpdateArgs};
use bincode::{serialize_into, deserialize_from, Infinite};

use network::{Command, Message};
use state::{UnitId, ClientId, WorldState, GameState, UNIT_SIZE};
use shapes::Shape;
use colors::{self, BLACK, ORANGE, WHITE};

pub mod menu;
pub mod error;

use self::menu::Menu;

pub struct NetworkClient {
    pub game_state: Arc<Mutex<Option<GameState>>>,
    server_addr: SocketAddr,
    stream: Option<TcpStream>,
    commands: Arc<Mutex<VecDeque<Command>>>,
}

impl NetworkClient {
    pub fn new<T: ToSocketAddrs>(server_addrs: T,
                                 game_state: Arc<Mutex<Option<GameState>>>,
                                 commands: Arc<Mutex<VecDeque<Command>>>) -> NetworkClient {
        let server_addr = server_addrs.to_socket_addrs().unwrap().next().unwrap();
        NetworkClient {
            game_state: game_state,
            server_addr: server_addr,
            stream: None,
            commands: commands,
        }
    }

    pub fn connect(&mut self) -> Result<(ClientId, WorldState), Box<Error>>  {
        let mut stream = TcpStream::connect(self.server_addr)?;
        serialize_into(&mut stream, &Message::ClientHello, Infinite)?;
        let server_hello = deserialize_from(&mut stream, Infinite);

        self.stream = Some(stream);
        if let Ok(Message::ServerHello(client_id, world_state)) = server_hello {
            Ok((client_id, world_state))
        } else {
            Err("Could not connect to server".into())
        }
    }

    pub fn update(&self) {
        let stream = self.stream.as_ref().expect("Stream not here :(");
        let mut command_stream = stream.try_clone().unwrap();
        let commands = self.commands.clone();

        // Command sender loop
        thread::spawn(move || {
            loop {
                let command = {
                    let mut commands = commands.lock().unwrap();
                    commands.pop_front()
                };
                command.map(|cmd| {
                    println!("Got command: {:?}", cmd);
                    //let cmd = Message::Command(Command::Move(0.into(), [100f64, 100f64]));
                    serialize_into(&mut command_stream, &Message::Command(cmd), Infinite)
                        .unwrap_or_else(|e|println!("Sending command failed: {}", e));
                });
                thread::sleep(time::Duration::from_millis(10));
            }
        });

        let mut game_state_stream = stream.try_clone().unwrap();
        let game_state = self.game_state.clone();
        thread::spawn(move || {
            loop {
                let game_state_server: Result<GameState,_> = deserialize_from(
                    &mut game_state_stream,
                    Infinite);
                match game_state_server {
                    Ok(game) => {
                        //println!("{:?}", game);
                        let mut game_state_lock = game_state.lock().unwrap();
                        *game_state_lock = Some(game);

                    }
                    Err(e) => {
                        println!("{:?}", e);
                        thread::sleep(time::Duration::from_millis(200));
                    }
                }
            }
        });
    }
}

#[derive(Clone, Debug)]
pub enum State {
    Menu,
    Error(error::Message),
    Running,
}

pub struct App {
    pub gl: GlGraphics, // OpenGL drawing backend.
    pub world_state: Option<WorldState>,
    pub game_state_server: Arc<Mutex<Option<GameState>>>,
    pub game_state: GameState,
    pub selected_units: Vec<UnitId>,
    pub commands: Arc<Mutex<VecDeque<Command>>>,
    pub cursor: [f64; 2],
    pub state: State,
    zoom: f64,
    scroll: [f64; 2],
    menu: Menu,
    client_id: Option<ClientId>,
}

impl App {
    pub fn new(gl: GlGraphics) -> App {
        App {
            gl: gl,
            world_state: None,
            game_state_server: Arc::new(Mutex::new(None)),
            game_state: GameState::new(),
            selected_units: vec![],
            commands: Arc::new(Mutex::new(VecDeque::new())),
            cursor: [0.0, 0.0],
            state: State::Menu,
            zoom: 1.0,
            scroll: [0.0, 0.0],
            menu: Menu::new(),
            client_id: None,
        }
    }

    pub fn start(&mut self) -> Result<(), Box<Error>> {
        let mut network_client = NetworkClient::new(
            ("127.0.0.1", 8080),
            self.game_state_server.clone(),
            self.commands.clone());
        let (client_id, world_state) = network_client.connect()?;
        self.client_id = Some(client_id);
        self.world_state = Some(world_state);
        network_client.update();
        Ok(())
    }

    pub fn select(&mut self, position: [f64;2]) {

        let player = {
            let index = self.client_id.unwrap_or(ClientId(0)).0 as usize;
            self.game_state.players.get(index).map(|v| v.clone())
        };

        self.selected_units.truncate(0);
        if let Some(player) = player {
            for unit in player.units.iter() {
                if unit.is_hit(UNIT_SIZE, position) {
                    self.selected_units.push(unit.id);
                }
            }
        }
    }

    fn render_game(&mut self, args: &RenderArgs, _: &mut GlyphCache) {
        use graphics::{polygon, line, clear, ellipse};
        use graphics::Transformed;
        use graphics::types::{Polygon, Line};

        const FRONT_THICKNESS: f64 = 5.0;

        let game_state = &self.game_state;
        let world = self.world_state.as_ref().unwrap();
        let (wx, wy) = (world.x, world.y);
        let zoom = self.zoom;
        let scroll = self.scroll;
        let selected_units = self.selected_units.clone();

        self.gl.draw(args.viewport(), |c, gl| {

            let transform = c.transform
                .scale(zoom, zoom)
                .trans(scroll[0], scroll[1]);

            // Clear the screen.
            clear(BLACK, gl);

            let world: [Line; 4] = [
                [0.0, 0.0, wx,  0.0],
                [wx,  0.0, wx,  wy],
                [wx,  wy,  0.0, wy],
                [0.0, wy,  0.0, 0.0],
            ];

            for l in world.iter() {
                line(ORANGE, 1.0, *l, transform, gl);
            }

            for i in 0..game_state.players.len() {
                let ref player = game_state.players[i];
                let color = &colors::PLAYERS[i % colors::PLAYERS.len()];
                for s in player.units.iter() {
                    // Create a triangle polygon. The initial orientation is facing east.
                    let triangle: Polygon = &s.get_shape(UNIT_SIZE);

                    // Create a border on the front of the polygon. This is a trapezoid.
                    // Because the angle of the trapezoid side is 22.5°, we know that `dx` is always `2 * dy`.
                    let front: Polygon = &[
                        [UNIT_SIZE, UNIT_SIZE],                                           // Top right
                        [UNIT_SIZE, 0.0],                                                 // Bottom right
                        [UNIT_SIZE - FRONT_THICKNESS, FRONT_THICKNESS / 2.0],             // Bottom left
                        [UNIT_SIZE - FRONT_THICKNESS, UNIT_SIZE - FRONT_THICKNESS / 2.0], // Top left
                    ];

                    // Rotate the front to match the unit
                    let transform_front = transform.trans(s.position[0], s.position[1])
                        .rot_rad(s.angle)
                        .trans(-0.5 * UNIT_SIZE, -0.5 * UNIT_SIZE);

                    // We don't need to apply any transformation to the units
                    let transform_triangle = transform;

                    // Draw the unit ORANGE if selected
                    let selected = selected_units.iter().any(|id| id == &s.id);
                    if selected {
                        polygon(color.primary, triangle, transform_triangle, gl);
                        polygon(color.secondary, front, transform_front, gl);
                    } else {
                        polygon(color.secondary, triangle, transform_triangle, gl);
                        polygon(color.primary, front, transform_front, gl);
                    }

                }
            }
            for b in game_state.bullets.iter() {
                let transform = transform.trans(b.position[0], b.position[1]);
                ellipse(WHITE, [0.0, 0.0, 1.0, 1.0], transform, gl);
            }
        });
    }

    pub fn render(&mut self, args: &RenderArgs, cache: &mut GlyphCache) {
        match self.state {
            State::Menu => self.menu.render(args, &mut self.gl, cache),
            State::Running => self.render_game(args, cache),
            State::Error(ref msg) => msg.render(args, &mut self.gl, cache),
        }
    }

    pub fn update(&mut self, args: &UpdateArgs) {
        // grab updated server state if it is available
        let game_state_option = {
            let mut game_state_lock = self.game_state_server.lock().unwrap();
            mem::replace(&mut *game_state_lock, None)
        };
        if let Some(game_state) = game_state_option {
            self.game_state = game_state;
        } else {
            if let Some(ref world) = self.world_state {
                self.game_state.update(world, args.dt*1000.0);
            }
        }
    }

    pub fn on_button_press(&mut self, button: &Button) -> bool {
        match self.state {
            State::Menu => {
                match button {
                    &Button::Keyboard(Key::Up) => {
                        self.menu.previous();
                    }
                    &Button::Keyboard(Key::Down) => {
                        self.menu.next();
                    }
                    &Button::Keyboard(Key::Return) => {
                        match self.menu.get_selected_entry() {
                            menu::Entries::Start => {
                                match self.start() {
                                    Ok(_) => {
                                        self.state = State::Running;
                                    }
                                    Err(err) => {
                                        self.state = State::Error(error::Message::new(err.description().into()));
                                    }
                                }
                            }
                            menu::Entries::Exit => {
                                return true;
                            }
                        }
                    }
                    _ => { }
                }
            }
            State::Running => {
                match button {
                    &Button::Keyboard(Key::Up) => {
                        self.scroll[1] += 10.0;
                    }
                    &Button::Keyboard(Key::Down) => {
                        self.scroll[1] -= 10.0;
                    }
                    &Button::Keyboard(Key::Left) => {
                        self.scroll[0] += 10.0;
                    }
                    &Button::Keyboard(Key::Right) => {
                        self.scroll[0] -= 10.0;
                    }
                    &Button::Keyboard(Key::F) => {
                        self.shoot();
                    }
                    &Button::Keyboard(_) => { }
                    &Button::Mouse(button) => {
                        self.on_mouse_click(&button);
                    }
                    &Button::Controller(_) => { }
                }
            }
            State::Error(_) => {
                match button {
                    &Button::Keyboard(_) => { self.state = State::Menu; }
                    _ => { }
                }
            }
        };
        false
    }

    pub fn on_mouse_click(&mut self, button: &MouseButton) {
        let cursor = [
            self.cursor[0] / self.zoom - self.scroll[0],
            self.cursor[1] / self.zoom - self.scroll[1],
        ];
        match *button {
            MouseButton::Left  => self.select(cursor),
            MouseButton::Right => self.move_selected(cursor),
            _ => println!("Pressed mouse button '{:?}'", button),
        }
    }

    pub fn on_mouse_move(&mut self, cursor: [f64; 2]) {
        self.cursor = cursor;
    }

    pub fn on_mouse_scroll(&mut self, scroll: [f64; 2]) {
        if scroll[1] > 0.0 {
            self.zoom *= 1.5 * scroll[1];
        } else {
            self.zoom /= 1.5 * -scroll[1];
        }
        println!("zoom: {}", self.zoom);
    }

    pub fn move_selected(&mut self, position: [f64;2]) {
        for u in self.selected_units.iter() {
            let mut commands = self.commands.lock().unwrap();
            commands.push_back(Command::Move(*u, position));
        }
    }

    pub fn shoot(&mut self) {
        for u in self.selected_units.iter() {
            let mut commands = self.commands.lock().unwrap();
            commands.push_back(Command::Shoot(*u));
        }
    }
}
<|endoftext|>


<commit_before>//! Contains the types and functions to communicate with the MusicBrainz API.

use errors::{ClientError, ClientErrorKind};
use entities::{Mbid, Resource};

use reqwest_mock::Client as MockClient;
use reqwest_mock::GenericClient as HttpClient;
use reqwest_mock::{StatusCode, Url};
use reqwest_mock::header::UserAgent;
use xpath_reader::reader::{FromXmlContained, XpathStrReader};

use std::time::{Duration, Instant};
use std::thread::sleep;

use search::{AreaSearchBuilder, ArtistSearchBuilder, ReleaseGroupSearchBuilder};
// TODO reconsider reexport
pub use search::SearchBuilder;

mod error;
pub(crate)
use self::error::check_response_error;

/// Helper extracting the number of milliseconds from a `Duration`.
fn as_millis(duration: &Duration) -> f64
{
    (duration.as_secs() as f64) + (duration.subsec_nanos() as f64) * 1e6
}

/// Returns an `Instant` at least 1000 seconds ago.
fn past_instant() -> Instant
{
    Instant::now() - Duration::new(1000, 0)
}

/// Configuration for the client.
#[derive(Clone, Debug)]
pub struct ClientConfig {
    /// The user-agent to be sent with every request to the API.
    ///
    /// Provide a meaningful one as it will be used by MusicBrainz to identify
    /// your application and
    /// without a user agent sever throttling will be undertaken. The official
    /// suggestion is to use
    /// either one of the following two options:
    ///
    /// * `Application name/<version> ( contact-url )`
    /// * `Application name/<version> ( contact-email )`
    ///
    /// For more information see:
    /// https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting
    pub user_agent: String,

    /// How many times to retry requests where MusicBrainz returned 503 because
    /// too many requests were being made.
    pub max_retries: u8,
}

/// The main struct to be used to communicate with the MusicBrainz API.
///
/// Please create only one instance and use it troughout your application
/// as it will ensure appropriate wait times between requests to prevent
/// being blocked for making to many requests.
pub struct Client {
    http_client: HttpClient,
    config: ClientConfig,

    /// The time the last request was made.
    /// According to the documentation we have to wait at least one second
    /// between any two requests
    /// to the MusicBrainz API.
    last_request: Instant,
}

impl Client {
    /// Create a new `Client` instance.
    pub fn new(config: ClientConfig) -> Self
    {
        Client {
            config: config,
            http_client: HttpClient::direct(),
            last_request: past_instant(),
        }
    }

    /// Create a new `Client` instance with the specified `HttpClient`.
    ///
    /// This is useful for testing purposes where you can inject a different
    /// `HttpClient`, i. e.
    /// one replaying requests to save API calls or one providing explicit
    /// stubbing.
    pub fn with_http_client(config: ClientConfig, client: HttpClient) -> Self
    {
        Client {
            config: config,
            http_client: client,
            last_request: past_instant(),
        }
    }
}

impl Client {
    fn wait_if_needed(&mut self)
    {
        let now = Instant::now();
        let elapsed = now.duration_since(self.last_request);
        if as_millis(&elapsed) < 1000. {
            // We have to wait a bit.
            sleep(Duration::new(1, 0) - elapsed);
        }
        self.last_request = now;
    }

    /// Fetch the specified ressource from the server and parse it.
    pub fn get_by_mbid<Res>(&mut self, mbid: &Mbid) -> Result<Res, ClientError>
    where
        Res: Resource + FromXmlContained,
    {
        let url = Res::get_url(mbid);
        let response_body = self.get_body(url.parse()?)?;

        // Parse the response.
        let context = ::util::musicbrainz_context();
        let reader = XpathStrReader::new(&response_body[..], &context)?;
        check_response_error(&reader)?;
        Ok(Res::from_xml(&reader)?)
    }

    pub(crate)
    fn get_body(&mut self, url: Url) -> Result<String, ClientError>
    {
        self.wait_if_needed();

        let mut attempts = 0;
        // TODO : make initial value configurable once we allow users to run against
        // their own
        // mirrors of the musicbrainz api.
        let mut backoff = 400;

        while attempts < self.config.max_retries {
            let response = self.http_client
                .get(url.clone())
                .header(UserAgent::new(self.config.user_agent.clone()))
                .send()?;
            if response.status == StatusCode::ServiceUnavailable {
                sleep(Duration::from_millis(backoff));
                attempts += 1;
                backoff *= 2;
                // If we are in testing we want to avoid always failing.
                self.http_client.force_record_next();
            } else {
                let response_body = response.body_to_utf8()?;
                return Ok(response_body);
            }
        }
        Err(
            "MusicBrainz returned 503 (ServiceUnavailable) too many times.".into(),
        )
    }

    /// Returns a search builder to search for an area.
    pub fn search_area<'cl>(&'cl mut self) -> AreaSearchBuilder<'cl>
    {
        AreaSearchBuilder::new(self)
    }

    /// Returns a search biulder to search for an artist.
    pub fn search_artist<'cl>(&'cl mut self) -> ArtistSearchBuilder<'cl>
    {
        ArtistSearchBuilder::new(self)
    }

    /// Returns a search builder to search for a release group.
    pub fn search_release_group<'cl>(&'cl mut self) -> ReleaseGroupSearchBuilder<'cl>
    {
        ReleaseGroupSearchBuilder::new(self)
    }
}

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

    fn get_client(testname: &str) -> Client
    {
        Client::with_http_client(
            ClientConfig {
                user_agent: "MusicBrainz-Rust/Testing".to_string(),
                max_retries: 5,
            },
            HttpClient::replay_file(format!("replay/test_client/search/{}.json", testname)),
        )
    }

    #[test]
    fn search_release_group()
    {
        let mut client = get_client("release_group_01");
        let results = client
            .search_release_group()
            .add(::search::fields::release_group::ReleaseGroupName(
                "霊魂消滅".to_owned(),
            ))
            .search()
            .unwrap();

        assert_eq!(results.len(), 1);
        assert_eq!(results[0].score, 100);
        assert_eq!(
            results[0].entity.mbid,
            "739de9cd-7e81-4bb0-9fdb-0feb7ea709c7".parse().unwrap()
        );
        assert_eq!(results[0].entity.title, "霊魂消滅".to_string());
    }
}
<commit_msg>Cosmetics<commit_after>//! Contains the types and functions to communicate with the MusicBrainz API.

use errors::{ClientError, ClientErrorKind};
use entities::{Mbid, Resource};

use reqwest_mock::Client as MockClient;
use reqwest_mock::GenericClient as HttpClient;
use reqwest_mock::{StatusCode, Url};
use reqwest_mock::header::UserAgent;
use xpath_reader::reader::{FromXmlContained, XpathStrReader};

use std::time::{Duration, Instant};
use std::thread::sleep;

use search::{AreaSearchBuilder, ArtistSearchBuilder, ReleaseGroupSearchBuilder};
// TODO reconsider reexport
pub use search::SearchBuilder;

mod error;
pub(crate) use self::error::check_response_error;

/// Helper extracting the number of milliseconds from a `Duration`.
fn as_millis(duration: &Duration) -> f64
{
    (duration.as_secs() as f64) + (duration.subsec_nanos() as f64) * 1e6
}

/// Returns an `Instant` at least 1000 seconds ago.
fn past_instant() -> Instant
{
    Instant::now() - Duration::new(1000, 0)
}

/// Configuration for the client.
#[derive(Clone, Debug)]
pub struct ClientConfig {
    /// The user-agent to be sent with every request to the API.
    ///
    /// Provide a meaningful one as it will be used by MusicBrainz to identify
    /// your application and without a user agent sever throttling will be
    /// undertaken. The official suggestion is to use either one of the
    /// following two options:
    ///
    /// * `Application name/<version> ( contact-url )`
    /// * `Application name/<version> ( contact-email )`
    ///
    /// For more information see:
    /// https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting
    pub user_agent: String,

    /// How many times to retry requests where MusicBrainz returned 503 because
    /// too many requests were being made.
    pub max_retries: u8,
}

/// The main struct to be used to communicate with the MusicBrainz API.
///
/// Please create only one instance and use it troughout your application
/// as it will ensure appropriate wait times between requests to prevent
/// being blocked for making to many requests.
pub struct Client {
    http_client: HttpClient,
    config: ClientConfig,

    /// The time the last request was made.
    /// According to the documentation we have to wait at least one second
    /// between any two requests
    /// to the MusicBrainz API.
    last_request: Instant,
}

impl Client {
    /// Create a new `Client` instance.
    pub fn new(config: ClientConfig) -> Self
    {
        Client {
            config: config,
            http_client: HttpClient::direct(),
            last_request: past_instant(),
        }
    }

    /// Create a new `Client` instance with the specified `HttpClient`.
    ///
    /// This is useful for testing purposes where you can inject a different
    /// `HttpClient`, i. e.
    /// one replaying requests to save API calls or one providing explicit
    /// stubbing.
    pub fn with_http_client(config: ClientConfig, client: HttpClient) -> Self
    {
        Client {
            config: config,
            http_client: client,
            last_request: past_instant(),
        }
    }
}

impl Client {
    fn wait_if_needed(&mut self)
    {
        let now = Instant::now();
        let elapsed = now.duration_since(self.last_request);
        if as_millis(&elapsed) < 1000. {
            // We have to wait a bit.
            sleep(Duration::new(1, 0) - elapsed);
        }
        self.last_request = now;
    }

    /// Fetch the specified ressource from the server and parse it.
    pub fn get_by_mbid<Res>(&mut self, mbid: &Mbid) -> Result<Res, ClientError>
    where
        Res: Resource + FromXmlContained,
    {
        let url = Res::get_url(mbid);
        let response_body = self.get_body(url.parse()?)?;

        // Parse the response.
        let context = ::util::musicbrainz_context();
        let reader = XpathStrReader::new(&response_body[..], &context)?;
        check_response_error(&reader)?;
        Ok(Res::from_xml(&reader)?)
    }

    pub(crate) fn get_body(&mut self, url: Url) -> Result<String, ClientError>
    {
        self.wait_if_needed();

        let mut attempts = 0;
        // TODO : make initial value configurable once we allow users to run against
        // their own
        // mirrors of the musicbrainz api.
        let mut backoff = 400;

        while attempts < self.config.max_retries {
            let response = self.http_client
                .get(url.clone())
                .header(UserAgent::new(self.config.user_agent.clone()))
                .send()?;
            if response.status == StatusCode::ServiceUnavailable {
                sleep(Duration::from_millis(backoff));
                attempts += 1;
                backoff *= 2;
                // If we are in testing we want to avoid always failing.
                self.http_client.force_record_next();
            } else {
                let response_body = response.body_to_utf8()?;
                return Ok(response_body);
            }
        }
        Err(
            "MusicBrainz returned 503 (ServiceUnavailable) too many times.".into(),
        )
    }

    /// Returns a search builder to search for an area.
    pub fn search_area<'cl>(&'cl mut self) -> AreaSearchBuilder<'cl>
    {
        AreaSearchBuilder::new(self)
    }

    /// Returns a search biulder to search for an artist.
    pub fn search_artist<'cl>(&'cl mut self) -> ArtistSearchBuilder<'cl>
    {
        ArtistSearchBuilder::new(self)
    }

    /// Returns a search builder to search for a release group.
    pub fn search_release_group<'cl>(&'cl mut self) -> ReleaseGroupSearchBuilder<'cl>
    {
        ReleaseGroupSearchBuilder::new(self)
    }
}

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

    fn get_client(testname: &str) -> Client
    {
        Client::with_http_client(
            ClientConfig {
                user_agent: "MusicBrainz-Rust/Testing".to_string(),
                max_retries: 5,
            },
            HttpClient::replay_file(format!("replay/test_client/search/{}.json", testname)),
        )
    }

    #[test]
    fn search_release_group()
    {
        let mut client = get_client("release_group_01");
        let results = client
            .search_release_group()
            .add(::search::fields::release_group::ReleaseGroupName(
                "霊魂消滅".to_owned(),
            ))
            .search()
            .unwrap();

        assert_eq!(results.len(), 1);
        assert_eq!(results[0].score, 100);
        assert_eq!(
            results[0].entity.mbid,
            "739de9cd-7e81-4bb0-9fdb-0feb7ea709c7".parse().unwrap()
        );
        assert_eq!(results[0].entity.title, "霊魂消滅".to_string());
    }
}
<|endoftext|>


<commit_before>//! A Comparator object provides a total order across slices that are
//! used as keys in an sstable or a database.

use std::cmp::Ordering;
use std::mem;
use std::os::raw::{c_char, c_int};
use std::slice;
use std::str;

use rocks_sys as ll;

/// A `Comparator` object provides a total order across slices that are
/// used as keys in an sstable or a database. A `Comparator` implementation
/// must be thread-safe since rocksdb may invoke its methods concurrently
/// from multiple threads.
pub trait Comparator {
    /// Three-way comparison.  Returns value:
    ///
    /// - `< 0 iff "a" < "b"`,
    /// - `== 0 iff "a" == "b"`,
    /// - `> 0 iff "a" > "b"`
    fn compare(&self, a: &[u8], b: &[u8]) -> Ordering;

    /// Compares two slices for equality. The following invariant should always
    /// hold (and is the default implementation):
    ///
    /// > `Equal(a, b) iff Compare(a, b) == 0`
    ///
    /// Overwrite only if equality comparisons can be done more efficiently than
    /// three-way comparisons.
    fn equal(&self, a: &[u8], b: &[u8]) -> bool {
        self.compare(a, b) == Ordering::Equal
    }
    /// The name of the comparator.  Used to check for comparator
    /// mismatches (i.e., a DB created with one comparator is
    /// accessed using a different comparator.
    ///
    /// The client of this package should switch to a new name whenever
    /// the comparator implementation changes in a way that will cause
    /// the relative ordering of any two keys to change.
    ///
    /// Names starting with "rocksdb." are reserved and should not be used
    /// by any clients of this package.
    // FIXME: \0 ended
    fn name(&self) -> &str {
        "rust-rocks.Comparator\0"
    }

    // Advanced functions: these are used to reduce the space requirements
    // for internal data structures like index blocks.

    /// If `*start < limit`, changes `*start` to a short string in `[start,limit)`.
    /// Simple comparator implementations may return with `*start` unchanged,
    /// i.e., an implementation of this method that does nothing is correct.
    fn find_shortest_separator(&self, _start: &[u8], _limit: &[u8]) -> Option<&[u8]> {
        None
    }

    /// Changes `*key` to a short string `>= *key`.
    ///
    /// Simple comparator implementations may return with `*key` unchanged,
    /// i.e., an implementation of this method that does nothing is correct.
    fn find_short_successor(&self, _key: &[u8]) -> Option<&[u8]> {
        None
    }
}

#[doc(hidden)]
pub mod rust_export {
    use super::*;

    #[no_mangle]
    pub unsafe extern "C" fn rust_comparator_compare(cp: *mut (), a: *const &[u8], b: *const &[u8]) -> c_int {
        let comparator = cp as *mut &dyn Comparator;
        // FIXME: 8 byte Ordering
        mem::transmute::<_, i8>((*comparator).compare(*a, *b)) as c_int
    }

    #[no_mangle]
    pub unsafe extern "C" fn rust_comparator_equal(cp: *mut (), a: *const &[u8], b: *const &[u8]) -> c_char {
        let comparator = cp as *mut &dyn Comparator;
        ((*comparator).equal(*a, *b)) as c_char
    }

    #[no_mangle]
    pub unsafe extern "C" fn rust_comparator_name(cp: *mut ()) -> *const c_char {
        let comparator = cp as *mut &dyn Comparator;
        (*comparator).name().as_ptr() as *const _
    }

    #[no_mangle]
    pub unsafe extern "C" fn rust_comparator_find_shortest_separator(
        cp: *mut (),
        start: *mut (), // std::string*
        limit: *const &[u8],
    ) {
        // Slice&
        let comparator = cp as *mut &dyn Comparator;

        let start_ptr = ll::cxx_string_data(start as *const _);
        let start_len = ll::cxx_string_size(start as *const _);

        let ret =
            (*comparator).find_shortest_separator(slice::from_raw_parts(start_ptr as *const _, start_len as _), *limit);
        if let Some(new_start) = ret {
            ll::cxx_string_assign(start as *mut _, new_start.as_ptr() as *const _, new_start.len() as _)
        }
    }

    #[no_mangle]
    pub unsafe extern "C" fn rust_comparator_find_short_successor(cp: *mut (), key: *mut ()) {
        // std::string*
        let comparator = cp as *mut &dyn Comparator;

        let key_ptr = ll::cxx_string_data(key as *const _);
        let key_len = ll::cxx_string_size(key as *const _);

        let ret = (*comparator).find_short_successor(slice::from_raw_parts(key_ptr as *const _, key_len as _));
        if let Some(new_key) = ret {
            ll::cxx_string_assign(key as *mut _, new_key.as_ptr() as *const _, new_key.len() as _);
        }
    }

    #[no_mangle]
    pub unsafe extern "C" fn rust_comparator_drop(op: *mut ()) {
        assert!(!op.is_null());
        let operator = op as *mut &dyn Comparator;
        Box::from_raw(operator);
    }
}

#[cfg(test)]
mod tests {
    use lazy_static::lazy_static;
    use std::str;

    use super::super::rocksdb::*;
    use super::*;

    #[test]
    fn bitwise_comparator_normal() {
        let tmp_dir = ::tempdir::TempDir::new_in(".", "rocks").unwrap();
        let db = DB::open(
            Options::default()
                .map_db_options(|db| db.create_if_missing(true))
                .map_cf_options(|cf| cf.bitwise_comparator_reversed(false)),
            tmp_dir,
        )
        .unwrap();

        assert!(db.put(&WriteOptions::default(), b"key1", b"val2").is_ok());
        assert!(db.put(&WriteOptions::default(), b"key2", b"val2").is_ok());

        let mut it = db.new_iterator(&ReadOptions::default().pin_data(true));

        it.seek_to_first();
        assert!(it.is_valid());

        let first = it.key().to_vec();
        it.next();
        assert!(it.is_valid());

        let second = it.key().to_vec();
        assert!(first < second);
    }

    #[test]
    fn bitwise_comparator_reversed() {
        let tmp_dir = ::tempdir::TempDir::new_in(".", "rocks").unwrap();
        let db = DB::open(
            Options::default()
                .map_db_options(|db| db.create_if_missing(true))
                .map_cf_options(|cf| cf.bitwise_comparator_reversed(true)),
            tmp_dir,
        )
        .unwrap();

        assert!(db.put(&WriteOptions::default(), b"key1", b"").is_ok());
        assert!(db.put(&WriteOptions::default(), b"key2", b"").is_ok());

        let mut it = db.new_iterator(&ReadOptions::default().pin_data(true));

        it.seek_to_first();
        assert!(it.is_valid());

        let first = it.key().to_vec();
        it.next();
        assert!(it.is_valid());

        let second = it.key().to_vec();
        assert!(first > second);
    }

    pub struct MyComparator;

    impl Comparator for MyComparator {
        fn compare(&self, a: &[u8], b: &[u8]) -> ::std::cmp::Ordering {
            let sa = unsafe { str::from_utf8_unchecked(a) };
            let sb = unsafe { str::from_utf8_unchecked(b) };
            sa.to_lowercase().cmp(&sb.to_lowercase())
        }
    }

    lazy_static! {
        static ref CMP: MyComparator = { MyComparator };
    }

    #[test]
    fn custom_lowercase_comparator() {
        let tmp_dir = ::tempdir::TempDir::new_in(".", "rocks").unwrap();

        let opts = Options::default()
            .map_db_options(|db| db.create_if_missing(true))
            .map_cf_options(|cf| cf.comparator(&*CMP));
        let db = DB::open(opts, tmp_dir).unwrap();

        assert!(db.put(&WriteOptions::default(), b"Key1", b"").is_ok());
        assert!(db.put(&WriteOptions::default(), b"kEY3", b"").is_ok());
        assert!(db.put(&WriteOptions::default(), b"key4", b"").is_ok());
        assert!(db.put(&WriteOptions::default(), b"kEy2", b"").is_ok());

        let ks = db
            .new_iterator(&ReadOptions::default().pin_data(true))
            .into_iter()
            .map(|kv| String::from_utf8_lossy(kv.0))
            .collect::<Vec<_>>();

        // println!("keys => {:?}", ks);
        assert_eq!(ks, vec!["Key1", "kEy2", "kEY3", "key4"]);
    }
}
<commit_msg>style: fix compile warning<commit_after>//! A Comparator object provides a total order across slices that are
//! used as keys in an sstable or a database.

use std::cmp::Ordering;
use std::mem;
use std::os::raw::{c_char, c_int};
use std::slice;
use std::str;

use rocks_sys as ll;

/// A `Comparator` object provides a total order across slices that are
/// used as keys in an sstable or a database. A `Comparator` implementation
/// must be thread-safe since rocksdb may invoke its methods concurrently
/// from multiple threads.
pub trait Comparator {
    /// Three-way comparison.  Returns value:
    ///
    /// - `< 0 iff "a" < "b"`,
    /// - `== 0 iff "a" == "b"`,
    /// - `> 0 iff "a" > "b"`
    fn compare(&self, a: &[u8], b: &[u8]) -> Ordering;

    /// Compares two slices for equality. The following invariant should always
    /// hold (and is the default implementation):
    ///
    /// > `Equal(a, b) iff Compare(a, b) == 0`
    ///
    /// Overwrite only if equality comparisons can be done more efficiently than
    /// three-way comparisons.
    fn equal(&self, a: &[u8], b: &[u8]) -> bool {
        self.compare(a, b) == Ordering::Equal
    }
    /// The name of the comparator.  Used to check for comparator
    /// mismatches (i.e., a DB created with one comparator is
    /// accessed using a different comparator.
    ///
    /// The client of this package should switch to a new name whenever
    /// the comparator implementation changes in a way that will cause
    /// the relative ordering of any two keys to change.
    ///
    /// Names starting with "rocksdb." are reserved and should not be used
    /// by any clients of this package.
    // FIXME: \0 ended
    fn name(&self) -> &str {
        "rust-rocks.Comparator\0"
    }

    // Advanced functions: these are used to reduce the space requirements
    // for internal data structures like index blocks.

    /// If `*start < limit`, changes `*start` to a short string in `[start,limit)`.
    /// Simple comparator implementations may return with `*start` unchanged,
    /// i.e., an implementation of this method that does nothing is correct.
    fn find_shortest_separator(&self, _start: &[u8], _limit: &[u8]) -> Option<&[u8]> {
        None
    }

    /// Changes `*key` to a short string `>= *key`.
    ///
    /// Simple comparator implementations may return with `*key` unchanged,
    /// i.e., an implementation of this method that does nothing is correct.
    fn find_short_successor(&self, _key: &[u8]) -> Option<&[u8]> {
        None
    }
}

#[doc(hidden)]
pub mod rust_export {
    use super::*;

    #[no_mangle]
    pub unsafe extern "C" fn rust_comparator_compare(cp: *mut (), a: *const &[u8], b: *const &[u8]) -> c_int {
        let comparator = cp as *mut &dyn Comparator;
        // FIXME: 8 byte Ordering
        mem::transmute::<_, i8>((*comparator).compare(*a, *b)) as c_int
    }

    #[no_mangle]
    pub unsafe extern "C" fn rust_comparator_equal(cp: *mut (), a: *const &[u8], b: *const &[u8]) -> c_char {
        let comparator = cp as *mut &dyn Comparator;
        ((*comparator).equal(*a, *b)) as c_char
    }

    #[no_mangle]
    pub unsafe extern "C" fn rust_comparator_name(cp: *mut ()) -> *const c_char {
        let comparator = cp as *mut &dyn Comparator;
        (*comparator).name().as_ptr() as *const _
    }

    #[no_mangle]
    pub unsafe extern "C" fn rust_comparator_find_shortest_separator(
        cp: *mut (),
        start: *mut (), // std::string*
        limit: *const &[u8],
    ) {
        // Slice&
        let comparator = cp as *mut &dyn Comparator;

        let start_ptr = ll::cxx_string_data(start as *const _);
        let start_len = ll::cxx_string_size(start as *const _);

        let ret =
            (*comparator).find_shortest_separator(slice::from_raw_parts(start_ptr as *const _, start_len as _), *limit);
        if let Some(new_start) = ret {
            ll::cxx_string_assign(start as *mut _, new_start.as_ptr() as *const _, new_start.len() as _)
        }
    }

    #[no_mangle]
    pub unsafe extern "C" fn rust_comparator_find_short_successor(cp: *mut (), key: *mut ()) {
        // std::string*
        let comparator = cp as *mut &dyn Comparator;

        let key_ptr = ll::cxx_string_data(key as *const _);
        let key_len = ll::cxx_string_size(key as *const _);

        let ret = (*comparator).find_short_successor(slice::from_raw_parts(key_ptr as *const _, key_len as _));
        if let Some(new_key) = ret {
            ll::cxx_string_assign(key as *mut _, new_key.as_ptr() as *const _, new_key.len() as _);
        }
    }

    #[no_mangle]
    pub unsafe extern "C" fn rust_comparator_drop(op: *mut ()) {
        assert!(!op.is_null());
        let operator = op as *mut &dyn Comparator;
        Box::from_raw(operator);
    }
}

#[cfg(test)]
mod tests {
    use lazy_static::lazy_static;
    use std::str;

    use super::super::rocksdb::*;
    use super::*;

    #[test]
    fn bitwise_comparator_normal() {
        let tmp_dir = ::tempdir::TempDir::new_in(".", "rocks").unwrap();
        let db = DB::open(
            Options::default()
                .map_db_options(|db| db.create_if_missing(true))
                .map_cf_options(|cf| cf.bitwise_comparator_reversed(false)),
            tmp_dir,
        )
        .unwrap();

        assert!(db.put(&WriteOptions::default(), b"key1", b"val2").is_ok());
        assert!(db.put(&WriteOptions::default(), b"key2", b"val2").is_ok());

        let mut it = db.new_iterator(&ReadOptions::default().pin_data(true));

        it.seek_to_first();
        assert!(it.is_valid());

        let first = it.key().to_vec();
        it.next();
        assert!(it.is_valid());

        let second = it.key().to_vec();
        assert!(first < second);
    }

    #[test]
    fn bitwise_comparator_reversed() {
        let tmp_dir = ::tempdir::TempDir::new_in(".", "rocks").unwrap();
        let db = DB::open(
            Options::default()
                .map_db_options(|db| db.create_if_missing(true))
                .map_cf_options(|cf| cf.bitwise_comparator_reversed(true)),
            tmp_dir,
        )
        .unwrap();

        assert!(db.put(&WriteOptions::default(), b"key1", b"").is_ok());
        assert!(db.put(&WriteOptions::default(), b"key2", b"").is_ok());

        let mut it = db.new_iterator(&ReadOptions::default().pin_data(true));

        it.seek_to_first();
        assert!(it.is_valid());

        let first = it.key().to_vec();
        it.next();
        assert!(it.is_valid());

        let second = it.key().to_vec();
        assert!(first > second);
    }

    pub struct MyComparator;

    impl Comparator for MyComparator {
        fn compare(&self, a: &[u8], b: &[u8]) -> ::std::cmp::Ordering {
            let sa = unsafe { str::from_utf8_unchecked(a) };
            let sb = unsafe { str::from_utf8_unchecked(b) };
            sa.to_lowercase().cmp(&sb.to_lowercase())
        }
    }

    lazy_static! {
        static ref CMP: MyComparator = MyComparator;
    }

    #[test]
    fn custom_lowercase_comparator() {
        let tmp_dir = ::tempdir::TempDir::new_in(".", "rocks").unwrap();

        let opts = Options::default()
            .map_db_options(|db| db.create_if_missing(true))
            .map_cf_options(|cf| cf.comparator(&*CMP));
        let db = DB::open(opts, tmp_dir).unwrap();

        assert!(db.put(&WriteOptions::default(), b"Key1", b"").is_ok());
        assert!(db.put(&WriteOptions::default(), b"kEY3", b"").is_ok());
        assert!(db.put(&WriteOptions::default(), b"key4", b"").is_ok());
        assert!(db.put(&WriteOptions::default(), b"kEy2", b"").is_ok());

        let ks = db
            .new_iterator(&ReadOptions::default().pin_data(true))
            .into_iter()
            .map(|kv| String::from_utf8_lossy(kv.0))
            .collect::<Vec<_>>();

        // println!("keys => {:?}", ks);
        assert_eq!(ks, vec!["Key1", "kEy2", "kEY3", "key4"]);
    }
}
<|endoftext|>