<commit_before>use http;
use http::headers::content_type::MediaType;
use time;

///A container for the response
pub struct Response<'a, 'b> {
    ///the original `http::server::ResponseWriter`
    pub origin: &'a mut http::server::ResponseWriter<'b>,
}

impl<'a, 'b> Response<'a, 'b> {
    pub fn write (&mut self, text: &str) {
        // TODO: This needs to be more sophisticated to return the correct headers
        // not just "some headers" :)
        Response::set_headers(self.origin);
        self.origin.write(text.as_bytes());
    }

    fn set_headers(response_writer: &mut http::server::ResponseWriter) {
        response_writer.headers.date = Some(time::now_utc());

        // we don't need to set this https://github.com/Ogeon/rustful/issues/3#issuecomment-44787613
        response_writer.headers.content_length = None;
        response_writer.headers.content_type = Some(MediaType {
            type_: String::from_str("text"),
            subtype: String::from_str("plain"),
            parameters: vec!((String::from_str("charset"), String::from_str("UTF-8")))
        });
        response_writer.headers.server = Some(String::from_str("Example"));
    }
}<commit_msg>docs(response): document write method<commit_after>use http;
use http::headers::content_type::MediaType;
use time;

///A container for the response
pub struct Response<'a, 'b> {
    ///the original `http::server::ResponseWriter`
    pub origin: &'a mut http::server::ResponseWriter<'b>,
}

impl<'a, 'b> Response<'a, 'b> {

    /// Writes a response
    ///
    /// # Example
    /// ```rust
    /// response.write("hello world");
    /// ```
    pub fn write (&mut self, text: &str) {
        // TODO: This needs to be more sophisticated to return the correct headers
        // not just "some headers" :)
        Response::set_headers(self.origin);
        self.origin.write(text.as_bytes());
    }

    fn set_headers(response_writer: &mut http::server::ResponseWriter) {
        response_writer.headers.date = Some(time::now_utc());

        // we don't need to set this https://github.com/Ogeon/rustful/issues/3#issuecomment-44787613
        response_writer.headers.content_length = None;
        response_writer.headers.content_type = Some(MediaType {
            type_: String::from_str("text"),
            subtype: String::from_str("plain"),
            parameters: vec!((String::from_str("charset"), String::from_str("UTF-8")))
        });
        response_writer.headers.server = Some(String::from_str("Example"));
    }
}<|endoftext|>


<commit_before>use std::io::Read;
use std::collections::HashMap;

use rustc_serialize::json::{self, Json};

use system::System;
use search::document::DocumentSource;
use search::store::IndexStore;

use api::persistent;
use api::iron::prelude::*;
use api::iron::status;
use api::utils::{json_response, index_not_found_response};

pub fn view_post_bulk(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Load data from body
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let mut items = Vec::new();

    // Iterate
    let mut payload_lines = payload.split('\n');
    loop {
        let action_line = payload_lines.next();

        // Check if end of input
        if action_line == None || action_line == Some("") {
            break;
        }

        // Parse action line
        let action_json = parse_json!(&action_line.unwrap());

        // Check action
        // Action should be an object with only one key, the key name indicates the action and
        // the value is the parameters for that action
        let action_name = action_json.as_object().unwrap().keys().nth(0).unwrap();
        let action_params = action_json.as_object()
                                       .unwrap()
                                       .get(action_name)
                                       .unwrap()
                                       .as_object()
                                       .unwrap();

        let doc_id = action_params.get("_id").unwrap().as_string().unwrap();
        let doc_type = action_params.get("_type").unwrap().as_string().unwrap();
        let doc_index = action_params.get("_index").unwrap().as_string().unwrap();

        match action_name.as_ref() {
            "index" => {
                let doc_line = payload_lines.next();
                let doc_json = parse_json!(&doc_line.unwrap());;

                // Find index
                let mut index = get_index_or_404!(indices, doc_index);

                let doc = {
                    // Find mapping
                    let mapping = match index.get_mapping_by_name(doc_type) {
                        Some(mapping) => mapping,
                        None => {
                            return Ok(json_response(status::NotFound, "{\"message\": \"Mapping not found\"}"));
                        }
                    };

                    // Create document
                    let document_source = DocumentSource {
                        key: doc_id.to_string(),
                        data: doc_json,
                    };
                    document_source.prepare(mapping)
                };

                index.store.insert_or_update_document(doc);

                // Insert into "items" array
                let mut item = HashMap::new();
                // TODO: "create" may not always be right
                item.insert("create", action_params.clone());
                items.push(item);
            }
            _ => {
                warn!("Unrecognised action! {}", action_name);
            }
        }
    }

    return Ok(json_response(status::Ok,
                            format!("{{\"took\": {}, \"items\": {}}}",
                                    items.len(),
                                    json::encode(&items).unwrap())));
}
<commit_msg>Fix typo<commit_after>use std::io::Read;
use std::collections::HashMap;

use rustc_serialize::json::{self, Json};

use system::System;
use search::document::DocumentSource;
use search::store::IndexStore;

use api::persistent;
use api::iron::prelude::*;
use api::iron::status;
use api::utils::{json_response, index_not_found_response};

pub fn view_post_bulk(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Load data from body
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let mut items = Vec::new();

    // Iterate
    let mut payload_lines = payload.split('\n');
    loop {
        let action_line = payload_lines.next();

        // Check if end of input
        if action_line == None || action_line == Some("") {
            break;
        }

        // Parse action line
        let action_json = parse_json!(&action_line.unwrap());

        // Check action
        // Action should be an object with only one key, the key name indicates the action and
        // the value is the parameters for that action
        let action_name = action_json.as_object().unwrap().keys().nth(0).unwrap();
        let action_params = action_json.as_object()
                                       .unwrap()
                                       .get(action_name)
                                       .unwrap()
                                       .as_object()
                                       .unwrap();

        let doc_id = action_params.get("_id").unwrap().as_string().unwrap();
        let doc_type = action_params.get("_type").unwrap().as_string().unwrap();
        let doc_index = action_params.get("_index").unwrap().as_string().unwrap();

        match action_name.as_ref() {
            "index" => {
                let doc_line = payload_lines.next();
                let doc_json = parse_json!(&doc_line.unwrap());;

                // Find index
                let mut index = get_index_or_404_mut!(indices, doc_index);

                let doc = {
                    // Find mapping
                    let mapping = match index.get_mapping_by_name(doc_type) {
                        Some(mapping) => mapping,
                        None => {
                            return Ok(json_response(status::NotFound, "{\"message\": \"Mapping not found\"}"));
                        }
                    };

                    // Create document
                    let document_source = DocumentSource {
                        key: doc_id.to_string(),
                        data: doc_json,
                    };
                    document_source.prepare(mapping)
                };

                index.store.insert_or_update_document(doc);

                // Insert into "items" array
                let mut item = HashMap::new();
                // TODO: "create" may not always be right
                item.insert("create", action_params.clone());
                items.push(item);
            }
            _ => {
                warn!("Unrecognised action! {}", action_name);
            }
        }
    }

    return Ok(json_response(status::Ok,
                            format!("{{\"took\": {}, \"items\": {}}}",
                                    items.len(),
                                    json::encode(&items).unwrap())));
}
<|endoftext|>


<commit_before>use std::ffi::{CStr, CString};
use std::rc::Rc;

use sys::sdl as ll;
use event::EventPump;
use util::CStringExt;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Error {
    NoMemError = ll::SDL_ENOMEM as isize,
    ReadError = ll::SDL_EFREAD as isize,
    WriteError = ll::SDL_EFWRITE as isize,
    SeekError = ll::SDL_EFSEEK as isize,
    UnsupportedError = ll::SDL_UNSUPPORTED as isize
}

pub type SdlResult<T> = Result<T, String>;

use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
/// Only one Sdl context can be alive at a time.
/// Set to false by default (not alive).
static IS_SDL_CONTEXT_ALIVE: AtomicBool = ATOMIC_BOOL_INIT;

/// The SDL context type. Initialize with `sdl2::init()`.
///
/// From a thread-safety perspective, `Sdl` represents the main thread.
/// Only one instance of `Sdl` is allowed per process, and cannot be moved or
/// used across non-main threads.
///
/// As such, `Sdl` is a useful type for ensuring that SDL types that can only
/// be used on the main thread are initialized that way.
///
/// For instance, `SDL_PumpEvents()` is not thread safe, and may only be
/// called on the main thread.
/// All functionality that calls `SDL_PumpEvents()` is thus put into an
/// `EventPump` type, which can only be obtained through `Sdl`.
/// This guarantees that the only way to call event-pumping functions is on
/// the main thread.
pub struct Sdl {
    sdldrop: Rc<SdlDrop>
}

impl Sdl {
    #[inline]
    pub fn new() -> SdlResult<Sdl> {
        unsafe {
            use std::sync::atomic::Ordering;

            // Atomically switch the `IS_SDL_CONTEXT_ALIVE` global to true
            let was_alive = IS_SDL_CONTEXT_ALIVE.swap(true, Ordering::Relaxed);

            if was_alive {
                Err(format!("Cannot have more than one `Sdl` in use at the same time"))
            } else {
                // Initialize SDL without any explicit subsystems (flags = 0).
                if ll::SDL_Init(0) == 0 {
                    Ok(Sdl {
                        sdldrop: Rc::new(SdlDrop)
                    })
                } else {
                    IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
                    Err(get_error())
                }
            }
        }
    }

    /// Initializes the audio subsystem.
    #[inline]
    pub fn audio(&self) -> SdlResult<AudioSubsystem> { AudioSubsystem::new(self) }

    /// Initializes the event subsystem.
    #[inline]
    pub fn event(&self) -> SdlResult<EventSubsystem> { EventSubsystem::new(self) }

    /// Initializes the joystick subsystem.
    #[inline]
    pub fn joystick(&self) -> SdlResult<JoystickSubsystem> { JoystickSubsystem::new(self) }

    /// Initializes the haptic subsystem.
    #[inline]
    pub fn haptic(&self) -> SdlResult<HapticSubsystem> { HapticSubsystem::new(self) }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn game_controller(&self) -> SdlResult<GameControllerSubsystem> { GameControllerSubsystem::new(self) }

    /// Initializes the timer subsystem.
    #[inline]
    pub fn timer(&self) -> SdlResult<TimerSubsystem> { TimerSubsystem::new(self) }

    /// Initializes the video subsystem.
    #[inline]
    pub fn video(&self) -> SdlResult<VideoSubsystem> { VideoSubsystem::new(self) }

    /// Obtains the SDL event pump.
    ///
    /// At most one `EventPump` is allowed to be alive during the program's execution.
    /// If this function is called while an `EventPump` instance is alive, the function will return
    /// an error.
    #[inline]
    pub fn event_pump(&self) -> SdlResult<EventPump> {
        EventPump::new(self)
    }
}

/// When SDL is no longer in use (the refcount in an `Rc<SdlDrop>` reaches 0), the library is quit.
struct SdlDrop;

impl Drop for SdlDrop {
    #[inline]
    fn drop(&mut self) {
        use std::sync::atomic::Ordering;

        let was_alive = IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
        assert!(was_alive);

        unsafe { ll::SDL_Quit(); }
    }
}

// No subsystem can implement `Send` because the destructor, `SDL_QuitSubSystem`,
// utilizes non-atomic reference counting and should thus be called on a single thread.
// Some subsystems have functions designed to be thread-safe, such as adding a timer or accessing
// the event queue. These subsystems implement `Sync`.

macro_rules! subsystem {
    ($name:ident, $flag:expr) => (
        impl $name {
            #[inline]
            fn new(sdl: &Sdl) -> SdlResult<$name> {
                let result = unsafe { ll::SDL_InitSubSystem($flag) };

                if result == 0 {
                    Ok($name {
                        _subsystem_drop: Rc::new(SubsystemDrop {
                            _sdldrop: sdl.sdldrop.clone(),
                            flag: $flag
                        })
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    );
    ($name:ident, $flag:expr, nosync) => (
        #[derive(Clone)]
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }

        subsystem!($name, $flag);
    );
    ($name:ident, $flag:expr, sync) => (
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }
        unsafe impl Sync for $name {}

        subsystem!($name, $flag);
    )
}

/// When a subsystem is no longer in use (the refcount in an `Rc<SubsystemDrop>` reaches 0),
/// the subsystem is quit.
#[derive(Clone)]
struct SubsystemDrop {
    _sdldrop: Rc<SdlDrop>,
    flag: ll::SDL_InitFlag
}

impl Drop for SubsystemDrop {
    #[inline]
    fn drop(&mut self) {
        unsafe { ll::SDL_QuitSubSystem(self.flag); }
    }
}

subsystem!(AudioSubsystem, ll::SDL_INIT_AUDIO, nosync);
subsystem!(GameControllerSubsystem, ll::SDL_INIT_GAMECONTROLLER, nosync);
subsystem!(HapticSubsystem, ll::SDL_INIT_HAPTIC, nosync);
subsystem!(JoystickSubsystem, ll::SDL_INIT_JOYSTICK, nosync);
subsystem!(VideoSubsystem, ll::SDL_INIT_VIDEO, nosync);
// Timers can be added on other threads.
subsystem!(TimerSubsystem, ll::SDL_INIT_VIDEO, sync);
// The event queue can be read from other threads.
subsystem!(EventSubsystem, ll::SDL_INIT_EVENTS, sync);

/// Initializes the SDL library.
/// This must be called before using any other SDL function.
///
/// # Example
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
/// let mut event_pump = sdl_context.event_pump().unwrap();
///
/// for event in event_pump.poll_iter() {
///     // ...
/// }
///
/// // SDL_Quit() is called here as `sdl_context` is dropped.
/// ```
#[inline]
pub fn init() -> SdlResult<Sdl> { Sdl::new() }

pub fn get_error() -> String {
    unsafe {
        let err = ll::SDL_GetError();
        String::from_utf8_lossy(CStr::from_ptr(err).to_bytes()).to_string()
    }
}

pub fn set_error(err: &str) {
    let err = CString::new(err).remove_nul();
    unsafe { ll::SDL_SetError(err.as_ptr()); }
}

pub fn set_error_from_code(err: Error) {
    unsafe { ll::SDL_Error(err as ll::SDL_errorcode); }
}

pub fn clear_error() {
    unsafe { ll::SDL_ClearError(); }
}
<commit_msg>Fix failing timer test on Travis, properly initialize timer subsystem<commit_after>use std::ffi::{CStr, CString};
use std::rc::Rc;

use sys::sdl as ll;
use event::EventPump;
use util::CStringExt;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Error {
    NoMemError = ll::SDL_ENOMEM as isize,
    ReadError = ll::SDL_EFREAD as isize,
    WriteError = ll::SDL_EFWRITE as isize,
    SeekError = ll::SDL_EFSEEK as isize,
    UnsupportedError = ll::SDL_UNSUPPORTED as isize
}

pub type SdlResult<T> = Result<T, String>;

use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
/// Only one Sdl context can be alive at a time.
/// Set to false by default (not alive).
static IS_SDL_CONTEXT_ALIVE: AtomicBool = ATOMIC_BOOL_INIT;

/// The SDL context type. Initialize with `sdl2::init()`.
///
/// From a thread-safety perspective, `Sdl` represents the main thread.
/// Only one instance of `Sdl` is allowed per process, and cannot be moved or
/// used across non-main threads.
///
/// As such, `Sdl` is a useful type for ensuring that SDL types that can only
/// be used on the main thread are initialized that way.
///
/// For instance, `SDL_PumpEvents()` is not thread safe, and may only be
/// called on the main thread.
/// All functionality that calls `SDL_PumpEvents()` is thus put into an
/// `EventPump` type, which can only be obtained through `Sdl`.
/// This guarantees that the only way to call event-pumping functions is on
/// the main thread.
pub struct Sdl {
    sdldrop: Rc<SdlDrop>
}

impl Sdl {
    #[inline]
    pub fn new() -> SdlResult<Sdl> {
        unsafe {
            use std::sync::atomic::Ordering;

            // Atomically switch the `IS_SDL_CONTEXT_ALIVE` global to true
            let was_alive = IS_SDL_CONTEXT_ALIVE.swap(true, Ordering::Relaxed);

            if was_alive {
                Err(format!("Cannot have more than one `Sdl` in use at the same time"))
            } else {
                // Initialize SDL without any explicit subsystems (flags = 0).
                if ll::SDL_Init(0) == 0 {
                    Ok(Sdl {
                        sdldrop: Rc::new(SdlDrop)
                    })
                } else {
                    IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
                    Err(get_error())
                }
            }
        }
    }

    /// Initializes the audio subsystem.
    #[inline]
    pub fn audio(&self) -> SdlResult<AudioSubsystem> { AudioSubsystem::new(self) }

    /// Initializes the event subsystem.
    #[inline]
    pub fn event(&self) -> SdlResult<EventSubsystem> { EventSubsystem::new(self) }

    /// Initializes the joystick subsystem.
    #[inline]
    pub fn joystick(&self) -> SdlResult<JoystickSubsystem> { JoystickSubsystem::new(self) }

    /// Initializes the haptic subsystem.
    #[inline]
    pub fn haptic(&self) -> SdlResult<HapticSubsystem> { HapticSubsystem::new(self) }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn game_controller(&self) -> SdlResult<GameControllerSubsystem> { GameControllerSubsystem::new(self) }

    /// Initializes the timer subsystem.
    #[inline]
    pub fn timer(&self) -> SdlResult<TimerSubsystem> { TimerSubsystem::new(self) }

    /// Initializes the video subsystem.
    #[inline]
    pub fn video(&self) -> SdlResult<VideoSubsystem> { VideoSubsystem::new(self) }

    /// Obtains the SDL event pump.
    ///
    /// At most one `EventPump` is allowed to be alive during the program's execution.
    /// If this function is called while an `EventPump` instance is alive, the function will return
    /// an error.
    #[inline]
    pub fn event_pump(&self) -> SdlResult<EventPump> {
        EventPump::new(self)
    }
}

/// When SDL is no longer in use (the refcount in an `Rc<SdlDrop>` reaches 0), the library is quit.
struct SdlDrop;

impl Drop for SdlDrop {
    #[inline]
    fn drop(&mut self) {
        use std::sync::atomic::Ordering;

        let was_alive = IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
        assert!(was_alive);

        unsafe { ll::SDL_Quit(); }
    }
}

// No subsystem can implement `Send` because the destructor, `SDL_QuitSubSystem`,
// utilizes non-atomic reference counting and should thus be called on a single thread.
// Some subsystems have functions designed to be thread-safe, such as adding a timer or accessing
// the event queue. These subsystems implement `Sync`.

macro_rules! subsystem {
    ($name:ident, $flag:expr) => (
        impl $name {
            #[inline]
            fn new(sdl: &Sdl) -> SdlResult<$name> {
                let result = unsafe { ll::SDL_InitSubSystem($flag) };

                if result == 0 {
                    Ok($name {
                        _subsystem_drop: Rc::new(SubsystemDrop {
                            _sdldrop: sdl.sdldrop.clone(),
                            flag: $flag
                        })
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    );
    ($name:ident, $flag:expr, nosync) => (
        #[derive(Clone)]
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }

        subsystem!($name, $flag);
    );
    ($name:ident, $flag:expr, sync) => (
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }
        unsafe impl Sync for $name {}

        subsystem!($name, $flag);
    )
}

/// When a subsystem is no longer in use (the refcount in an `Rc<SubsystemDrop>` reaches 0),
/// the subsystem is quit.
#[derive(Clone)]
struct SubsystemDrop {
    _sdldrop: Rc<SdlDrop>,
    flag: ll::SDL_InitFlag
}

impl Drop for SubsystemDrop {
    #[inline]
    fn drop(&mut self) {
        unsafe { ll::SDL_QuitSubSystem(self.flag); }
    }
}

subsystem!(AudioSubsystem, ll::SDL_INIT_AUDIO, nosync);
subsystem!(GameControllerSubsystem, ll::SDL_INIT_GAMECONTROLLER, nosync);
subsystem!(HapticSubsystem, ll::SDL_INIT_HAPTIC, nosync);
subsystem!(JoystickSubsystem, ll::SDL_INIT_JOYSTICK, nosync);
subsystem!(VideoSubsystem, ll::SDL_INIT_VIDEO, nosync);
// Timers can be added on other threads.
subsystem!(TimerSubsystem, ll::SDL_INIT_TIMER, sync);
// The event queue can be read from other threads.
subsystem!(EventSubsystem, ll::SDL_INIT_EVENTS, sync);

/// Initializes the SDL library.
/// This must be called before using any other SDL function.
///
/// # Example
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
/// let mut event_pump = sdl_context.event_pump().unwrap();
///
/// for event in event_pump.poll_iter() {
///     // ...
/// }
///
/// // SDL_Quit() is called here as `sdl_context` is dropped.
/// ```
#[inline]
pub fn init() -> SdlResult<Sdl> { Sdl::new() }

pub fn get_error() -> String {
    unsafe {
        let err = ll::SDL_GetError();
        String::from_utf8_lossy(CStr::from_ptr(err).to_bytes()).to_string()
    }
}

pub fn set_error(err: &str) {
    let err = CString::new(err).remove_nul();
    unsafe { ll::SDL_SetError(err.as_ptr()); }
}

pub fn set_error_from_code(err: Error) {
    unsafe { ll::SDL_Error(err as ll::SDL_errorcode); }
}

pub fn clear_error() {
    unsafe { ll::SDL_ClearError(); }
}
<|endoftext|>


<commit_before>//! Module to make Rust subclasses of C++ classes. See [`CppSubclass`]
//! for details.

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

use std::{
    cell::RefCell,
    pin::Pin,
    rc::{Rc, Weak},
};

use cxx::{memory::UniquePtrTarget, UniquePtr};

pub use autocxx_macro::is_subclass;
pub use autocxx_macro::CppSubclassDefault;
pub use autocxx_macro::CppSubclassSelfOwnedDefault;

/// A prelude containing all the traits and macros required to create
/// Rust subclasses of C++ classes. It's recommended that you:
///
/// ```rust
/// use autocxx::subclass::prelude::*;
/// ```
pub mod prelude {
    pub use super::{
        is_subclass, CppPeerConstructor, CppSubclass, CppSubclassDefault, CppSubclassSelfOwned,
        CppSubclassSelfOwnedDefault,
    };
}

#[doc(hidden)]
pub trait CppSubclassCppPeer: UniquePtrTarget {
    fn relinquish_ownership(&self);
}

#[doc(hidden)]
pub enum CppSubclassRustPeerHolder<T> {
    Owned(Rc<RefCell<T>>),
    Unowned(Weak<RefCell<T>>),
}

impl<T> CppSubclassRustPeerHolder<T> {
    pub fn get(&self) -> Option<Rc<RefCell<T>>> {
        match self {
            CppSubclassRustPeerHolder::Owned(strong) => Some(strong.clone()),
            CppSubclassRustPeerHolder::Unowned(weak) => weak.upgrade(),
        }
    }
    pub fn relinquish_ownership(self) -> Self {
        match self {
            CppSubclassRustPeerHolder::Owned(strong) => {
                CppSubclassRustPeerHolder::Unowned(Rc::downgrade(&strong))
            }
            _ => self,
        }
    }
}

#[doc(hidden)]
pub enum CppSubclassCppPeerHolder<CppPeer: CppSubclassCppPeer> {
    Empty,
    Owned(Box<UniquePtr<CppPeer>>),
    Unowned(*mut CppPeer),
}

impl<CppPeer: CppSubclassCppPeer> Default for CppSubclassCppPeerHolder<CppPeer> {
    fn default() -> Self {
        CppSubclassCppPeerHolder::Empty
    }
}

impl<CppPeer: CppSubclassCppPeer> CppSubclassCppPeerHolder<CppPeer> {
    fn pin_mut(&mut self) -> Pin<&mut CppPeer> {
        match self {
            CppSubclassCppPeerHolder::Empty => panic!("Peer not set up"),
            CppSubclassCppPeerHolder::Owned(peer) => peer.pin_mut(),
            CppSubclassCppPeerHolder::Unowned(peer) => unsafe {
                Pin::new_unchecked(peer.as_mut().unwrap())
            },
        }
    }
    fn get(&self) -> &CppPeer {
        match self {
            CppSubclassCppPeerHolder::Empty => panic!("Peer not set up"),
            CppSubclassCppPeerHolder::Owned(peer) => peer.as_ref(),
            CppSubclassCppPeerHolder::Unowned(peer) => unsafe { peer.as_ref().unwrap() },
        }
    }
    fn set_owned(&mut self, peer: UniquePtr<CppPeer>) {
        *self = Self::Owned(Box::new(peer));
    }
    fn set_unowned(&mut self, peer: &mut UniquePtr<CppPeer>) {
        *self = Self::Unowned(unsafe {
            std::pin::Pin::<&mut CppPeer>::into_inner_unchecked(peer.pin_mut())
        });
    }
}

fn make_owning_peer<CppPeer, PeerConstructor, Subclass, PeerBoxer>(
    me: Subclass,
    peer_constructor: PeerConstructor,
    peer_boxer: PeerBoxer,
) -> Rc<RefCell<Subclass>>
where
    CppPeer: CppSubclassCppPeer,
    Subclass: CppSubclass<CppPeer>,
    PeerConstructor:
        FnOnce(&mut Subclass, CppSubclassRustPeerHolder<Subclass>) -> UniquePtr<CppPeer>,
    PeerBoxer: FnOnce(Rc<RefCell<Subclass>>) -> CppSubclassRustPeerHolder<Subclass>,
{
    let me = Rc::new(RefCell::new(me));
    let holder = peer_boxer(me.clone());
    let cpp_side = peer_constructor(&mut me.as_ref().borrow_mut(), holder);
    me.as_ref()
        .borrow_mut()
        .peer_holder_mut()
        .set_owned(cpp_side);
    me
}

/// A trait to be implemented by a subclass which knows how to construct
/// its C++ peer object. Specifically, the implementation here will
/// arrange to call one or other of the `make_unique` methods to be
/// found on the superclass of the C++ object. If the superclass
/// has a single trivial constructor, then this is implemented
/// automatically for you. If there are multiple constructors, or
/// a single constructor which takes parameters, you'll need to implement
/// this trait for your subclass in order to call the correct
/// constructor.
pub trait CppPeerConstructor<CppPeer: CppSubclassCppPeer>: Sized {
    /// Create the C++ peer. This method will be automatically generated
    /// for you *except* in cases where the superclass has multiple constructors,
    /// or its only constructor takes parameters. In such a case you'll need
    /// to implement this by calling a `make_unique` method on the
    /// `<my subclass name>Cpp` type, passing `peer_holder` as the first
    /// argument.
    fn make_peer(&mut self, peer_holder: CppSubclassRustPeerHolder<Self>) -> UniquePtr<CppPeer>;
}

/// A subclass of a C++ type.
///
/// To create a Rust subclass of a C++ class, you must do these things:
/// * Use the `subclass` directive in your [`crate::include_cpp`] macro (or use
///   the auto-allow mode in your `build.rs`)
/// * Create a `struct` to act as your subclass, and add the #[`is_subclass`] attribute.
///   This adds a field to your struct for autocxx record-keeping. You can
///   instead choose to implement [`CppSubclass`] a different way.
/// * Use the [`CppSubclass`] trait, and instantiate the subclass using
///   [`CppSubclass::new_rust_owned`] or [`CppSubclass::new_cpp_owned`]
///   constructors. (You can use [`CppSubclassSelfOwned`] if you need that
///   instead; also, see [`CppSubclassSelfOwnedDefault`] and [`CppSubclassDefault`]
///   to arrange for easier constructors to exist.
/// * You _may_ need to implement [`CppPeerConstructor`] for your subclass,
///   but only if autocxx determines that there are multiple possible superclass
///   constructors so you need to call one explicitly (or if there's a single
///   non-trivial superclass constructor.) autocxx will implemente this trait
///   for you if there's no ambiguity.
///
/// # How to access your Rust structure from outside
///
/// Use [`CppSubclass::new_rust_owned`] then use [`std::cell::RefCell::borrow`]
/// or [`std::cell::RefCell::borrow_mut`] to obtain the underlying Rust struct.
///
/// # How to call C++ methods on the subclass
///
/// Do the same. You should find that your subclass struct `impl`s all the
/// C++ methods belonging to the superclass.
///
/// # How to implement virtual methods
///
/// Simply add an `impl` for the `struct`, implementing the relevant method.
/// The C++ virtual function call will be redirected to your Rust implementation.
///
/// # How _not_ to implement virtual methods
///
/// If you don't want to implement a virtual method, don't: the superclass
/// method will be called instead. Naturally, you must implement any pure virtual
/// methods.
///
/// # How it works
///
/// This actually consists of two objects: this object itself and a C++-side
/// peer. The ownership relationship between those two things can work in three
/// different ways:
/// 1. Neither object is owned by Rust. The C++ peer is owned by a C++
///    [`UniquePtr`] held elsewhere in C++. That C++ peer then owns
///    this Rust-side object via a strong [`Rc`] reference. This is the
///    ownership relationship set up by [`CppSubclass::new_cpp_owned`].
/// 2. The object pair is owned by Rust. Specifically, by a strong
///    [`Rc`] reference to this Rust-side object. In turn, the Rust-side object
///    owns the C++-side peer via a [`UniquePtr`]. This is what's set up by
///    [`CppSubclass::new_rust_owned`]. The C++-side peer _does not_ own the Rust
///    object; it just has a weak pointer. (Otherwise we'd get a reference
///    loop and nothing would ever be freed.)
/// 3. The object pair is self-owned and will stay around forever until
///    [`CppSubclassSelfOwned::delete_self`] is called. In this case there's a strong reference
///    from the C++ to the Rust and from the Rust to the C++. This is useful
///    for cases where the subclass is listening for events, and needs to
///    stick around until a particular event occurs then delete itself.
///
/// # Limitations
///
/// * *Re-entrancy*. The main thing to look out for is re-entrancy. If a
///   (non-const) virtual method is called on your type, which then causes you
///   to call back into C++, which results in a _second_ call into a (non-const)
///   virtual method, we will try to create two mutable references to your
///   subclass which isn't allowed in Rust and will therefore panic.
///
///   A future version of autocxx may provide the option of treating all
///   non-const methods (in C++) as const methods on the Rust side, which will
///   give the option of using interior mutability ([`std::cell::RefCell`])
///   for you to safely handle this situation, whilst remaining compatible
///   with existing C++ interfaces. If you need this, indicate support on
///   [this issue](https://github.com/google/autocxx/issues/622).
///
/// * *Thread safety*. The subclass object is not thread-safe and shouldn't
///   be passed to different threads in C++. A future version of this code
///   will give the option to use `Arc` and `Mutex` internally rather than
///   `Rc` and `RefCell`, solving this problem.
///
/// * *Complex or multiple constructors*. At present, this code doesn't work
///   if the superclass has anything other than a single, zero-argument,
///   constructor. This is
///   [this issue](https://github.com/google/autocxx/issues/596) and is just a matter of doing
///   a bit of work to plumb this together. (See [`CppPeerConstructor`] for
///   how this will work when it's done.)
///
/// * *Protected methods.* We don't do anything clever here - they're public.
///
/// * *Non-trivial class hierarchies*. We don't yet consider virtual methods
///   on base classes of base classes. This is a temporary limitation,
///   [see this issue](https://github.com/google/autocxx/issues/610).
///
/// * *Namespaces.* Superclasses in namespaces are not yet supported:
///   [see this issue](https://github.com/google/autocxx/issues/599).
pub trait CppSubclass<CppPeer: CppSubclassCppPeer>: CppPeerConstructor<CppPeer> {
    /// Return the field which holds the C++ peer object. This is normally
    /// implemented by the #[`is_subclass`] macro, but you're welcome to
    /// implement it yourself if you prefer.
    fn peer_holder(&self) -> &CppSubclassCppPeerHolder<CppPeer>;

    /// Return the field which holds the C++ peer object. This is normally
    /// implemented by the #[`is_subclass`] macro, but you're welcome to
    /// implement it yourself if you prefer.
    fn peer_holder_mut(&mut self) -> &mut CppSubclassCppPeerHolder<CppPeer>;

    /// Return a reference to the C++ part of this object pair.
    /// This can be used to register listeners, etc.
    fn peer(&self) -> &CppPeer {
        self.peer_holder().get()
    }

    /// Return a mutable reference to the C++ part of this object pair.
    /// This can be used to register listeners, etc.
    fn peer_mut(&mut self) -> Pin<&mut CppPeer> {
        self.peer_holder_mut().pin_mut()
    }

    /// Creates a new instance of this subclass. This instance is owned by the
    /// returned [`cxx::UniquePtr`] and thus would typically be returned immediately
    /// to C++ such that it can be owned on the C++ side.
    fn new_cpp_owned(me: Self) -> UniquePtr<CppPeer> {
        let me = Rc::new(RefCell::new(me));
        let holder = CppSubclassRustPeerHolder::Owned(me.clone());
        let mut borrowed = me.as_ref().borrow_mut();
        let mut cpp_side = borrowed.make_peer(holder);
        borrowed.peer_holder_mut().set_unowned(&mut cpp_side);
        cpp_side
    }

    /// Creates a new instance of this subclass. This instance is not owned
    /// by C++, and therefore will be deleted when it goes out of scope in
    /// Rust.
    fn new_rust_owned(me: Self) -> Rc<RefCell<Self>> {
        make_owning_peer(
            me,
            |obj, holder| obj.make_peer(holder),
            |me| CppSubclassRustPeerHolder::Unowned(Rc::downgrade(&me)),
        )
    }
}

/// Trait to be implemented by subclasses which are self-owned, i.e. not owned
/// externally by either Rust or C++ code, and thus need the ability to delete
/// themselves when some virtual function is called.
pub trait CppSubclassSelfOwned<CppPeer: CppSubclassCppPeer>: CppSubclass<CppPeer> {
    /// Creates a new instance of this subclass which owns itself.
    /// This is useful
    /// for observers (etc.) which self-register to listen to events.
    /// If an event occurs which would cause this to want to unregister,
    /// use [`CppSubclassSelfOwned::delete_self`].
    /// The return value may be useful to register this, etc. but can ultimately
    /// be discarded without destroying this object.
    fn new_self_owned(me: Self) -> Rc<RefCell<Self>> {
        make_owning_peer(
            me,
            |obj, holder| obj.make_peer(holder),
            CppSubclassRustPeerHolder::Owned,
        )
    }

    /// Relinquishes ownership from the C++ side. If there are no outstanding
    /// references from the Rust side, this will result in the destruction
    /// of this subclass instance.
    fn delete_self(&self) {
        self.peer().relinquish_ownership()
    }
}

/// Provides default constructors for subclasses which implement `Default`.
pub trait CppSubclassDefault<CppPeer: CppSubclassCppPeer>: CppSubclass<CppPeer> + Default {
    /// Create a Rust-owned instance of this subclass, initializing with default values. See
    /// [`CppSubclass`] for more details of the ownership models available.
    fn default_rust_owned() -> Rc<RefCell<Self>> {
        Self::new_rust_owned(Self::default())
    }

    /// Create a C++-owned instance of this subclass, initializing with default values. See
    /// [`CppSubclass`] for more details of the ownership models available.
    fn default_cpp_owned() -> UniquePtr<CppPeer> {
        Self::new_cpp_owned(Self::default())
    }
}

/// Provides default constructors for subclasses which implement `Default`
/// and are self-owning.
pub trait CppSubclassSelfOwnedDefault<CppPeer: CppSubclassCppPeer>:
    CppSubclassSelfOwned<CppPeer> + Default
{
    /// Create a self-owned instance of this subclass, initializing with default values. See
    /// [`CppSubclass`] for more details of the ownership models available.
    fn default_self_owned() -> Rc<RefCell<Self>> {
        Self::new_self_owned(Self::default())
    }
}
<commit_msg>Fix namespace comment.<commit_after>//! Module to make Rust subclasses of C++ classes. See [`CppSubclass`]
//! for details.

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

use std::{
    cell::RefCell,
    pin::Pin,
    rc::{Rc, Weak},
};

use cxx::{memory::UniquePtrTarget, UniquePtr};

pub use autocxx_macro::is_subclass;
pub use autocxx_macro::CppSubclassDefault;
pub use autocxx_macro::CppSubclassSelfOwnedDefault;

/// A prelude containing all the traits and macros required to create
/// Rust subclasses of C++ classes. It's recommended that you:
///
/// ```rust
/// use autocxx::subclass::prelude::*;
/// ```
pub mod prelude {
    pub use super::{
        is_subclass, CppPeerConstructor, CppSubclass, CppSubclassDefault, CppSubclassSelfOwned,
        CppSubclassSelfOwnedDefault,
    };
}

#[doc(hidden)]
pub trait CppSubclassCppPeer: UniquePtrTarget {
    fn relinquish_ownership(&self);
}

#[doc(hidden)]
pub enum CppSubclassRustPeerHolder<T> {
    Owned(Rc<RefCell<T>>),
    Unowned(Weak<RefCell<T>>),
}

impl<T> CppSubclassRustPeerHolder<T> {
    pub fn get(&self) -> Option<Rc<RefCell<T>>> {
        match self {
            CppSubclassRustPeerHolder::Owned(strong) => Some(strong.clone()),
            CppSubclassRustPeerHolder::Unowned(weak) => weak.upgrade(),
        }
    }
    pub fn relinquish_ownership(self) -> Self {
        match self {
            CppSubclassRustPeerHolder::Owned(strong) => {
                CppSubclassRustPeerHolder::Unowned(Rc::downgrade(&strong))
            }
            _ => self,
        }
    }
}

#[doc(hidden)]
pub enum CppSubclassCppPeerHolder<CppPeer: CppSubclassCppPeer> {
    Empty,
    Owned(Box<UniquePtr<CppPeer>>),
    Unowned(*mut CppPeer),
}

impl<CppPeer: CppSubclassCppPeer> Default for CppSubclassCppPeerHolder<CppPeer> {
    fn default() -> Self {
        CppSubclassCppPeerHolder::Empty
    }
}

impl<CppPeer: CppSubclassCppPeer> CppSubclassCppPeerHolder<CppPeer> {
    fn pin_mut(&mut self) -> Pin<&mut CppPeer> {
        match self {
            CppSubclassCppPeerHolder::Empty => panic!("Peer not set up"),
            CppSubclassCppPeerHolder::Owned(peer) => peer.pin_mut(),
            CppSubclassCppPeerHolder::Unowned(peer) => unsafe {
                Pin::new_unchecked(peer.as_mut().unwrap())
            },
        }
    }
    fn get(&self) -> &CppPeer {
        match self {
            CppSubclassCppPeerHolder::Empty => panic!("Peer not set up"),
            CppSubclassCppPeerHolder::Owned(peer) => peer.as_ref(),
            CppSubclassCppPeerHolder::Unowned(peer) => unsafe { peer.as_ref().unwrap() },
        }
    }
    fn set_owned(&mut self, peer: UniquePtr<CppPeer>) {
        *self = Self::Owned(Box::new(peer));
    }
    fn set_unowned(&mut self, peer: &mut UniquePtr<CppPeer>) {
        *self = Self::Unowned(unsafe {
            std::pin::Pin::<&mut CppPeer>::into_inner_unchecked(peer.pin_mut())
        });
    }
}

fn make_owning_peer<CppPeer, PeerConstructor, Subclass, PeerBoxer>(
    me: Subclass,
    peer_constructor: PeerConstructor,
    peer_boxer: PeerBoxer,
) -> Rc<RefCell<Subclass>>
where
    CppPeer: CppSubclassCppPeer,
    Subclass: CppSubclass<CppPeer>,
    PeerConstructor:
        FnOnce(&mut Subclass, CppSubclassRustPeerHolder<Subclass>) -> UniquePtr<CppPeer>,
    PeerBoxer: FnOnce(Rc<RefCell<Subclass>>) -> CppSubclassRustPeerHolder<Subclass>,
{
    let me = Rc::new(RefCell::new(me));
    let holder = peer_boxer(me.clone());
    let cpp_side = peer_constructor(&mut me.as_ref().borrow_mut(), holder);
    me.as_ref()
        .borrow_mut()
        .peer_holder_mut()
        .set_owned(cpp_side);
    me
}

/// A trait to be implemented by a subclass which knows how to construct
/// its C++ peer object. Specifically, the implementation here will
/// arrange to call one or other of the `make_unique` methods to be
/// found on the superclass of the C++ object. If the superclass
/// has a single trivial constructor, then this is implemented
/// automatically for you. If there are multiple constructors, or
/// a single constructor which takes parameters, you'll need to implement
/// this trait for your subclass in order to call the correct
/// constructor.
pub trait CppPeerConstructor<CppPeer: CppSubclassCppPeer>: Sized {
    /// Create the C++ peer. This method will be automatically generated
    /// for you *except* in cases where the superclass has multiple constructors,
    /// or its only constructor takes parameters. In such a case you'll need
    /// to implement this by calling a `make_unique` method on the
    /// `<my subclass name>Cpp` type, passing `peer_holder` as the first
    /// argument.
    fn make_peer(&mut self, peer_holder: CppSubclassRustPeerHolder<Self>) -> UniquePtr<CppPeer>;
}

/// A subclass of a C++ type.
///
/// To create a Rust subclass of a C++ class, you must do these things:
/// * Use the `subclass` directive in your [`crate::include_cpp`] macro (or use
///   the auto-allow mode in your `build.rs`)
/// * Create a `struct` to act as your subclass, and add the #[`is_subclass`] attribute.
///   This adds a field to your struct for autocxx record-keeping. You can
///   instead choose to implement [`CppSubclass`] a different way.
/// * Use the [`CppSubclass`] trait, and instantiate the subclass using
///   [`CppSubclass::new_rust_owned`] or [`CppSubclass::new_cpp_owned`]
///   constructors. (You can use [`CppSubclassSelfOwned`] if you need that
///   instead; also, see [`CppSubclassSelfOwnedDefault`] and [`CppSubclassDefault`]
///   to arrange for easier constructors to exist.
/// * You _may_ need to implement [`CppPeerConstructor`] for your subclass,
///   but only if autocxx determines that there are multiple possible superclass
///   constructors so you need to call one explicitly (or if there's a single
///   non-trivial superclass constructor.) autocxx will implemente this trait
///   for you if there's no ambiguity.
///
/// # How to access your Rust structure from outside
///
/// Use [`CppSubclass::new_rust_owned`] then use [`std::cell::RefCell::borrow`]
/// or [`std::cell::RefCell::borrow_mut`] to obtain the underlying Rust struct.
///
/// # How to call C++ methods on the subclass
///
/// Do the same. You should find that your subclass struct `impl`s all the
/// C++ methods belonging to the superclass.
///
/// # How to implement virtual methods
///
/// Simply add an `impl` for the `struct`, implementing the relevant method.
/// The C++ virtual function call will be redirected to your Rust implementation.
///
/// # How _not_ to implement virtual methods
///
/// If you don't want to implement a virtual method, don't: the superclass
/// method will be called instead. Naturally, you must implement any pure virtual
/// methods.
///
/// # How it works
///
/// This actually consists of two objects: this object itself and a C++-side
/// peer. The ownership relationship between those two things can work in three
/// different ways:
/// 1. Neither object is owned by Rust. The C++ peer is owned by a C++
///    [`UniquePtr`] held elsewhere in C++. That C++ peer then owns
///    this Rust-side object via a strong [`Rc`] reference. This is the
///    ownership relationship set up by [`CppSubclass::new_cpp_owned`].
/// 2. The object pair is owned by Rust. Specifically, by a strong
///    [`Rc`] reference to this Rust-side object. In turn, the Rust-side object
///    owns the C++-side peer via a [`UniquePtr`]. This is what's set up by
///    [`CppSubclass::new_rust_owned`]. The C++-side peer _does not_ own the Rust
///    object; it just has a weak pointer. (Otherwise we'd get a reference
///    loop and nothing would ever be freed.)
/// 3. The object pair is self-owned and will stay around forever until
///    [`CppSubclassSelfOwned::delete_self`] is called. In this case there's a strong reference
///    from the C++ to the Rust and from the Rust to the C++. This is useful
///    for cases where the subclass is listening for events, and needs to
///    stick around until a particular event occurs then delete itself.
///
/// # Limitations
///
/// * *Re-entrancy*. The main thing to look out for is re-entrancy. If a
///   (non-const) virtual method is called on your type, which then causes you
///   to call back into C++, which results in a _second_ call into a (non-const)
///   virtual method, we will try to create two mutable references to your
///   subclass which isn't allowed in Rust and will therefore panic.
///
///   A future version of autocxx may provide the option of treating all
///   non-const methods (in C++) as const methods on the Rust side, which will
///   give the option of using interior mutability ([`std::cell::RefCell`])
///   for you to safely handle this situation, whilst remaining compatible
///   with existing C++ interfaces. If you need this, indicate support on
///   [this issue](https://github.com/google/autocxx/issues/622).
///
/// * *Thread safety*. The subclass object is not thread-safe and shouldn't
///   be passed to different threads in C++. A future version of this code
///   will give the option to use `Arc` and `Mutex` internally rather than
///   `Rc` and `RefCell`, solving this problem.
///
/// * *Complex or multiple constructors*. At present, this code doesn't work
///   if the superclass has anything other than a single, zero-argument,
///   constructor. This is
///   [this issue](https://github.com/google/autocxx/issues/596) and is just a matter of doing
///   a bit of work to plumb this together. (See [`CppPeerConstructor`] for
///   how this will work when it's done.)
///
/// * *Protected methods.* We don't do anything clever here - they're public.
///
/// * *Non-trivial class hierarchies*. We don't yet consider virtual methods
///   on base classes of base classes. This is a temporary limitation,
///   [see this issue](https://github.com/google/autocxx/issues/610).
pub trait CppSubclass<CppPeer: CppSubclassCppPeer>: CppPeerConstructor<CppPeer> {
    /// Return the field which holds the C++ peer object. This is normally
    /// implemented by the #[`is_subclass`] macro, but you're welcome to
    /// implement it yourself if you prefer.
    fn peer_holder(&self) -> &CppSubclassCppPeerHolder<CppPeer>;

    /// Return the field which holds the C++ peer object. This is normally
    /// implemented by the #[`is_subclass`] macro, but you're welcome to
    /// implement it yourself if you prefer.
    fn peer_holder_mut(&mut self) -> &mut CppSubclassCppPeerHolder<CppPeer>;

    /// Return a reference to the C++ part of this object pair.
    /// This can be used to register listeners, etc.
    fn peer(&self) -> &CppPeer {
        self.peer_holder().get()
    }

    /// Return a mutable reference to the C++ part of this object pair.
    /// This can be used to register listeners, etc.
    fn peer_mut(&mut self) -> Pin<&mut CppPeer> {
        self.peer_holder_mut().pin_mut()
    }

    /// Creates a new instance of this subclass. This instance is owned by the
    /// returned [`cxx::UniquePtr`] and thus would typically be returned immediately
    /// to C++ such that it can be owned on the C++ side.
    fn new_cpp_owned(me: Self) -> UniquePtr<CppPeer> {
        let me = Rc::new(RefCell::new(me));
        let holder = CppSubclassRustPeerHolder::Owned(me.clone());
        let mut borrowed = me.as_ref().borrow_mut();
        let mut cpp_side = borrowed.make_peer(holder);
        borrowed.peer_holder_mut().set_unowned(&mut cpp_side);
        cpp_side
    }

    /// Creates a new instance of this subclass. This instance is not owned
    /// by C++, and therefore will be deleted when it goes out of scope in
    /// Rust.
    fn new_rust_owned(me: Self) -> Rc<RefCell<Self>> {
        make_owning_peer(
            me,
            |obj, holder| obj.make_peer(holder),
            |me| CppSubclassRustPeerHolder::Unowned(Rc::downgrade(&me)),
        )
    }
}

/// Trait to be implemented by subclasses which are self-owned, i.e. not owned
/// externally by either Rust or C++ code, and thus need the ability to delete
/// themselves when some virtual function is called.
pub trait CppSubclassSelfOwned<CppPeer: CppSubclassCppPeer>: CppSubclass<CppPeer> {
    /// Creates a new instance of this subclass which owns itself.
    /// This is useful
    /// for observers (etc.) which self-register to listen to events.
    /// If an event occurs which would cause this to want to unregister,
    /// use [`CppSubclassSelfOwned::delete_self`].
    /// The return value may be useful to register this, etc. but can ultimately
    /// be discarded without destroying this object.
    fn new_self_owned(me: Self) -> Rc<RefCell<Self>> {
        make_owning_peer(
            me,
            |obj, holder| obj.make_peer(holder),
            CppSubclassRustPeerHolder::Owned,
        )
    }

    /// Relinquishes ownership from the C++ side. If there are no outstanding
    /// references from the Rust side, this will result in the destruction
    /// of this subclass instance.
    fn delete_self(&self) {
        self.peer().relinquish_ownership()
    }
}

/// Provides default constructors for subclasses which implement `Default`.
pub trait CppSubclassDefault<CppPeer: CppSubclassCppPeer>: CppSubclass<CppPeer> + Default {
    /// Create a Rust-owned instance of this subclass, initializing with default values. See
    /// [`CppSubclass`] for more details of the ownership models available.
    fn default_rust_owned() -> Rc<RefCell<Self>> {
        Self::new_rust_owned(Self::default())
    }

    /// Create a C++-owned instance of this subclass, initializing with default values. See
    /// [`CppSubclass`] for more details of the ownership models available.
    fn default_cpp_owned() -> UniquePtr<CppPeer> {
        Self::new_cpp_owned(Self::default())
    }
}

/// Provides default constructors for subclasses which implement `Default`
/// and are self-owning.
pub trait CppSubclassSelfOwnedDefault<CppPeer: CppSubclassCppPeer>:
    CppSubclassSelfOwned<CppPeer> + Default
{
    /// Create a self-owned instance of this subclass, initializing with default values. See
    /// [`CppSubclass`] for more details of the ownership models available.
    fn default_self_owned() -> Rc<RefCell<Self>> {
        Self::new_self_owned(Self::default())
    }
}
<|endoftext|>


<commit_before>use types;
use unsafe_binding::util;

pub fn internal_id(string: &str) -> types::rb_id {
    unsafe {
        util::rb_intern(::util::str_as_ptr(string))
    }
}
<commit_msg>Create binding::call_method<commit_after>use types;
use unsafe_binding::util;

pub fn internal_id(string: &str) -> types::rb_id {
    unsafe {
        util::rb_intern(::util::str_as_ptr(string))
    }
}

pub fn call_method(receiver: types::rb_value,
                   method: &str,
                   arguments: Vec<types::rb_value>) -> types::rb_value {
    let method_id = internal_id(method);
    let argc = arguments.len() as types::c_int;
    let argv = arguments.as_ptr();

    unsafe {
        util::rb_funcall2(receiver, method_id, argc, argv)
    }
}
<|endoftext|>


<commit_before>use cgmath;
use cgmath::{Angle, Deg, Point2};
use num::{Num, NumCast};

use crate::bullet::BulletDrawable;
use crate::character::CharacterDrawable;
use crate::game::{constants::{RESOLUTION_Y, TERRAIN_OBJECTS, TILE_WIDTH, TILES_PCS_H, TILES_PCS_W, Y_OFFSET}, get_rand_from_range};
use crate::gfx_app::{mouse_controls::MouseInputState};
use crate::graphics::{dimensions::Dimensions, orientation::Orientation};
use crate::shaders::Position;
use crate::terrain_object::TerrainObjectDrawable;
use crate::zombie::ZombieDrawable;

pub mod camera;
pub mod dimensions;
mod graphics_test;
pub mod mesh;
pub mod orientation;
pub mod texture;

#[derive(Default)]
pub struct DeltaTime(pub f64);

#[derive(Default)]
pub struct GameTime(pub u64);

pub fn flip_y_axel(point: Point2<f32>) -> Point2<f32> {
  Point2::new(point.x, RESOLUTION_Y as f32 - point.y)
}

pub fn direction(start_point: Point2<f32>, end_point: Point2<f32>) -> f32 {
  let theta = Angle::atan2(end_point.y - start_point.y, end_point.x - start_point.x);
  let Deg(angle) = theta;
  if angle < 0.0 { (360.0 + angle) } else { angle }
}

pub fn direction_movement(direction: f32) -> Point2<f32> {
  let angle = Deg(direction);
  Point2::new(Angle::cos(angle), Angle::sin(angle))
}

pub fn direction_movement_180(movement_direction: Point2<f32>) -> Point2<f32> {
  let angle = Deg(direction(Point2::new(0.0, 0.0), movement_direction) + 180.0);
  Point2::new(Angle::cos(angle), Angle::sin(angle))
}

pub fn orientation_to_direction(angle_in_degrees: f32) -> Orientation {
  match angle_in_degrees as u32 {
    345...360 | 0...22 => Orientation::Right,
    23...68 => Orientation::UpRight,
    69...114 => Orientation::Up,
    115...160 => Orientation::UpLeft,
    161...206 => Orientation::Left,
    207...252 => Orientation::DownLeft,
    253...298 => Orientation::Down,
    299...344 => Orientation::DownRight,
    _ => unreachable!("Invalid orientation")
  }
}

pub fn get_orientation_from_center(mouse_input: &MouseInputState, dim: &Dimensions) -> Orientation {
  if let Some(end_point_gl) = mouse_input.left_click_point {
    let start_point = Point2::new(dim.window_width / 2.0 * dim.hidpi_factor, dim.window_height / 2.0 * dim.hidpi_factor);
    let dir = direction(start_point, flip_y_axel(end_point_gl));
    orientation_to_direction(dir)
  } else {
    Orientation::Right
  }
}

pub fn overlaps(area: Position, el: Position, width: f32, height: f32) -> bool {
  area.x() - width < el.x() &&
    area.x() + width > el.x() &&
    area.y() - height < el.y() &&
    area.y() + height > el.y()
}

pub fn is_within_map_borders(point: Point2<f32>) -> bool {
  point.x >= 0.0 && point.x < (TILES_PCS_W as f32 - 1f32) && point.y >= 0.0 && point.y < (TILES_PCS_H as f32 - 1f32)
}

pub fn can_move(screen_pos: Position) -> bool {
  let point = coords_to_tile(screen_pos);
  is_within_map_borders(Point2::new(point.x as f32, point.y as f32))
}

pub fn is_not_terrain_object<T>(pos: Point2<T>) -> bool
  where T: NumCast + Num, i32: std::cmp::PartialEq<T> {
  !TERRAIN_OBJECTS.iter().any(|e| (e[0] == pos.x) && (e[1] == pos.y))
}

fn is_map_tile(pos: Point2<i32>) -> bool {
  pos.x > 0 && pos.y > 0 && pos.x < (TILES_PCS_W - 1) as i32 && pos.y < (TILES_PCS_H - 1) as i32
}

pub fn can_move_to_tile(screen_pos: Position) -> bool {
  let tile_pos = coords_to_tile(screen_pos);
  is_not_terrain_object(tile_pos) && is_map_tile(tile_pos)
}

pub fn coords_to_tile(position: Position) -> Point2<i32> {
  let pos = Point2::new(-position.x(), position.y() + Y_OFFSET);
  Point2::new(((pos.x + pos.y) / TILE_WIDTH) as i32, ((pos.y - pos.x) / TILE_WIDTH) as i32)
}

pub fn tile_to_coords(tile: Point2<i32>) -> Position {
  let new_tile = Point2::new(tile.x as f32, tile.y as f32);
  let x = round(new_tile.x * TILE_WIDTH - new_tile.y / TILE_WIDTH, 3);
  let y = round(new_tile.y * TILE_WIDTH - new_tile.x / TILE_WIDTH, 3);
  Position::new(-x, y - Y_OFFSET)
}

fn round(number: f32, precision: usize) -> f32 {
  let ten = 10.0f64;
  let divider = ten.powf(precision as f64) as f32;
  (number * divider).round() / divider
}

pub fn add_random_offset_to_screen_pos(pos: Position) -> Position {
  fn iter(pos: Position) -> Position {
    let offset = Position::new(get_rand_from_range(-2, 2) as f32, get_rand_from_range(-2, 2) as f32);
    let offset_point = Position::new(
      round(offset.x() * TILE_WIDTH - offset.y() / TILE_WIDTH, 3),
      round(offset.y() * TILE_WIDTH - offset.y() / TILE_WIDTH, 3),
    );
    pos + offset_point
  }
  loop {
    let res = iter(pos);
    if can_move_to_tile(res) {
      return res;
    }
  }
}

pub fn calc_hypotenuse(a: f32, b: f32) -> f32 {
  (a.powf(2.0) + b.powf(2.0)).sqrt()
}

pub enum Drawables<'b> {
  Bullet(&'b BulletDrawable),
  Character(&'b mut CharacterDrawable),
  TerrainAmmo(&'b TerrainObjectDrawable),
  TerrainHouse(&'b TerrainObjectDrawable),
  TerrainTree(&'b TerrainObjectDrawable),
  Zombie(&'b mut ZombieDrawable),
}

impl<'b> Drawables<'b> {
  pub fn get_vertical_pos(drawable: &Drawables) -> f32 {
    match drawable {
      Drawables::Bullet(e) => e.position.y(),
      Drawables::Zombie(e) => e.position.y(),
      Drawables::TerrainAmmo(e) => e.position.y(),
      Drawables::TerrainHouse(e) => e.position.y(),
      Drawables::TerrainTree(e) => e.position.y(),
      Drawables::Character(e) => e.position.y(),
    }
  }
}
<commit_msg>Update range syntax to newer one<commit_after>use cgmath;
use cgmath::{Angle, Deg, Point2};
use num::{Num, NumCast};

use crate::bullet::BulletDrawable;
use crate::character::CharacterDrawable;
use crate::game::{constants::{RESOLUTION_Y, TERRAIN_OBJECTS, TILE_WIDTH, TILES_PCS_H, TILES_PCS_W, Y_OFFSET}, get_rand_from_range};
use crate::gfx_app::{mouse_controls::MouseInputState};
use crate::graphics::{dimensions::Dimensions, orientation::Orientation};
use crate::shaders::Position;
use crate::terrain_object::TerrainObjectDrawable;
use crate::zombie::ZombieDrawable;

pub mod camera;
pub mod dimensions;
mod graphics_test;
pub mod mesh;
pub mod orientation;
pub mod texture;

#[derive(Default)]
pub struct DeltaTime(pub f64);

#[derive(Default)]
pub struct GameTime(pub u64);

pub fn flip_y_axel(point: Point2<f32>) -> Point2<f32> {
  Point2::new(point.x, RESOLUTION_Y as f32 - point.y)
}

pub fn direction(start_point: Point2<f32>, end_point: Point2<f32>) -> f32 {
  let theta = Angle::atan2(end_point.y - start_point.y, end_point.x - start_point.x);
  let Deg(angle) = theta;
  if angle < 0.0 { (360.0 + angle) } else { angle }
}

pub fn direction_movement(direction: f32) -> Point2<f32> {
  let angle = Deg(direction);
  Point2::new(Angle::cos(angle), Angle::sin(angle))
}

pub fn direction_movement_180(movement_direction: Point2<f32>) -> Point2<f32> {
  let angle = Deg(direction(Point2::new(0.0, 0.0), movement_direction) + 180.0);
  Point2::new(Angle::cos(angle), Angle::sin(angle))
}

pub fn orientation_to_direction(angle_in_degrees: f32) -> Orientation {
  match angle_in_degrees as u32 {
    345..=360 | 0..=22 => Orientation::Right,
    23..=68 => Orientation::UpRight,
    69..=114 => Orientation::Up,
    115..=160 => Orientation::UpLeft,
    161..=206 => Orientation::Left,
    207..=252 => Orientation::DownLeft,
    253..=298 => Orientation::Down,
    299..=344 => Orientation::DownRight,
    _ => unreachable!("Invalid orientation")
  }
}

pub fn get_orientation_from_center(mouse_input: &MouseInputState, dim: &Dimensions) -> Orientation {
  if let Some(end_point_gl) = mouse_input.left_click_point {
    let start_point = Point2::new(dim.window_width / 2.0 * dim.hidpi_factor, dim.window_height / 2.0 * dim.hidpi_factor);
    let dir = direction(start_point, flip_y_axel(end_point_gl));
    orientation_to_direction(dir)
  } else {
    Orientation::Right
  }
}

pub fn overlaps(area: Position, el: Position, width: f32, height: f32) -> bool {
  area.x() - width < el.x() &&
    area.x() + width > el.x() &&
    area.y() - height < el.y() &&
    area.y() + height > el.y()
}

pub fn is_within_map_borders(point: Point2<f32>) -> bool {
  point.x >= 0.0 && point.x < (TILES_PCS_W as f32 - 1f32) && point.y >= 0.0 && point.y < (TILES_PCS_H as f32 - 1f32)
}

pub fn can_move(screen_pos: Position) -> bool {
  let point = coords_to_tile(screen_pos);
  is_within_map_borders(Point2::new(point.x as f32, point.y as f32))
}

pub fn is_not_terrain_object<T>(pos: Point2<T>) -> bool
  where T: NumCast + Num, i32: std::cmp::PartialEq<T> {
  !TERRAIN_OBJECTS.iter().any(|e| (e[0] == pos.x) && (e[1] == pos.y))
}

fn is_map_tile(pos: Point2<i32>) -> bool {
  pos.x > 0 && pos.y > 0 && pos.x < (TILES_PCS_W - 1) as i32 && pos.y < (TILES_PCS_H - 1) as i32
}

pub fn can_move_to_tile(screen_pos: Position) -> bool {
  let tile_pos = coords_to_tile(screen_pos);
  is_not_terrain_object(tile_pos) && is_map_tile(tile_pos)
}

pub fn coords_to_tile(position: Position) -> Point2<i32> {
  let pos = Point2::new(-position.x(), position.y() + Y_OFFSET);
  Point2::new(((pos.x + pos.y) / TILE_WIDTH) as i32, ((pos.y - pos.x) / TILE_WIDTH) as i32)
}

pub fn tile_to_coords(tile: Point2<i32>) -> Position {
  let new_tile = Point2::new(tile.x as f32, tile.y as f32);
  let x = round(new_tile.x * TILE_WIDTH - new_tile.y / TILE_WIDTH, 3);
  let y = round(new_tile.y * TILE_WIDTH - new_tile.x / TILE_WIDTH, 3);
  Position::new(-x, y - Y_OFFSET)
}

fn round(number: f32, precision: usize) -> f32 {
  let ten = 10.0f64;
  let divider = ten.powf(precision as f64) as f32;
  (number * divider).round() / divider
}

pub fn add_random_offset_to_screen_pos(pos: Position) -> Position {
  fn iter(pos: Position) -> Position {
    let offset = Position::new(get_rand_from_range(-2, 2) as f32, get_rand_from_range(-2, 2) as f32);
    let offset_point = Position::new(
      round(offset.x() * TILE_WIDTH - offset.y() / TILE_WIDTH, 3),
      round(offset.y() * TILE_WIDTH - offset.y() / TILE_WIDTH, 3),
    );
    pos + offset_point
  }
  loop {
    let res = iter(pos);
    if can_move_to_tile(res) {
      return res;
    }
  }
}

pub fn calc_hypotenuse(a: f32, b: f32) -> f32 {
  (a.powf(2.0) + b.powf(2.0)).sqrt()
}

pub enum Drawables<'b> {
  Bullet(&'b BulletDrawable),
  Character(&'b mut CharacterDrawable),
  TerrainAmmo(&'b TerrainObjectDrawable),
  TerrainHouse(&'b TerrainObjectDrawable),
  TerrainTree(&'b TerrainObjectDrawable),
  Zombie(&'b mut ZombieDrawable),
}

impl<'b> Drawables<'b> {
  pub fn get_vertical_pos(drawable: &Drawables) -> f32 {
    match drawable {
      Drawables::Bullet(e) => e.position.y(),
      Drawables::Zombie(e) => e.position.y(),
      Drawables::TerrainAmmo(e) => e.position.y(),
      Drawables::TerrainHouse(e) => e.position.y(),
      Drawables::TerrainTree(e) => e.position.y(),
      Drawables::Character(e) => e.position.y(),
    }
  }
}
<|endoftext|>


<commit_before>extern crate piston_window;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate find_folder;

use piston_window::Transformed;

use piston_window as pw;

mod object;
use object::Object;

struct Game {
    player: Object,
    up: bool,
    down: bool,
    left: bool,
    right: bool,
}

impl Game {
    fn new() -> Game {
        Game { player: Object::new(), up: false, down: false, left: false, right: false }
    }

    fn on_update(&mut self, args: &pw::UpdateArgs) {
        if self.up   { self.player.mov(0.0, -150.0 * args.dt); }
        if self.down { self.player.mov(0.0, 150.0 * args.dt); }
        if self.left { self.player.mov(-150.0 * args.dt, 0.0); }
        if self.right { self.player.mov(150.0 * args.dt, 0.0); }
    }

    fn on_draw(&mut self, args: &pw::RenderArgs, window: &pw::PistonWindow) {
        window.draw_2d(|context, graphics| {
            pw::clear([0.0, 0.0, 0.0, 1.0], graphics);

            let center = context.transform.trans((args.width / 2) as f64, (args.height / 2) as f64);
            self.player.render(graphics, &center);
        });
    }

    fn on_input(&mut self, input: &pw::Input) {
        use piston_window::{Button, Key};

        match input {
            &pw::Input::Press(button) => {
                match button {
                    Button::Keyboard(Key::Up) => { self.up = true; }
                    Button::Keyboard(Key::Down) => { self.down = true; }
                    Button::Keyboard(Key::Left) => { self.left = true; }
                    Button::Keyboard(Key::Right) => { self.right = true; }
                    _ => {}
                }
            }
            &pw::Input::Release(button) => {
                match button {
                    Button::Keyboard(Key::Up) => { self.up = false; }
                    Button::Keyboard(Key::Down) => { self.down = false; }
                    Button::Keyboard(Key::Left) => { self.left = false; }
                    Button::Keyboard(Key::Right) => { self.right = false; }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

fn main() {
    use piston_window::Event;

    let window: pw::PistonWindow = pw::WindowSettings::new("rrthozopsi", [600, 600])
        .exit_on_esc(true)
        .build()
        .unwrap();

    let mut game = Game::new();

    for w in window {
        match w.event {
            Some(Event::Update(args)) => { game.on_update(&args); }
            Some(Event::Render(args)) => { game.on_draw(&args, &w); }
            Some(Event::Input(input)) => { game.on_input(&input); }
            _ => {}
        }
    }
}
<commit_msg>Sprite loading<commit_after>extern crate piston_window;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate find_folder;

use piston_window::Transformed;

use piston_window as pw;

mod object;
use object::Object;

struct Game {
    player: Object,
    up: bool,
    down: bool,
    left: bool,
    right: bool,
}

impl Game {
    fn new() -> Game {
        Game { player: Object::new(), up: false, down: false, left: false, right: false }
    }

    fn on_update(&mut self, args: &pw::UpdateArgs) {
        if self.up   { self.player.mov(0.0, -150.0 * args.dt); }
        if self.down { self.player.mov(0.0, 150.0 * args.dt); }
        if self.left { self.player.mov(-150.0 * args.dt, 0.0); }
        if self.right { self.player.mov(150.0 * args.dt, 0.0); }
    }

    fn on_draw(&mut self, args: &pw::RenderArgs, window: &pw::PistonWindow) {
        window.draw_2d(|context, graphics| {
            pw::clear([0.0, 0.0, 0.0, 1.0], graphics);

            let center = context.transform.trans((args.width / 2) as f64, (args.height / 2) as f64);
            self.player.render(graphics, &center);
        });
    }

    fn on_input(&mut self, input: &pw::Input) {
        use piston_window::{Button, Key};

        match input {
            &pw::Input::Press(button) => {
                match button {
                    Button::Keyboard(Key::Up) => { self.up = true; }
                    Button::Keyboard(Key::Down) => { self.down = true; }
                    Button::Keyboard(Key::Left) => { self.left = true; }
                    Button::Keyboard(Key::Right) => { self.right = true; }
                    _ => {}
                }
            }
            &pw::Input::Release(button) => {
                match button {
                    Button::Keyboard(Key::Up) => { self.up = false; }
                    Button::Keyboard(Key::Down) => { self.down = false; }
                    Button::Keyboard(Key::Left) => { self.left = false; }
                    Button::Keyboard(Key::Right) => { self.right = false; }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

fn main() {
    use piston_window::Event;

    let window: pw::PistonWindow = pw::WindowSettings::new("rrthozopsi", [600, 600])
        .exit_on_esc(true)
        .build()
        .unwrap();

    let mut game = Game::new();
    {
        let assets = find_folder::Search::ParentsThenKids(3, 3).for_folder("assets").unwrap();
        let sprite = assets.join("skeleton.png");
        let sprite = pw::Texture::from_path(&mut *window.factory.borrow_mut(), &sprite, pw::Flip::None, &pw::TextureSettings::new()).unwrap();

        game.player.set_sprite(sprite);
    }

    for w in window {
        match w.event {
            Some(Event::Update(args)) => { game.on_update(&args); }
            Some(Event::Render(args)) => { game.on_draw(&args, &w); }
            Some(Event::Input(input)) => { game.on_input(&input); }
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Guess_the_number
// not_tested
extern crate rand;

use std::rand::{task_rng, Rng};
use std::io::stdio::stdin;
use std::io::BufferedReader;

fn main() {
    let mystery_number = task_rng().gen_range(0i, 10) + 1;
    println!("Guess my number between 1 and 10");

    let mut input = BufferedReader::new(stdin());
    loop {
        let line = input.read_line().unwrap();
        match from_str::<int>(line.as_slice().trim()) {
            Some(number) if (number == mystery_number) => break,
            Some(_) => println!("Wrong! Try again!"),
            None    => println!("Please enter an integer")
        }
    }

    // The loop ends only if the player wins
    println!("Well guessed!");
}
<commit_msg>guess number: unnecessary imports<commit_after>// Implements http://rosettacode.org/wiki/Guess_the_number
// not_tested
use std::rand::{task_rng, Rng};
use std::io::stdio::stdin;

fn main() {
    let mystery_number = task_rng().gen_range(0i, 10) + 1;
    println!("Guess my number between 1 and 10");

    let mut input = stdin();
    loop {
        let line = input.read_line().unwrap();
        match from_str::<int>(line.as_slice().trim()) {
            Some(guess) if guess == mystery_number => break,
            Some(_) => println!("Wrong! Try again!"),
            None => println!("Please enter an integer")
        }
    }

    // The loop ends only if the player wins
    println!("Well guessed!");
}
<|endoftext|>


<commit_before>//! Values taken from RFC 2616

/// OCTET: any 8-bit sequence of data (typechecking ensures this to be true)
#[inline]
pub fn is_octet(_: u8) -> bool { true }

/// CHAR: any US-ASCII character (octets 0 - 127)
#[inline]
pub fn is_char(octet: u8) -> bool { octet < 128 }

/// UPALPHA: any US-ASCII uppercase letter "A".."Z">
#[inline]
pub fn is_upalpha(octet: u8) -> bool { octet >= b'A' && octet <= b'Z' }

/// LOALPHA: any US-ASCII lowercase letter "a".."z">
#[inline]
pub fn is_loalpha(octet: u8) -> bool { octet >= b'a' && octet <= b'z' }

/// ALPHA: UPALPHA | LOALPHA
#[inline]
pub fn is_alpha(octet: u8) -> bool { is_upalpha(octet) || is_loalpha(octet) }

/// DIGIT: any US-ASCII digit "0".."9"
#[inline]
pub fn is_digit(octet: u8) -> bool { octet >= b'0' && octet <= b'9' }

/// CTL: any US-ASCII control character (octets 0 - 31) and DEL (127)
#[inline]
pub fn is_ctl(octet: u8) -> bool { octet < 32 || octet == 127 }

/// CR: US-ASCII CR, carriage return (13)
pub const CR: u8 = b'\r';

/// LF: US-ASCII LF, linefeed (10)
pub const LF: u8 = b'\n';

/// SP: US-ASCII SP, space (32)
pub const SP: u8 = b' ';

/// HT: US-ASCII HT, horizontal-tab (9)
pub const HT: u8 = b'\t';

/// US-ASCII colon (58)
pub const COLON: u8 = b':';

/// <">: US-ASCII double-quote mark (34)
pub const DOUBLE_QUOTE: u8 = b'"';

/// "\": US-ASCII backslash (92)
pub const BACKSLASH: u8 = b'\\';

// CRLF: CR LF
//const CRLF: [u8] = [CR, LF];

// LWS: [CRLF] 1*( SP | HT )
/*#[inline]
fn is_lws(octets: &[u8]) -> bool {
    let mut has_crlf = false;
    let mut iter = octets.iter();
    if len(octets) == 0 {
        return false;
    }
    if len(octets) > 2 && octets[0] == CR && octets[1] == LF {
        iter = iter.next().next();
    }
    iter.all(|&octet| octet == SP || octet == HT)
}
*/

/*
   The TEXT rule is only used for descriptive field contents and values
   that are not intended to be interpreted by the message parser. Words
   of *TEXT MAY contain characters from character sets other than ISO-
   8859-1 [22] only when encoded according to the rules of RFC 2047
   [14].

       TEXT           = <any OCTET except CTLs,
                        but including LWS>

   A CRLF is allowed in the definition of TEXT only as part of a header
   field continuation. It is expected that the folding LWS will be
   replaced with a single SP before interpretation of the TEXT value.
*/

/// HEX: "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f" | DIGIT
#[inline]
pub fn is_hex(octet: u8) -> bool {
    (octet >= b'A' && octet <= b'F') ||
    (octet >= b'a' && octet <= b'f') ||
    is_digit(octet)
}

/// token          = 1*<any CHAR except CTLs or separators>
#[inline]
pub fn is_token_item(o: u8) -> bool {
    is_char(o) && !is_ctl(o) && !is_separator(o)
}

#[inline]
pub fn is_token(s: &String) -> bool {
    s[].bytes().all(|b| is_token_item(b))
}

/// separators: "(" | ")" | "<" | ">" | "@" | "," | ";" | ":"
///           | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{"
///           | "}" | SP | HT
#[inline]
pub fn is_separator(o: u8) -> bool {
    o == b'(' || o == b')' || o == b'<' || o == b'>' || o == b'@' ||
    o == b',' || o == b';' || o == b':' || o == b'\\' || o == b'"' ||
    o == b'/' || o == b'[' || o == b']' || o == b'?' || o == b'=' ||
    o == b'{' || o == b'}' || o == SP || o == HT
}

/*
 * Comments can be included in some HTTP header fields by surrounding
 * the comment text with parentheses. Comments are only allowed in
 * fields containing "comment" as part of their field value definition.
 * In all other fields, parentheses are considered part of the field
 * value.
 *
 *     comment        = "(" *( ctext | quoted-pair | comment ) ")"
 *     ctext          = <any TEXT excluding "(" and ")">
 *
 * A string of text is parsed as a single word if it is quoted using
 * double-quote marks.
 *
 *     quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> )
 *     qdtext         = <any TEXT except <">>
 *
 * The backslash character ("\") MAY be used as a single-character
 * quoting mechanism only within quoted-string and comment constructs.
 *
 *     quoted-pair    = "\" CHAR
 */
//#[inline]
//fn is_quoted_pair(o: &[u8, ..2]) { o[0] == 92 }

// IANA is assigned as maintaining the registry for these things:
// see https://www.iana.org/assignments/http-parameters/http-parameters.xml

mod content_coding {
    use std::fmt;
    use std::str::FromStr;

    use self::ValueToken::{Gzip, Compress, Deflate, Identity};

    /// Content-coding value tokens
    pub enum ValueToken {
        // An encoding format produced by the file compression program "gzip" (GNU zip) as described
        // in RFC 1952 [25]. This format is a Lempel-Ziv coding (LZ77) with a 32 bit CRC.
        Gzip,

        // The encoding format produced by the common UNIX file compression program "compress". This
        // format is an adaptive Lempel-Ziv-Welch coding (LZW).
        //
        // Use of program names for the identification of encoding formats is not desirable and is
        // discouraged for future encodings. Their use here is representative of historical
        // practice, not good design. For compatibility with previous implementations of HTTP,
        // applications SHOULD consider "x-gzip" and "x-compress" to be equivalent to "gzip" and
        // "compress" respectively.
        Compress,

        // The "zlib" format defined in RFC 1950 [31] in combination with the "deflate" compression
        // mechanism described in RFC 1951 [29].
        Deflate,

        // The default (identity) encoding; the use of no transformation whatsoever. This
        // content-coding is used only in the Accept- Encoding header, and SHOULD NOT be used in the
        // Content-Encoding header.
        Identity,

        // IANA has also assigned the following currently unsupported content codings:
        //
        // - "exi": W3C Efficient XML Interchange
        // - "pack200-gzip" (Network Transfer Format for Java Archives)
    }
    impl fmt::Show for ValueToken {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            f.write(match *self {
                Gzip => b"gzip",
                Compress => b"compress",
                Deflate => b"deflate",
                Identity => b"identity",
            })
        }
    }
    impl FromStr for ValueToken {
        fn from_str(s: &str) -> Option<ValueToken> {
            use std::ascii::AsciiExt;
            match s.to_ascii_lower()[] {
                "gzip" => Some(Gzip),
                "compress" => Some(Compress),
                "deflate" => Some(Deflate),
                "identity" => Some(Identity),
                _ => None,
            }
        }
    }
}

mod transfer_coding {
    use std::fmt;

    use self::ValueToken::{Chunked, Gzip, Compress, Deflate};

    /// Transfer-coding value tokens
    // Identity is in RFC 2616 but is withdrawn in RFC 2616 errata ID 408
    // http://www.rfc-editor.org/errata_search.php?rfc=2616&eid=408
    pub enum ValueToken {
        Chunked,   // RFC 2616, §3.6.1
        Gzip,      // See above
        Compress,  // See above
        Deflate,   // See above
    }
    impl fmt::Show for ValueToken {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            f.write(match *self {
                Chunked => b"chunked",
                Gzip => b"gzip",
                Compress => b"compress",
                Deflate => b"deflate",
            })
        }
    }
}

// A server which receives an entity-body with a transfer-coding it does
// not understand SHOULD return 501 (Unimplemented), and close the
// connection. A server MUST NOT send transfer-codings to an HTTP/1.0
// client.

// [My note: implication of this is that I need to track HTTP version number of clients.]
<commit_msg>De-mod-ify some stuff enum scoping makes possible<commit_after>//! Values taken from RFC 2616

use std::fmt;
use std::str::FromStr;
use std::ascii::AsciiExt;

/// OCTET: any 8-bit sequence of data (typechecking ensures this to be true)
#[inline]
pub fn is_octet(_: u8) -> bool { true }

/// CHAR: any US-ASCII character (octets 0 - 127)
#[inline]
pub fn is_char(octet: u8) -> bool { octet < 128 }

/// UPALPHA: any US-ASCII uppercase letter "A".."Z">
#[inline]
pub fn is_upalpha(octet: u8) -> bool { octet >= b'A' && octet <= b'Z' }

/// LOALPHA: any US-ASCII lowercase letter "a".."z">
#[inline]
pub fn is_loalpha(octet: u8) -> bool { octet >= b'a' && octet <= b'z' }

/// ALPHA: UPALPHA | LOALPHA
#[inline]
pub fn is_alpha(octet: u8) -> bool { is_upalpha(octet) || is_loalpha(octet) }

/// DIGIT: any US-ASCII digit "0".."9"
#[inline]
pub fn is_digit(octet: u8) -> bool { octet >= b'0' && octet <= b'9' }

/// CTL: any US-ASCII control character (octets 0 - 31) and DEL (127)
#[inline]
pub fn is_ctl(octet: u8) -> bool { octet < 32 || octet == 127 }

/// CR: US-ASCII CR, carriage return (13)
pub const CR: u8 = b'\r';

/// LF: US-ASCII LF, linefeed (10)
pub const LF: u8 = b'\n';

/// SP: US-ASCII SP, space (32)
pub const SP: u8 = b' ';

/// HT: US-ASCII HT, horizontal-tab (9)
pub const HT: u8 = b'\t';

/// US-ASCII colon (58)
pub const COLON: u8 = b':';

/// <">: US-ASCII double-quote mark (34)
pub const DOUBLE_QUOTE: u8 = b'"';

/// "\": US-ASCII backslash (92)
pub const BACKSLASH: u8 = b'\\';

// CRLF: CR LF
//const CRLF: [u8] = [CR, LF];

// LWS: [CRLF] 1*( SP | HT )
/*#[inline]
fn is_lws(octets: &[u8]) -> bool {
    let mut has_crlf = false;
    let mut iter = octets.iter();
    if len(octets) == 0 {
        return false;
    }
    if len(octets) > 2 && octets[0] == CR && octets[1] == LF {
        iter = iter.next().next();
    }
    iter.all(|&octet| octet == SP || octet == HT)
}
*/

/*
   The TEXT rule is only used for descriptive field contents and values
   that are not intended to be interpreted by the message parser. Words
   of *TEXT MAY contain characters from character sets other than ISO-
   8859-1 [22] only when encoded according to the rules of RFC 2047
   [14].

       TEXT           = <any OCTET except CTLs,
                        but including LWS>

   A CRLF is allowed in the definition of TEXT only as part of a header
   field continuation. It is expected that the folding LWS will be
   replaced with a single SP before interpretation of the TEXT value.
*/

/// HEX: "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f" | DIGIT
#[inline]
pub fn is_hex(octet: u8) -> bool {
    (octet >= b'A' && octet <= b'F') ||
    (octet >= b'a' && octet <= b'f') ||
    is_digit(octet)
}

/// token          = 1*<any CHAR except CTLs or separators>
#[inline]
pub fn is_token_item(o: u8) -> bool {
    is_char(o) && !is_ctl(o) && !is_separator(o)
}

#[inline]
pub fn is_token(s: &String) -> bool {
    s[].bytes().all(|b| is_token_item(b))
}

/// separators: "(" | ")" | "<" | ">" | "@" | "," | ";" | ":"
///           | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{"
///           | "}" | SP | HT
#[inline]
pub fn is_separator(o: u8) -> bool {
    o == b'(' || o == b')' || o == b'<' || o == b'>' || o == b'@' ||
    o == b',' || o == b';' || o == b':' || o == b'\\' || o == b'"' ||
    o == b'/' || o == b'[' || o == b']' || o == b'?' || o == b'=' ||
    o == b'{' || o == b'}' || o == SP || o == HT
}

/*
 * Comments can be included in some HTTP header fields by surrounding
 * the comment text with parentheses. Comments are only allowed in
 * fields containing "comment" as part of their field value definition.
 * In all other fields, parentheses are considered part of the field
 * value.
 *
 *     comment        = "(" *( ctext | quoted-pair | comment ) ")"
 *     ctext          = <any TEXT excluding "(" and ")">
 *
 * A string of text is parsed as a single word if it is quoted using
 * double-quote marks.
 *
 *     quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> )
 *     qdtext         = <any TEXT except <">>
 *
 * The backslash character ("\") MAY be used as a single-character
 * quoting mechanism only within quoted-string and comment constructs.
 *
 *     quoted-pair    = "\" CHAR
 */
//#[inline]
//fn is_quoted_pair(o: &[u8, ..2]) { o[0] == 92 }

// IANA is assigned as maintaining the registry for these things:
// see https://www.iana.org/assignments/http-parameters/http-parameters.xml

/// Content-coding value tokens
pub enum ContentCoding {
    // An encoding format produced by the file compression program "gzip" (GNU zip) as described
    // in RFC 1952 [25]. This format is a Lempel-Ziv coding (LZ77) with a 32 bit CRC.
    Gzip,

    // The encoding format produced by the common UNIX file compression program "compress". This
    // format is an adaptive Lempel-Ziv-Welch coding (LZW).
    //
    // Use of program names for the identification of encoding formats is not desirable and is
    // discouraged for future encodings. Their use here is representative of historical
    // practice, not good design. For compatibility with previous implementations of HTTP,
    // applications SHOULD consider "x-gzip" and "x-compress" to be equivalent to "gzip" and
    // "compress" respectively.
    Compress,

    // The "zlib" format defined in RFC 1950 [31] in combination with the "deflate" compression
    // mechanism described in RFC 1951 [29].
    Deflate,

    // The default (identity) encoding; the use of no transformation whatsoever. This
    // content-coding is used only in the Accept- Encoding header, and SHOULD NOT be used in the
    // Content-Encoding header.
    Identity,

    // IANA has also assigned the following currently unsupported content codings:
    //
    // - "exi": W3C Efficient XML Interchange
    // - "pack200-gzip" (Network Transfer Format for Java Archives)
}

impl fmt::Show for ContentCoding {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write(match *self {
            ContentCoding::Gzip => b"gzip",
            ContentCoding::Compress => b"compress",
            ContentCoding::Deflate => b"deflate",
            ContentCoding::Identity => b"identity",
        })
    }
}

impl FromStr for ContentCoding {
    fn from_str(s: &str) -> Option<ContentCoding> {
        if s.eq_ignore_ascii_case("gzip") {
            Some(ContentCoding::Gzip)
        } else if s.eq_ignore_ascii_case("compress") {
            Some(ContentCoding::Compress)
        } else if s.eq_ignore_ascii_case("deflate") {
            Some(ContentCoding::Deflate)
        } else if s.eq_ignore_ascii_case("identity") {
            Some(ContentCoding::Identity)
        } else {
            None
        }
    }
}

/// Transfer-coding value tokens
// Identity is in RFC 2616 but is withdrawn in RFC 2616 errata ID 408
// http://www.rfc-editor.org/errata_search.php?rfc=2616&eid=408
pub enum TransferCoding {
    Chunked,   // RFC 2616, §3.6.1
    Gzip,      // See above
    Compress,  // See above
    Deflate,   // See above
}

impl fmt::Show for TransferCoding {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write(match *self {
            TransferCoding::Chunked => b"chunked",
            TransferCoding::Gzip => b"gzip",
            TransferCoding::Compress => b"compress",
            TransferCoding::Deflate => b"deflate",
        })
    }
}

impl FromStr for TransferCoding {
    fn from_str(s: &str) -> Option<TransferCoding> {
        if s.eq_ignore_ascii_case("gzip") {
            Some(TransferCoding::Gzip)
        } else if s.eq_ignore_ascii_case("compress") {
            Some(TransferCoding::Compress)
        } else if s.eq_ignore_ascii_case("deflate") {
            Some(TransferCoding::Deflate)
        } else if s.eq_ignore_ascii_case("chunked") {
            Some(TransferCoding::Chunked)
        } else {
            None
        }
    }
}

// A server which receives an entity-body with a transfer-coding it does
// not understand SHOULD return 501 (Unimplemented), and close the
// connection. A server MUST NOT send transfer-codings to an HTTP/1.0
// client.

// [My note: implication of this is that I need to track HTTP version number of clients.]
<|endoftext|>


<commit_before>#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]
#![cfg(all(unix, not(target_os = "dragonfly")))]

use tokio::net::UnixStream;

use libc::getegid;
use libc::geteuid;

#[tokio::test]
#[cfg_attr(
    target_os = "freebsd",
    ignore = "Requires FreeBSD 12.0 or later. https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=176419"
)]
#[cfg_attr(
    target_os = "netbsd",
    ignore = "NetBSD does not support getpeereid() for sockets created by socketpair()"
)]
async fn test_socket_pair() {
    let (a, b) = UnixStream::pair().unwrap();
    let cred_a = a.peer_cred().unwrap();
    let cred_b = b.peer_cred().unwrap();
    assert_eq!(cred_a, cred_b);

    let uid = unsafe { geteuid() };
    let gid = unsafe { getegid() };

    assert_eq!(cred_a.uid(), uid);
    assert_eq!(cred_a.gid(), gid);
}
<commit_msg>chore: re-enable test_socket_pair on FreeBSD (#3844)<commit_after>#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]
#![cfg(all(unix, not(target_os = "dragonfly")))]

use tokio::net::UnixStream;

use libc::getegid;
use libc::geteuid;

#[tokio::test]
#[cfg_attr(
    target_os = "netbsd",
    ignore = "NetBSD does not support getpeereid() for sockets created by socketpair()"
)]
async fn test_socket_pair() {
    let (a, b) = UnixStream::pair().unwrap();
    let cred_a = a.peer_cred().unwrap();
    let cred_b = b.peer_cred().unwrap();
    assert_eq!(cred_a, cred_b);

    let uid = unsafe { geteuid() };
    let gid = unsafe { getegid() };

    assert_eq!(cred_a.uid(), uid);
    assert_eq!(cred_a.gid(), gid);
}
<|endoftext|>