<commit_before>//! iOS support
//!
//! # Building app
//! To build ios app you will need rustc built for this targets:
//!
//!  - armv7-apple-ios
//!  - armv7s-apple-ios
//!  - i386-apple-ios
//!  - aarch64-apple-ios
//!  - x86_64-apple-ios
//!
//! Then
//!
//! ```
//! cargo build --target=...
//! ```
//! The simplest way to integrate your app into xcode environment is to build it
//! as a static library. Wrap your main function and export it.
//!
//! ```rust, ignore
//! #[no_mangle]
//! pub extern fn start_glutin_app() {
//!     start_inner()
//! }
//!
//! fn start_inner() {
//!    ...
//! }
//!
//! ```
//!
//! Compile project and then drag resulting .a into Xcode project. Add glutin.h to xcode.
//!
//! ```ignore
//! void start_glutin_app();
//! ```
//!
//! Use start_glutin_app inside your xcode's main function.
//!
//!
//! # App lifecycle and events
//!
//! iOS environment is very different from other platforms and you must be very
//! careful with it's events. Familiarize yourself with
//! [app lifecycle](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/).
//!
//!
//! This is how those event are represented in glutin:
//!
//!  - applicationDidBecomeActive is Focused(true)
//!  - applicationWillResignActive is Focused(false)
//!  - applicationDidEnterBackground is Suspended(true)
//!  - applicationWillEnterForeground is Suspended(false)
//!  - applicationWillTerminate is Closed
//!
//! Keep in mind that after Closed event is received every attempt to draw with
//! opengl will result in segfault.
//!
//! Also note that app will not receive Closed event if suspended, it will be SIGKILL'ed

#![cfg(target_os = "ios")]

use std::collections::VecDeque;
use std::ptr;
use std::mem;
use std::os::raw::c_void;

use libc;
use libc::c_int;
use objc::runtime::{Class, Object, Sel, BOOL, YES };
use objc::declare::{ ClassDecl };

use { CreationError, CursorState, MouseCursor, WindowAttributes, FullScreenState };
use WindowEvent as Event;
use events::{ Touch, TouchPhase };

mod ffi;
use self::ffi::{
    setjmp,
    UIApplicationMain,
    CFTimeInterval,
    CFRunLoopRunInMode,
    kCFRunLoopDefaultMode,
    kCFRunLoopRunHandledSource,
    id,
    nil,
    NSString,
    CGFloat,
    longjmp,
    CGRect,
    CGPoint
 };

static mut jmpbuf: [c_int;27] = [0;27];

#[derive(Clone)]
pub struct MonitorId;

pub struct Window {
    delegate_state: *mut DelegateState
}

#[derive(Clone)]
pub struct WindowProxy;

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

#[derive(Debug)]
struct DelegateState {
    events_queue: VecDeque<Event>,
    window: id,
    controller: id,
    size: (u32,u32),
    scale: f32
}

impl DelegateState {
    #[inline]
    fn new(window: id, controller:id, size: (u32,u32), scale: f32) -> DelegateState {
        DelegateState {
            events_queue: VecDeque::new(),
            window: window,
            controller: controller,
            size: size,
            scale: scale
        }
    }
}

#[inline]
pub fn get_available_monitors() -> VecDeque<MonitorId> {
    let mut rb = VecDeque::new();
    rb.push_back(MonitorId);
    rb
}

#[inline]
pub fn get_primary_monitor() -> MonitorId {
    MonitorId
}

impl MonitorId {
    #[inline]
    pub fn get_name(&self) -> Option<String> {
        Some("Primary".to_string())
    }

    #[inline]
    pub fn get_dimensions(&self) -> (u32, u32) {
        unimplemented!()
    }
}

gen_api_transition!();

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;

impl Window {

    pub fn new(_: &WindowAttributes, _: &PlatformSpecificWindowBuilderAttributes) -> Result<Window, CreationError>
    {
        unsafe {
            if setjmp(mem::transmute(&mut jmpbuf)) != 0 {
                let app: id = msg_send![Class::get("UIApplication").unwrap(), sharedApplication];
                let delegate: id = msg_send![app, delegate];
                let state: *mut c_void = *(&*delegate).get_ivar("glutinState");
                let state = state as *mut DelegateState;

                let window = Window {
                    delegate_state: state
                };

                return Ok(window)
            }
        }

        Window::create_delegate_class();
        Window::create_view_class();
        Window::start_app();

        Err(CreationError::OsError(format!("Couldn't create UIApplication")))
    }

    fn create_delegate_class() {
        extern fn did_finish_launching(this: &mut Object, _: Sel, _: id, _: id) -> BOOL {
            unsafe {
                let main_screen: id = msg_send![Class::get("UIScreen").unwrap(), mainScreen];
                let bounds: CGRect = msg_send![main_screen, bounds];
                let scale: CGFloat = msg_send![main_screen, nativeScale];

                let window: id = msg_send![Class::get("UIWindow").unwrap(), alloc];
                let window: id = msg_send![window, initWithFrame:bounds.clone()];

                let size = (bounds.size.width as u32, bounds.size.height as u32);

                let view_controller: id = msg_send![Class::get("MainViewController").unwrap(), alloc];
                let view_controller: id = msg_send![view_controller, init];

                let _: () = msg_send![window, setRootViewController:view_controller];
                let _: () = msg_send![window, makeKeyAndVisible];

                let state = Box::new(DelegateState::new(window, view_controller, size, scale as f32));
                let state_ptr: *mut DelegateState = mem::transmute(state);
                this.set_ivar("glutinState", state_ptr as *mut c_void);

                let _: () = msg_send![this, performSelector:sel!(postLaunch:) withObject:nil afterDelay:0.0];
            }
            YES
        }

        extern fn post_launch(_: &Object, _: Sel, _: id) {
            unsafe { longjmp(mem::transmute(&mut jmpbuf),1); }
        }

        extern fn did_become_active(this: &Object, _: Sel, _: id) {
            unsafe {
                let state: *mut c_void = *this.get_ivar("glutinState");
                let state = &mut *(state as *mut DelegateState);
                state.events_queue.push_back(Event::Focused(true));
            }
        }

        extern fn will_resign_active(this: &Object, _: Sel, _: id) {
            unsafe {
                let state: *mut c_void = *this.get_ivar("glutinState");
                let state = &mut *(state as *mut DelegateState);
                state.events_queue.push_back(Event::Focused(false));
            }
        }

        extern fn will_enter_foreground(this: &Object, _: Sel, _: id) {
            unsafe {
                let state: *mut c_void = *this.get_ivar("glutinState");
                let state = &mut *(state as *mut DelegateState);
                state.events_queue.push_back(Event::Suspended(false));
            }
        }

        extern fn did_enter_background(this: &Object, _: Sel, _: id) {
            unsafe {
                let state: *mut c_void = *this.get_ivar("glutinState");
                let state = &mut *(state as *mut DelegateState);
                state.events_queue.push_back(Event::Suspended(true));
            }
        }

        extern fn will_terminate(this: &Object, _: Sel, _: id) {
            unsafe {
                let state: *mut c_void = *this.get_ivar("glutinState");
                let state = &mut *(state as *mut DelegateState);
                // push event to the front to garantee that we'll process it
                // immidiatly after jump
                state.events_queue.push_front(Event::Closed);
                longjmp(mem::transmute(&mut jmpbuf),1);
            }
        }

        extern fn handle_touches(this: &Object, _: Sel, touches: id, _:id) {
            unsafe {
                let state: *mut c_void = *this.get_ivar("glutinState");
                let state = &mut *(state as *mut DelegateState);

                let touches_enum: id = msg_send![touches, objectEnumerator];

                loop {
                    let touch: id = msg_send![touches_enum, nextObject];
                    if touch == nil {
                        break
                    }
                    let location: CGPoint = msg_send![touch, locationInView:nil];
                    let touch_id = touch as u64;
                    let phase: i32 = msg_send![touch, phase];

                    state.events_queue.push_back(Event::Touch(Touch {
                        device_id: DEVICE_ID,
                        id: touch_id,
                        location: (location.x as f64, location.y as f64),
                        phase: match phase {
                            0 => TouchPhase::Started,
                            1 => TouchPhase::Moved,
                            // 2 is UITouchPhaseStationary and is not expected here
                            3 => TouchPhase::Ended,
                            4 => TouchPhase::Cancelled,
                            _ => panic!("unexpected touch phase: {:?}", phase)
                        }
                    }));
                }
            }
        }

        let ui_responder = Class::get("UIResponder").unwrap();
        let mut decl = ClassDecl::new("AppDelegate", ui_responder).unwrap();

        unsafe {
            decl.add_method(sel!(application:didFinishLaunchingWithOptions:),
                            did_finish_launching as extern fn(&mut Object, Sel, id, id) -> BOOL);

            decl.add_method(sel!(applicationDidBecomeActive:),
                            did_become_active as extern fn(&Object, Sel, id));

            decl.add_method(sel!(applicationWillResignActive:),
                            will_resign_active as extern fn(&Object, Sel, id));

            decl.add_method(sel!(applicationWillEnterForeground:),
                            will_enter_foreground as extern fn(&Object, Sel, id));

            decl.add_method(sel!(applicationDidEnterBackground:),
                            did_enter_background as extern fn(&Object, Sel, id));

            decl.add_method(sel!(applicationWillTerminate:),
                            will_terminate as extern fn(&Object, Sel, id));

            decl.add_method(sel!(touchesBegan:withEvent:),
                            handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));

            decl.add_method(sel!(touchesMoved:withEvent:),
                            handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));

            decl.add_method(sel!(touchesEnded:withEvent:),
                            handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));

            decl.add_method(sel!(touchesCancelled:withEvent:),
                            handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));

            decl.add_method(sel!(postLaunch:),
                            post_launch as extern fn(&Object, Sel, id));

            decl.add_ivar::<*mut c_void>("glutinState");

            decl.register();
        }
    }

    fn create_view_class() {
        let ui_view_controller = Class::get("UIViewController").unwrap();
        let decl = ClassDecl::new("MainViewController", ui_view_controller).unwrap();

        decl.register();
    }

    #[inline]
    fn start_app() {
        unsafe {
            UIApplicationMain(0, ptr::null(), nil, NSString::alloc(nil).init_str("AppDelegate"));
        }
    }

    #[inline]
    pub fn set_title(&self, _: &str) {
    }

    #[inline]
    pub fn show(&self) {
    }

    #[inline]
    pub fn hide(&self) {
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        None
    }

    #[inline]
    pub fn set_position(&self, _x: i32, _y: i32) {
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        unsafe { Some((&*self.delegate_state).size) }
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        self.get_inner_size()
    }

    #[inline]
    pub fn set_inner_size(&self, _x: u32, _y: u32) {
    }

    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        unimplemented!();
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        unimplemented!()
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
    }

    #[inline]
    pub fn set_cursor(&self, _: MouseCursor) {
    }

    #[inline]
    pub fn set_cursor_state(&self, _: CursorState) -> Result<(), String> {
        Ok(())
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        unsafe { (&*self.delegate_state) }.scale
    }

    #[inline]
    pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> {
        unimplemented!();
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy
    }

    #[inline]
    pub fn set_maximized(&self, maximized: bool) {
    }

    #[inline]
    pub fn set_fullscreen(&self, state: FullScreenState) {
    }
}

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        unimplemented!()
    }
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        loop {
            if let Some(ev) = self.window.poll_events().next() {
                return Some(ev);
            }
        }
    }
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        unsafe {
            let state = &mut *self.window.delegate_state;

            if let Some(event) = state.events_queue.pop_front() {
                return Some(event)
            }

            // jump hack, so we won't quit on willTerminate event before processing it
            if setjmp(mem::transmute(&mut jmpbuf)) != 0 {
                return state.events_queue.pop_front()
            }

            // run runloop
            let seconds: CFTimeInterval = 0.000002;
            while CFRunLoopRunInMode(kCFRunLoopDefaultMode, seconds, 1) == kCFRunLoopRunHandledSource {}

            state.events_queue.pop_front()
        }
    }
}

// Constant device ID, to be removed when this backend is updated to report real device IDs.
const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId);
<commit_msg>Update iOS for EventsLoop design (#275)<commit_after>//! iOS support
//!
//! # Building app
//! To build ios app you will need rustc built for this targets:
//!
//!  - armv7-apple-ios
//!  - armv7s-apple-ios
//!  - i386-apple-ios
//!  - aarch64-apple-ios
//!  - x86_64-apple-ios
//!
//! Then
//!
//! ```
//! cargo build --target=...
//! ```
//! The simplest way to integrate your app into xcode environment is to build it
//! as a static library. Wrap your main function and export it.
//!
//! ```rust, ignore
//! #[no_mangle]
//! pub extern fn start_glutin_app() {
//!     start_inner()
//! }
//!
//! fn start_inner() {
//!    ...
//! }
//!
//! ```
//!
//! Compile project and then drag resulting .a into Xcode project. Add glutin.h to xcode.
//!
//! ```ignore
//! void start_glutin_app();
//! ```
//!
//! Use start_glutin_app inside your xcode's main function.
//!
//!
//! # App lifecycle and events
//!
//! iOS environment is very different from other platforms and you must be very
//! careful with it's events. Familiarize yourself with
//! [app lifecycle](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/).
//!
//!
//! This is how those event are represented in glutin:
//!
//!  - applicationDidBecomeActive is Focused(true)
//!  - applicationWillResignActive is Focused(false)
//!  - applicationDidEnterBackground is Suspended(true)
//!  - applicationWillEnterForeground is Suspended(false)
//!  - applicationWillTerminate is Closed
//!
//! Keep in mind that after Closed event is received every attempt to draw with
//! opengl will result in segfault.
//!
//! Also note that app will not receive Closed event if suspended, it will be SIGKILL'ed

#![cfg(target_os = "ios")]

use std::collections::VecDeque;
use std::ptr;
use std::mem;
use std::os::raw::c_void;

use libc;
use libc::c_int;
use objc::runtime::{Class, Object, Sel, BOOL, YES };
use objc::declare::{ ClassDecl };

use { CreationError, CursorState, MouseCursor, WindowAttributes, FullScreenState };
use WindowId as RootEventId;
use WindowEvent;
use Event;
use events::{ Touch, TouchPhase };

mod ffi;
use self::ffi::{
    setjmp,
    UIApplicationMain,
    CFTimeInterval,
    CFRunLoopRunInMode,
    kCFRunLoopDefaultMode,
    kCFRunLoopRunHandledSource,
    id,
    nil,
    NSString,
    CGFloat,
    longjmp,
    CGRect,
    CGPoint
 };

static mut jmpbuf: [c_int;27] = [0;27];

#[derive(Clone)]
pub struct MonitorId;

pub struct Window2 {
    delegate_state: *mut DelegateState
}

#[derive(Clone)]
pub struct WindowProxy;

#[derive(Debug)]
struct DelegateState {
    events_queue: VecDeque<WindowEvent>,
    window: id,
    controller: id,
    size: (u32,u32),
    scale: f32
}

impl DelegateState {
    #[inline]
    fn new(window: id, controller:id, size: (u32,u32), scale: f32) -> DelegateState {
        DelegateState {
            events_queue: VecDeque::new(),
            window: window,
            controller: controller,
            size: size,
            scale: scale
        }
    }
}

impl MonitorId {
    #[inline]
    pub fn get_name(&self) -> Option<String> {
        Some("Primary".to_string())
    }

    #[inline]
    pub fn get_dimensions(&self) -> (u32, u32) {
        unimplemented!()
    }
}

pub struct EventsLoop {
    delegate_state: *mut DelegateState
}

pub struct EventsLoopProxy;

impl EventsLoop {
    pub fn new() -> EventsLoop {
        unsafe {
            if setjmp(mem::transmute(&mut jmpbuf)) != 0 {
                let app: id = msg_send![Class::get("UIApplication").unwrap(), sharedApplication];
                let delegate: id = msg_send![app, delegate];
                let state: *mut c_void = *(&*delegate).get_ivar("glutinState");
                let state = state as *mut DelegateState;

                let events_loop = EventsLoop {
                    delegate_state: state
                };

                return events_loop;
            }
        }

        create_delegate_class();
        create_view_class();
        start_app();

        panic!("Couldn't create UIApplication")
    }

    #[inline]
    pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
        let mut rb = VecDeque::new();
        rb.push_back(MonitorId);
        rb
    }

    #[inline]
    pub fn get_primary_monitor(&self) -> MonitorId {
        MonitorId
    }

    pub fn poll_events<F>(&mut self, mut callback: F)
        where F: FnMut(::Event)
    {
        unsafe {
            let state = &mut *self.delegate_state;

            if let Some(event) = state.events_queue.pop_front() {
                callback(Event::WindowEvent {
                    window_id: RootEventId(WindowId),
                    event: event,
                });
                return;
            }

            // jump hack, so we won't quit on willTerminate event before processing it
            if setjmp(mem::transmute(&mut jmpbuf)) != 0 {
                if let Some(event) = state.events_queue.pop_front() {
                    callback(Event::WindowEvent {
                        window_id: RootEventId(WindowId),
                        event: event,
                    });
                    return;
                }
            }

            // run runloop
            let seconds: CFTimeInterval = 0.000002;
            while CFRunLoopRunInMode(kCFRunLoopDefaultMode, seconds, 1) == kCFRunLoopRunHandledSource {}

            if let Some(event) = state.events_queue.pop_front() {
                callback(Event::WindowEvent {
                    window_id: RootEventId(WindowId),
                    event: event,
                })
            }
        }
    }

    pub fn run_forever<F>(&mut self, mut callback: F)
        where F: FnMut(::Event) -> ::ControlFlow,
    {
        // Yeah that's a very bad implementation.
        loop {
            let mut control_flow = ::ControlFlow::Continue;
            self.poll_events(|e| {
                if let ::ControlFlow::Break = callback(e) {
                    control_flow = ::ControlFlow::Break;
                }
            });
            if let ::ControlFlow::Break = control_flow {
                break;
            }
            ::std::thread::sleep(::std::time::Duration::from_millis(5));
        }
    }

    pub fn create_proxy(&self) -> EventsLoopProxy {
        EventsLoopProxy
    }
}

impl EventsLoopProxy {
    pub fn wakeup(&self) -> Result<(), ::EventsLoopClosed> {
        unimplemented!()
    }
}

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

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

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;

impl Window2 {
    pub fn new(ev: &EventsLoop, _: &WindowAttributes, _: &PlatformSpecificWindowBuilderAttributes)
               -> Result<Window2, CreationError>
    {
        Ok(Window2 {
            delegate_state: ev.delegate_state,
        })
    }

    #[inline]
    pub fn set_title(&self, _: &str) {
    }

    #[inline]
    pub fn show(&self) {
    }

    #[inline]
    pub fn hide(&self) {
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        None
    }

    #[inline]
    pub fn set_position(&self, _x: i32, _y: i32) {
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        unsafe { Some((&*self.delegate_state).size) }
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        self.get_inner_size()
    }

    #[inline]
    pub fn set_inner_size(&self, _x: u32, _y: u32) {
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        unimplemented!();
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        unimplemented!()
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
    }

    #[inline]
    pub fn set_cursor(&self, _: MouseCursor) {
    }

    #[inline]
    pub fn set_cursor_state(&self, _: CursorState) -> Result<(), String> {
        Ok(())
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        unsafe { (&*self.delegate_state) }.scale
    }

    #[inline]
    pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> {
        unimplemented!();
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy
    }

    #[inline]
    pub fn set_maximized(&self, maximized: bool) {
    }

    #[inline]
    pub fn set_fullscreen(&self, state: FullScreenState) {
    }

    #[inline]
    pub fn id(&self) -> WindowId {
        WindowId
    }
}

fn create_delegate_class() {
    extern fn did_finish_launching(this: &mut Object, _: Sel, _: id, _: id) -> BOOL {
        unsafe {
            let main_screen: id = msg_send![Class::get("UIScreen").unwrap(), mainScreen];
            let bounds: CGRect = msg_send![main_screen, bounds];
            let scale: CGFloat = msg_send![main_screen, nativeScale];

            let window: id = msg_send![Class::get("UIWindow").unwrap(), alloc];
            let window: id = msg_send![window, initWithFrame:bounds.clone()];

            let size = (bounds.size.width as u32, bounds.size.height as u32);

            let view_controller: id = msg_send![Class::get("MainViewController").unwrap(), alloc];
            let view_controller: id = msg_send![view_controller, init];

            let _: () = msg_send![window, setRootViewController:view_controller];
            let _: () = msg_send![window, makeKeyAndVisible];

            let state = Box::new(DelegateState::new(window, view_controller, size, scale as f32));
            let state_ptr: *mut DelegateState = mem::transmute(state);
            this.set_ivar("glutinState", state_ptr as *mut c_void);

            let _: () = msg_send![this, performSelector:sel!(postLaunch:) withObject:nil afterDelay:0.0];
        }
        YES
    }

    extern fn post_launch(_: &Object, _: Sel, _: id) {
        unsafe { longjmp(mem::transmute(&mut jmpbuf),1); }
    }

    extern fn did_become_active(this: &Object, _: Sel, _: id) {
        unsafe {
            let state: *mut c_void = *this.get_ivar("glutinState");
            let state = &mut *(state as *mut DelegateState);
            state.events_queue.push_back(WindowEvent::Focused(true));
        }
    }

    extern fn will_resign_active(this: &Object, _: Sel, _: id) {
        unsafe {
            let state: *mut c_void = *this.get_ivar("glutinState");
            let state = &mut *(state as *mut DelegateState);
            state.events_queue.push_back(WindowEvent::Focused(false));
        }
    }

    extern fn will_enter_foreground(this: &Object, _: Sel, _: id) {
        unsafe {
            let state: *mut c_void = *this.get_ivar("glutinState");
            let state = &mut *(state as *mut DelegateState);
            state.events_queue.push_back(WindowEvent::Suspended(false));
        }
    }

    extern fn did_enter_background(this: &Object, _: Sel, _: id) {
        unsafe {
            let state: *mut c_void = *this.get_ivar("glutinState");
            let state = &mut *(state as *mut DelegateState);
            state.events_queue.push_back(WindowEvent::Suspended(true));
        }
    }

    extern fn will_terminate(this: &Object, _: Sel, _: id) {
        unsafe {
            let state: *mut c_void = *this.get_ivar("glutinState");
            let state = &mut *(state as *mut DelegateState);
            // push event to the front to garantee that we'll process it
            // immidiatly after jump
            state.events_queue.push_front(WindowEvent::Closed);
            longjmp(mem::transmute(&mut jmpbuf),1);
        }
    }

    extern fn handle_touches(this: &Object, _: Sel, touches: id, _:id) {
        unsafe {
            let state: *mut c_void = *this.get_ivar("glutinState");
            let state = &mut *(state as *mut DelegateState);

            let touches_enum: id = msg_send![touches, objectEnumerator];

            loop {
                let touch: id = msg_send![touches_enum, nextObject];
                if touch == nil {
                    break
                }
                let location: CGPoint = msg_send![touch, locationInView:nil];
                let touch_id = touch as u64;
                let phase: i32 = msg_send![touch, phase];

                state.events_queue.push_back(WindowEvent::Touch(Touch {
                    device_id: DEVICE_ID,
                    id: touch_id,
                    location: (location.x as f64, location.y as f64),
                    phase: match phase {
                        0 => TouchPhase::Started,
                        1 => TouchPhase::Moved,
                        // 2 is UITouchPhaseStationary and is not expected here
                        3 => TouchPhase::Ended,
                        4 => TouchPhase::Cancelled,
                        _ => panic!("unexpected touch phase: {:?}", phase)
                    }
                }));
            }
        }
    }

    let ui_responder = Class::get("UIResponder").unwrap();
    let mut decl = ClassDecl::new("AppDelegate", ui_responder).unwrap();

    unsafe {
        decl.add_method(sel!(application:didFinishLaunchingWithOptions:),
                        did_finish_launching as extern fn(&mut Object, Sel, id, id) -> BOOL);

        decl.add_method(sel!(applicationDidBecomeActive:),
                        did_become_active as extern fn(&Object, Sel, id));

        decl.add_method(sel!(applicationWillResignActive:),
                        will_resign_active as extern fn(&Object, Sel, id));

        decl.add_method(sel!(applicationWillEnterForeground:),
                        will_enter_foreground as extern fn(&Object, Sel, id));

        decl.add_method(sel!(applicationDidEnterBackground:),
                        did_enter_background as extern fn(&Object, Sel, id));

        decl.add_method(sel!(applicationWillTerminate:),
                        will_terminate as extern fn(&Object, Sel, id));

        decl.add_method(sel!(touchesBegan:withEvent:),
                        handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));

        decl.add_method(sel!(touchesMoved:withEvent:),
                        handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));

        decl.add_method(sel!(touchesEnded:withEvent:),
                        handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));

        decl.add_method(sel!(touchesCancelled:withEvent:),
                        handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));

        decl.add_method(sel!(postLaunch:),
                        post_launch as extern fn(&Object, Sel, id));

        decl.add_ivar::<*mut c_void>("glutinState");

        decl.register();
    }
}

fn create_view_class() {
    let ui_view_controller = Class::get("UIViewController").unwrap();
    let decl = ClassDecl::new("MainViewController", ui_view_controller).unwrap();

    decl.register();
}

#[inline]
fn start_app() {
    unsafe {
        UIApplicationMain(0, ptr::null(), nil, NSString::alloc(nil).init_str("AppDelegate"));
    }
}

// Constant device ID, to be removed when this backend is updated to report real device IDs.
const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId);
<|endoftext|>


<commit_before>use std;
use extra::comm::DuplexStream;

use player;

pub struct WorldState {
    player_state: ~player::PlayerState,
    ticks: int,
}

impl WorldState {
    pub fn new(player_state: ~player::PlayerState) -> WorldState {
        WorldState{ticks: 0, player_state: player_state}
    }
}

impl Clone for WorldState {
    fn clone(&self) -> WorldState {
        WorldState{ticks: self.ticks, player_state: self.player_state.clone()}
    }
}

fn update_world_state(world_state: &WorldState, input: ~[int]) -> WorldState {
    let mut move_x = 0 as f32;
    let mut move_y = 0 as f32;

    for val in input.iter() {
        move_x = match *val {
            1073741903 => move_x + 1.0,
            _ => move_x
        }
    }

    WorldState{ticks: world_state.ticks + 1, player_state: ~world_state.player_state.move_by(move_x, move_y)}
}

/**
 Loop, updating the world state every time a value is sent on the timing port.
 Upon updating, the new world state is sent on the state server stream.
 */
pub fn world_handler(shared_timing_port: std::comm::Port<()>, player_state: ~player::PlayerState, world_state_server: DuplexStream<WorldState, ~[int]>) {
    let mut world_state = WorldState::new(player_state);

    'world : loop {
        shared_timing_port.recv();

        let input = world_state_server.recv();

        // update world state
        let updated_state = update_world_state(&world_state, input);
        world_state = updated_state;
        world_state_server.send(world_state.clone());
    }
}
<commit_msg>Take a vector slice instead of an owned pointer.<commit_after>use std;
use extra::comm::DuplexStream;

use player;

pub struct WorldState {
    player_state: ~player::PlayerState,
    ticks: int,
}

impl WorldState {
    pub fn new(player_state: ~player::PlayerState) -> WorldState {
        WorldState{ticks: 0, player_state: player_state}
    }
}

impl Clone for WorldState {
    fn clone(&self) -> WorldState {
        WorldState{ticks: self.ticks, player_state: self.player_state.clone()}
    }
}

fn update_world_state(world_state: &WorldState, input: &[int]) -> WorldState {
    let mut move_x = 0 as f32;
    let mut move_y = 0 as f32;

    for val in input.iter() {
        move_x = match *val {
            1073741903 => move_x + 1.0,
            _ => move_x
        }
    }

    WorldState{ticks: world_state.ticks + 1, player_state: ~world_state.player_state.move_by(move_x, move_y)}
}

/**
 Loop, updating the world state every time a value is sent on the timing port.
 Upon updating, the new world state is sent on the state server stream.
 */
pub fn world_handler(shared_timing_port: std::comm::Port<()>, player_state: ~player::PlayerState, world_state_server: DuplexStream<WorldState, ~[int]>) {
    let mut world_state = WorldState::new(player_state);

    'world : loop {
        shared_timing_port.recv();

        let input = world_state_server.recv();

        // update world state
        let updated_state = update_world_state(&world_state, input);
        world_state = updated_state;
        world_state_server.send(world_state.clone());
    }
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::path::Path;

use collada;
use gfx;
use gfx::traits::*;
use gfx_texture;

use math::*;
use skeleton::Skeleton;

const MAX_JOINTS: usize = 64;

pub struct SkinnedRenderBatch<R: gfx::Resources> {
    skinning_transforms_buffer: gfx::BufferHandle<R, [[f32; 4]; 4]>,
    batch: gfx::batch::RefBatch<SkinnedShaderParams<R>>,
}

pub struct SkinnedRenderer<R: gfx::Resources> {
    skeleton: Skeleton, // TODO Should this be a ref? Should this just be the joints?
    render_batches: Vec<SkinnedRenderBatch<R>>,
}

impl<R: gfx::Resources> SkinnedRenderer<R> {

    pub fn from_collada<
        C: gfx::CommandBuffer<R>,
        F: gfx::Factory<R>,
        D: Device<Resources = R, CommandBuffer = C>,
    > (
        graphics: &mut gfx::Graphics<D, F>,
        collada_document: collada::document::ColladaDocument,
        texture_paths: Vec<&str>, // TODO - read from the COLLADA document (if available)
    ) -> Result<SkinnedRenderer<R>, gfx::ProgramError> {

        let program = match graphics.factory.link_program(SKINNED_VERTEX_SHADER.clone(), SKINNED_FRAGMENT_SHADER.clone()) {
            Ok(program_handle) => program_handle,
            Err(e) => return Err(e),
        };

        let obj_set = collada_document.get_obj_set().unwrap();

        let mut skeleton_set = collada_document.get_skeletons().unwrap();
        let mut animations = collada_document.get_animations();
        let skeleton = Skeleton::from_collada(&skeleton_set[0]);

        let mut render_batches = Vec::new();

        for (i, object) in obj_set.objects.iter().enumerate().take(6) {

            let mut vertex_data: Vec<SkinnedVertex> = Vec::new();
            let mut index_data: Vec<u32> = Vec::new();

            get_vertex_index_data(&object, &mut vertex_data, &mut index_data);

            let mesh = graphics.factory.create_mesh(vertex_data.as_slice());

            let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

            let slice = graphics.factory
                .create_buffer_index::<u32>(index_data.as_slice())
                .to_slice(gfx::PrimitiveType::TriangleList);

            let skinning_transforms_buffer = graphics.factory.create_buffer::<[[f32; 4]; 4]>(MAX_JOINTS, gfx::BufferUsage::Dynamic);

            let texture = gfx_texture::Texture::from_path(
                &mut graphics.factory,
                &Path::new(&texture_paths[i]),
                &gfx_texture::Settings::new()
            ).unwrap();

            let sampler = graphics.factory.create_sampler(
                gfx::tex::SamplerInfo::new(
                    gfx::tex::FilterMethod::Trilinear,
                    gfx::tex::WrapMode::Clamp
                    )
                );

            let shader_params = SkinnedShaderParams {
                u_model_view_proj: mat4_id(),
                u_model_view: mat4_id(),
                u_skinning_transforms: skinning_transforms_buffer.raw().clone(),
                u_texture: (texture.handle, Some(sampler)),
            };

            let batch: gfx::batch::RefBatch<SkinnedShaderParams<R>> = graphics.make_batch(&program, shader_params, &mesh, slice, &state).unwrap();

            render_batches.push(SkinnedRenderBatch {
                batch: batch,
                skinning_transforms_buffer: skinning_transforms_buffer,
            });
        }

        Ok(SkinnedRenderer {
            render_batches: render_batches,
            skeleton: skeleton.clone(),
        })
    }

    pub fn render<
        C: gfx::CommandBuffer<R>,
        F: gfx::Factory<R>,
        D: Device<Resources = R, CommandBuffer = C>,
    >(
        &mut self,
        graphics: &mut gfx::Graphics<D, F>,
        frame: &gfx::Frame<R>,
        view: [[f32; 4]; 4],
        projection: [[f32; 4]; 4],
        joint_poses: &[Matrix4<f32>]
    ) {

        let skinning_transforms = self.calculate_skinning_transforms(&joint_poses);

        for material in self.render_batches.iter_mut() {
            material.batch.params.u_model_view = view;
            material.batch.params.u_model_view_proj = projection;

            // FIXME -- should all be able to share the same buffer
            graphics.factory.update_buffer(&material.skinning_transforms_buffer, &skinning_transforms[..], 0);

            graphics.draw(&material.batch, frame).unwrap();
        }
    }

    ///
    /// TODO - don't allocate a new vector
    ///
    pub fn calculate_skinning_transforms(&self, global_poses: &[Matrix4<f32>]) -> Vec<Matrix4<f32>> {

        use std::f32::consts::PI;
        use std::num::{Float};

        self.skeleton.joints.iter().enumerate().map(|(i, joint)| {
            row_mat4_mul(global_poses[i], joint.inverse_bind_pose)
        }).collect()
    }
}

#[shader_param]
struct SkinnedShaderParams<R: gfx::Resources> {
    u_model_view_proj: [[f32; 4]; 4],
    u_model_view: [[f32; 4]; 4],
    u_skinning_transforms: gfx::RawBufferHandle<R>,
    u_texture: gfx::shade::TextureParam<R>,
}

#[vertex_format]
#[derive(Copy)]
#[derive(Clone)]
#[derive(Debug)]
struct SkinnedVertex {
    pos: [f32; 3],
    normal: [f32; 3],
    uv: [f32; 2],
    joint_indices: [i32; 4],
    joint_weights: [f32; 4], // TODO last weight is redundant
}

impl Default for SkinnedVertex {
    fn default() -> SkinnedVertex {
        SkinnedVertex {
            pos: [0.0; 3],
            normal: [0.0; 3],
            uv: [0.0; 2],
            joint_indices: [0; 4],
            joint_weights: [0.0; 4],
        }
    }
}

static SKINNED_VERTEX_SHADER: &'static [u8] = b"
    #version 150 core

    uniform mat4 u_model_view_proj;
    uniform mat4 u_model_view;

    const int MAX_JOINTS = 64;

    uniform u_skinning_transforms {
        mat4 skinning_transforms[MAX_JOINTS];
    };

    in vec3 pos, normal;
    in vec2 uv;

    in ivec4 joint_indices;
    in vec4 joint_weights;

    out vec3 v_normal;
    out vec2 v_TexCoord;

    void main() {
        v_TexCoord = vec2(uv.x, 1 - uv.y); // this feels like a bug with gfx?

        vec4 adjustedVertex;
        vec4 adjustedNormal;

        vec4 bindPoseVertex = vec4(pos, 1.0);
        vec4 bindPoseNormal = vec4(normal, 0.0);

        adjustedVertex = bindPoseVertex * skinning_transforms[joint_indices.x] * joint_weights.x;
        adjustedNormal = bindPoseNormal * skinning_transforms[joint_indices.x] * joint_weights.x;

        adjustedVertex = adjustedVertex + bindPoseVertex * skinning_transforms[joint_indices.y] * joint_weights.y;
        adjustedNormal = adjustedNormal + bindPoseNormal * skinning_transforms[joint_indices.y] * joint_weights.y;

        adjustedVertex = adjustedVertex + bindPoseVertex * skinning_transforms[joint_indices.z] * joint_weights.z;
        adjustedNormal = adjustedNormal + bindPoseNormal * skinning_transforms[joint_indices.z] * joint_weights.z;

        // TODO just use remainder for this weight?
        adjustedVertex = adjustedVertex + bindPoseVertex * skinning_transforms[joint_indices.a] * joint_weights.a;
        adjustedNormal = adjustedNormal + bindPoseNormal * skinning_transforms[joint_indices.a] * joint_weights.a;

        gl_Position = u_model_view_proj * adjustedVertex;
        v_normal = normalize(u_model_view * adjustedNormal).xyz;
    }
";

static SKINNED_FRAGMENT_SHADER: &'static [u8] = b"
    #version 150

    uniform sampler2D u_texture;

    in vec3 v_normal;
    out vec4 out_color;

    in vec2 v_TexCoord;

    void main() {
        vec4 texColor = texture(u_texture, v_TexCoord);

        // unidirectional light in direction as camera
        vec3 light = vec3(0.0, 0.0, 1.0);
        light = normalize(light);
        float intensity = max(dot(v_normal, light), 0.0);

        out_color = vec4(intensity, intensity, intensity, 1.0) * texColor;
    }
";

fn vtn_to_vertex(a: collada::VTNIndex, obj: &collada::Object) -> SkinnedVertex
{
    let mut vertex: SkinnedVertex = Default::default();
    let position = obj.vertices[a.0];

    vertex.pos = [position.x as f32, position.y as f32, position.z as f32];

    if obj.joint_weights.len() == obj.vertices.len() {
        let weights = obj.joint_weights[a.0];
        vertex.joint_weights = weights.weights;
        vertex.joint_indices = [
            weights.joints[0] as i32,
            weights.joints[1] as i32,
            weights.joints[2] as i32,
            weights.joints[3] as i32,
        ];
    }

    if let Some(uv) = a.1 {
        let uv = obj.tex_vertices[uv];
        vertex.uv = [uv.x as f32, uv.y as f32];
    }

    if let Some(normal) = a.2 {
        let normal = obj.normals[normal];
        vertex.normal = [normal.x as f32, normal.y as f32, normal.z as f32];
    }

    vertex
}

fn get_vertex_index_data(obj: &collada::Object, vertex_data: &mut Vec<SkinnedVertex>, index_data: &mut Vec<u32>) {
    for geom in obj.geometry.iter() {
        let start = index_data.len();
        let mut i = vertex_data.len() as u32;
        let mut uvs: u32 = 0;
        let mut normals: u32 = 0;
        {
            let mut add = |a: collada::VTNIndex| {
                if let Some(_) = a.1 { uvs += 1; }
                if let Some(_) = a.2 { normals += 1; }
                vertex_data.push(vtn_to_vertex(a, obj));
                index_data.push(i);
                i += 1;
            };
            for shape in geom.shapes.iter() {
                match shape {
                    &collada::Shape::Triangle(a, b, c) => {
                        add(a);
                        add(b);
                        add(c);
                    }
                    _ => {}
                }
            }
        }
    }
}
<commit_msg>SkinnedRenderer using gfx::render::target::Output<commit_after>use std::default::Default;
use std::path::Path;

use collada;
use gfx;
use gfx::traits::*;
use gfx_texture;

use math::*;
use skeleton::Skeleton;

const MAX_JOINTS: usize = 64;

pub struct SkinnedRenderBatch<R: gfx::Resources> {
    skinning_transforms_buffer: gfx::BufferHandle<R, [[f32; 4]; 4]>,
    batch: gfx::batch::RefBatch<SkinnedShaderParams<R>>,
}

pub struct SkinnedRenderer<R: gfx::Resources> {
    skeleton: Skeleton, // TODO Should this be a ref? Should this just be the joints?
    render_batches: Vec<SkinnedRenderBatch<R>>,
}

impl<R: gfx::Resources> SkinnedRenderer<R> {

    pub fn from_collada<
        C: gfx::CommandBuffer<R>,
        F: gfx::Factory<R>,
        D: Device<Resources = R, CommandBuffer = C>,
    > (
        graphics: &mut gfx::Graphics<D, F>,
        collada_document: collada::document::ColladaDocument,
        texture_paths: Vec<&str>, // TODO - read from the COLLADA document (if available)
    ) -> Result<SkinnedRenderer<R>, gfx::ProgramError> {

        let program = match graphics.factory.link_program(SKINNED_VERTEX_SHADER.clone(), SKINNED_FRAGMENT_SHADER.clone()) {
            Ok(program_handle) => program_handle,
            Err(e) => return Err(e),
        };

        let obj_set = collada_document.get_obj_set().unwrap();

        let mut skeleton_set = collada_document.get_skeletons().unwrap();
        let mut animations = collada_document.get_animations();
        let skeleton = Skeleton::from_collada(&skeleton_set[0]);

        let mut render_batches = Vec::new();

        for (i, object) in obj_set.objects.iter().enumerate().take(6) {

            let mut vertex_data: Vec<SkinnedVertex> = Vec::new();
            let mut index_data: Vec<u32> = Vec::new();

            get_vertex_index_data(&object, &mut vertex_data, &mut index_data);

            let mesh = graphics.factory.create_mesh(vertex_data.as_slice());

            let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

            let slice = graphics.factory
                .create_buffer_index::<u32>(index_data.as_slice())
                .to_slice(gfx::PrimitiveType::TriangleList);

            let skinning_transforms_buffer = graphics.factory.create_buffer::<[[f32; 4]; 4]>(MAX_JOINTS, gfx::BufferUsage::Dynamic);

            let texture = gfx_texture::Texture::from_path(
                &mut graphics.factory,
                &Path::new(&texture_paths[i]),
                &gfx_texture::Settings::new()
            ).unwrap();

            let sampler = graphics.factory.create_sampler(
                gfx::tex::SamplerInfo::new(
                    gfx::tex::FilterMethod::Trilinear,
                    gfx::tex::WrapMode::Clamp
                    )
                );

            let shader_params = SkinnedShaderParams {
                u_model_view_proj: mat4_id(),
                u_model_view: mat4_id(),
                u_skinning_transforms: skinning_transforms_buffer.raw().clone(),
                u_texture: (texture.handle, Some(sampler)),
            };

            let batch: gfx::batch::RefBatch<SkinnedShaderParams<R>> = graphics.make_batch(&program, shader_params, &mesh, slice, &state).unwrap();

            render_batches.push(SkinnedRenderBatch {
                batch: batch,
                skinning_transforms_buffer: skinning_transforms_buffer,
            });
        }

        Ok(SkinnedRenderer {
            render_batches: render_batches,
            skeleton: skeleton.clone(),
        })
    }

    pub fn render<
        C: gfx::CommandBuffer<R>,
        F: gfx::Factory<R>,
        D: Device<Resources = R, CommandBuffer = C>,
        O: gfx::render::target::Output<R>,
    >(
        &mut self,
        graphics: &mut gfx::Graphics<D, F>,
        output: &O,
        view: [[f32; 4]; 4],
        projection: [[f32; 4]; 4],
        joint_poses: &[Matrix4<f32>]
    ) {

        let skinning_transforms = self.calculate_skinning_transforms(&joint_poses);

        for material in self.render_batches.iter_mut() {
            material.batch.params.u_model_view = view;
            material.batch.params.u_model_view_proj = projection;

            // FIXME -- should all be able to share the same buffer
            graphics.factory.update_buffer(&material.skinning_transforms_buffer, &skinning_transforms[..], 0);

            graphics.draw(&material.batch, output).unwrap();
        }
    }

    ///
    /// TODO - don't allocate a new vector
    ///
    pub fn calculate_skinning_transforms(&self, global_poses: &[Matrix4<f32>]) -> Vec<Matrix4<f32>> {

        use std::f32::consts::PI;
        use std::num::{Float};

        self.skeleton.joints.iter().enumerate().map(|(i, joint)| {
            row_mat4_mul(global_poses[i], joint.inverse_bind_pose)
        }).collect()
    }
}

#[shader_param]
struct SkinnedShaderParams<R: gfx::Resources> {
    u_model_view_proj: [[f32; 4]; 4],
    u_model_view: [[f32; 4]; 4],
    u_skinning_transforms: gfx::RawBufferHandle<R>,
    u_texture: gfx::shade::TextureParam<R>,
}

#[vertex_format]
#[derive(Copy)]
#[derive(Clone)]
#[derive(Debug)]
struct SkinnedVertex {
    pos: [f32; 3],
    normal: [f32; 3],
    uv: [f32; 2],
    joint_indices: [i32; 4],
    joint_weights: [f32; 4], // TODO last weight is redundant
}

impl Default for SkinnedVertex {
    fn default() -> SkinnedVertex {
        SkinnedVertex {
            pos: [0.0; 3],
            normal: [0.0; 3],
            uv: [0.0; 2],
            joint_indices: [0; 4],
            joint_weights: [0.0; 4],
        }
    }
}

static SKINNED_VERTEX_SHADER: &'static [u8] = b"
    #version 150 core

    uniform mat4 u_model_view_proj;
    uniform mat4 u_model_view;

    const int MAX_JOINTS = 64;

    uniform u_skinning_transforms {
        mat4 skinning_transforms[MAX_JOINTS];
    };

    in vec3 pos, normal;
    in vec2 uv;

    in ivec4 joint_indices;
    in vec4 joint_weights;

    out vec3 v_normal;
    out vec2 v_TexCoord;

    void main() {
        v_TexCoord = vec2(uv.x, 1 - uv.y); // this feels like a bug with gfx?

        vec4 adjustedVertex;
        vec4 adjustedNormal;

        vec4 bindPoseVertex = vec4(pos, 1.0);
        vec4 bindPoseNormal = vec4(normal, 0.0);

        adjustedVertex = bindPoseVertex * skinning_transforms[joint_indices.x] * joint_weights.x;
        adjustedNormal = bindPoseNormal * skinning_transforms[joint_indices.x] * joint_weights.x;

        adjustedVertex = adjustedVertex + bindPoseVertex * skinning_transforms[joint_indices.y] * joint_weights.y;
        adjustedNormal = adjustedNormal + bindPoseNormal * skinning_transforms[joint_indices.y] * joint_weights.y;

        adjustedVertex = adjustedVertex + bindPoseVertex * skinning_transforms[joint_indices.z] * joint_weights.z;
        adjustedNormal = adjustedNormal + bindPoseNormal * skinning_transforms[joint_indices.z] * joint_weights.z;

        // TODO just use remainder for this weight?
        adjustedVertex = adjustedVertex + bindPoseVertex * skinning_transforms[joint_indices.a] * joint_weights.a;
        adjustedNormal = adjustedNormal + bindPoseNormal * skinning_transforms[joint_indices.a] * joint_weights.a;

        gl_Position = u_model_view_proj * adjustedVertex;
        v_normal = normalize(u_model_view * adjustedNormal).xyz;
    }
";

static SKINNED_FRAGMENT_SHADER: &'static [u8] = b"
    #version 150

    uniform sampler2D u_texture;

    in vec3 v_normal;
    out vec4 out_color;

    in vec2 v_TexCoord;

    void main() {
        vec4 texColor = texture(u_texture, v_TexCoord);

        // unidirectional light in direction as camera
        vec3 light = vec3(0.0, 0.0, 1.0);
        light = normalize(light);
        float intensity = max(dot(v_normal, light), 0.0);

        out_color = vec4(intensity, intensity, intensity, 1.0) * texColor;
    }
";

fn vtn_to_vertex(a: collada::VTNIndex, obj: &collada::Object) -> SkinnedVertex
{
    let mut vertex: SkinnedVertex = Default::default();
    let position = obj.vertices[a.0];

    vertex.pos = [position.x as f32, position.y as f32, position.z as f32];

    if obj.joint_weights.len() == obj.vertices.len() {
        let weights = obj.joint_weights[a.0];
        vertex.joint_weights = weights.weights;
        vertex.joint_indices = [
            weights.joints[0] as i32,
            weights.joints[1] as i32,
            weights.joints[2] as i32,
            weights.joints[3] as i32,
        ];
    }

    if let Some(uv) = a.1 {
        let uv = obj.tex_vertices[uv];
        vertex.uv = [uv.x as f32, uv.y as f32];
    }

    if let Some(normal) = a.2 {
        let normal = obj.normals[normal];
        vertex.normal = [normal.x as f32, normal.y as f32, normal.z as f32];
    }

    vertex
}

fn get_vertex_index_data(obj: &collada::Object, vertex_data: &mut Vec<SkinnedVertex>, index_data: &mut Vec<u32>) {
    for geom in obj.geometry.iter() {
        let start = index_data.len();
        let mut i = vertex_data.len() as u32;
        let mut uvs: u32 = 0;
        let mut normals: u32 = 0;
        {
            let mut add = |a: collada::VTNIndex| {
                if let Some(_) = a.1 { uvs += 1; }
                if let Some(_) = a.2 { normals += 1; }
                vertex_data.push(vtn_to_vertex(a, obj));
                index_data.push(i);
                i += 1;
            };
            for shape in geom.shapes.iter() {
                match shape {
                    &collada::Shape::Triangle(a, b, c) => {
                        add(a);
                        add(b);
                        add(c);
                    }
                    _ => {}
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>mod completion_config;
mod completion_item;
mod completion_context;
mod presentation;

mod complete_attribute;
mod complete_dot;
mod complete_record;
mod complete_pattern;
mod complete_fn_param;
mod complete_keyword;
mod complete_snippet;
mod complete_qualified_path;
mod complete_unqualified_path;
mod complete_postfix;
mod complete_macro_in_item_position;
mod complete_trait_impl;
mod patterns;
#[cfg(test)]
mod test_utils;

use ra_ide_db::RootDatabase;

use crate::{
    completion::{
        completion_context::CompletionContext,
        completion_item::{CompletionKind, Completions},
    },
    FilePosition,
};

pub use crate::completion::{
    completion_config::CompletionConfig,
    completion_item::{CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat},
};

//FIXME: split the following feature into fine-grained features.

// Feature: Magic Completions
//
// In addition to usual reference completion, rust-analyzer provides some ✨magic✨
// completions as well:
//
// Keywords like `if`, `else` `while`, `loop` are completed with braces, and cursor
// is placed at the appropriate position. Even though `if` is easy to type, you
// still want to complete it, to get ` { }` for free! `return` is inserted with a
// space or `;` depending on the return type of the function.
//
// When completing a function call, `()` are automatically inserted. If a function
// takes arguments, the cursor is positioned inside the parenthesis.
//
// There are postfix completions, which can be triggered by typing something like
// `foo().if`. The word after `.` determines postfix completion. Possible variants are:
//
// - `expr.if` -> `if expr {}` or `if let ... {}` for `Option` or `Result`
// - `expr.match` -> `match expr {}`
// - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result`
// - `expr.ref` -> `&expr`
// - `expr.refm` -> `&mut expr`
// - `expr.not` -> `!expr`
// - `expr.dbg` -> `dbg!(expr)`
//
// There also snippet completions:
//
// .Expressions
// - `pd` -> `println!("{:?}")`
// - `ppd` -> `println!("{:#?}")`
//
// .Items
// - `tfn` -> `#[test] fn f(){}`
// - `tmod` ->
// ```rust
// #[cfg(test)]
// mod tests {
//     use super::*;
//
//     #[test]
//     fn test_fn() {}
// }
// ```

/// Main entry point for completion. We run completion as a two-phase process.
///
/// First, we look at the position and collect a so-called `CompletionContext.
/// This is a somewhat messy process, because, during completion, syntax tree is
/// incomplete and can look really weird.
///
/// Once the context is collected, we run a series of completion routines which
/// look at the context and produce completion items. One subtlety about this
/// phase is that completion engine should not filter by the substring which is
/// already present, it should give all possible variants for the identifier at
/// the caret. In other words, for
///
/// ```no-run
/// fn f() {
///     let foo = 92;
///     let _ = bar<|>
/// }
/// ```
///
/// `foo` *should* be present among the completion variants. Filtering by
/// identifier prefix/fuzzy match should be done higher in the stack, together
/// with ordering of completions (currently this is done by the client).
pub(crate) fn completions(
    db: &RootDatabase,
    config: &CompletionConfig,
    position: FilePosition,
) -> Option<Completions> {
    let ctx = CompletionContext::new(db, position, config)?;

    let mut acc = Completions::default();
    complete_attribute::complete_attribute(&mut acc, &ctx);
    complete_fn_param::complete_fn_param(&mut acc, &ctx);
    complete_keyword::complete_expr_keyword(&mut acc, &ctx);
    complete_keyword::complete_use_tree_keyword(&mut acc, &ctx);
    complete_snippet::complete_expr_snippet(&mut acc, &ctx);
    complete_snippet::complete_item_snippet(&mut acc, &ctx);
    complete_qualified_path::complete_qualified_path(&mut acc, &ctx);
    complete_unqualified_path::complete_unqualified_path(&mut acc, &ctx);
    complete_dot::complete_dot(&mut acc, &ctx);
    complete_record::complete_record(&mut acc, &ctx);
    complete_pattern::complete_pattern(&mut acc, &ctx);
    complete_postfix::complete_postfix(&mut acc, &ctx);
    complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx);
    complete_trait_impl::complete_trait_impl(&mut acc, &ctx);

    Some(acc)
}

#[cfg(test)]
mod tests {
    use crate::completion::completion_config::CompletionConfig;
    use crate::mock_analysis::analysis_and_position;

    struct DetailAndDocumentation<'a> {
        detail: &'a str,
        documentation: &'a str,
    }

    fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) {
        let (analysis, position) = analysis_and_position(ra_fixture);
        let config = CompletionConfig::default();
        let completions = analysis.completions(&config, position).unwrap().unwrap();
        for item in completions {
            if item.detail() == Some(expected.detail) {
                let opt = item.documentation();
                let doc = opt.as_ref().map(|it| it.as_str());
                assert_eq!(doc, Some(expected.documentation));
                return;
            }
        }
        panic!("completion detail not found: {}", expected.detail)
    }

    #[test]
    fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() {
        check_detail_and_documentation(
            r#"
            //- /lib.rs
            macro_rules! bar {
                () => {
                    struct Bar;
                    impl Bar {
                        #[doc = "Do the foo"]
                        fn foo(&self) {}
                    }
                }
            }

            bar!();

            fn foo() {
                let bar = Bar;
                bar.fo<|>;
            }
            "#,
            DetailAndDocumentation { detail: "fn foo(&self)", documentation: "Do the foo" },
        );
    }

    #[test]
    fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() {
        check_detail_and_documentation(
            r#"
            //- /lib.rs
            macro_rules! bar {
                () => {
                    struct Bar;
                    impl Bar {
                        /// Do the foo
                        fn foo(&self) {}
                    }
                }
            }

            bar!();

            fn foo() {
                let bar = Bar;
                bar.fo<|>;
            }
            "#,
            DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" },
        );
    }
}
<commit_msg>fix: correct pd/ppd/tfn/tmod completion doc<commit_after>mod completion_config;
mod completion_item;
mod completion_context;
mod presentation;

mod complete_attribute;
mod complete_dot;
mod complete_record;
mod complete_pattern;
mod complete_fn_param;
mod complete_keyword;
mod complete_snippet;
mod complete_qualified_path;
mod complete_unqualified_path;
mod complete_postfix;
mod complete_macro_in_item_position;
mod complete_trait_impl;
mod patterns;
#[cfg(test)]
mod test_utils;

use ra_ide_db::RootDatabase;

use crate::{
    completion::{
        completion_context::CompletionContext,
        completion_item::{CompletionKind, Completions},
    },
    FilePosition,
};

pub use crate::completion::{
    completion_config::CompletionConfig,
    completion_item::{CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat},
};

//FIXME: split the following feature into fine-grained features.

// Feature: Magic Completions
//
// In addition to usual reference completion, rust-analyzer provides some ✨magic✨
// completions as well:
//
// Keywords like `if`, `else` `while`, `loop` are completed with braces, and cursor
// is placed at the appropriate position. Even though `if` is easy to type, you
// still want to complete it, to get ` { }` for free! `return` is inserted with a
// space or `;` depending on the return type of the function.
//
// When completing a function call, `()` are automatically inserted. If a function
// takes arguments, the cursor is positioned inside the parenthesis.
//
// There are postfix completions, which can be triggered by typing something like
// `foo().if`. The word after `.` determines postfix completion. Possible variants are:
//
// - `expr.if` -> `if expr {}` or `if let ... {}` for `Option` or `Result`
// - `expr.match` -> `match expr {}`
// - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result`
// - `expr.ref` -> `&expr`
// - `expr.refm` -> `&mut expr`
// - `expr.not` -> `!expr`
// - `expr.dbg` -> `dbg!(expr)`
//
// There also snippet completions:
//
// .Expressions
// - `pd` -> `eprintln!(" = {:?}", );")`
// - `ppd` -> `eprintln!(" = {:#?}", );`
//
// .Items
// - `tfn` -> `#[test] fn feature(){}`
// - `tmod` ->
// ```rust
// #[cfg(test)]
// mod tests {
//     use super::*;
//
//     #[test]
//     fn test_name() {}
// }
// ```

/// Main entry point for completion. We run completion as a two-phase process.
///
/// First, we look at the position and collect a so-called `CompletionContext.
/// This is a somewhat messy process, because, during completion, syntax tree is
/// incomplete and can look really weird.
///
/// Once the context is collected, we run a series of completion routines which
/// look at the context and produce completion items. One subtlety about this
/// phase is that completion engine should not filter by the substring which is
/// already present, it should give all possible variants for the identifier at
/// the caret. In other words, for
///
/// ```no-run
/// fn f() {
///     let foo = 92;
///     let _ = bar<|>
/// }
/// ```
///
/// `foo` *should* be present among the completion variants. Filtering by
/// identifier prefix/fuzzy match should be done higher in the stack, together
/// with ordering of completions (currently this is done by the client).
pub(crate) fn completions(
    db: &RootDatabase,
    config: &CompletionConfig,
    position: FilePosition,
) -> Option<Completions> {
    let ctx = CompletionContext::new(db, position, config)?;

    let mut acc = Completions::default();
    complete_attribute::complete_attribute(&mut acc, &ctx);
    complete_fn_param::complete_fn_param(&mut acc, &ctx);
    complete_keyword::complete_expr_keyword(&mut acc, &ctx);
    complete_keyword::complete_use_tree_keyword(&mut acc, &ctx);
    complete_snippet::complete_expr_snippet(&mut acc, &ctx);
    complete_snippet::complete_item_snippet(&mut acc, &ctx);
    complete_qualified_path::complete_qualified_path(&mut acc, &ctx);
    complete_unqualified_path::complete_unqualified_path(&mut acc, &ctx);
    complete_dot::complete_dot(&mut acc, &ctx);
    complete_record::complete_record(&mut acc, &ctx);
    complete_pattern::complete_pattern(&mut acc, &ctx);
    complete_postfix::complete_postfix(&mut acc, &ctx);
    complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx);
    complete_trait_impl::complete_trait_impl(&mut acc, &ctx);

    Some(acc)
}

#[cfg(test)]
mod tests {
    use crate::completion::completion_config::CompletionConfig;
    use crate::mock_analysis::analysis_and_position;

    struct DetailAndDocumentation<'a> {
        detail: &'a str,
        documentation: &'a str,
    }

    fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) {
        let (analysis, position) = analysis_and_position(ra_fixture);
        let config = CompletionConfig::default();
        let completions = analysis.completions(&config, position).unwrap().unwrap();
        for item in completions {
            if item.detail() == Some(expected.detail) {
                let opt = item.documentation();
                let doc = opt.as_ref().map(|it| it.as_str());
                assert_eq!(doc, Some(expected.documentation));
                return;
            }
        }
        panic!("completion detail not found: {}", expected.detail)
    }

    #[test]
    fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() {
        check_detail_and_documentation(
            r#"
            //- /lib.rs
            macro_rules! bar {
                () => {
                    struct Bar;
                    impl Bar {
                        #[doc = "Do the foo"]
                        fn foo(&self) {}
                    }
                }
            }

            bar!();

            fn foo() {
                let bar = Bar;
                bar.fo<|>;
            }
            "#,
            DetailAndDocumentation { detail: "fn foo(&self)", documentation: "Do the foo" },
        );
    }

    #[test]
    fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() {
        check_detail_and_documentation(
            r#"
            //- /lib.rs
            macro_rules! bar {
                () => {
                    struct Bar;
                    impl Bar {
                        /// Do the foo
                        fn foo(&self) {}
                    }
                }
            }

            bar!();

            fn foo() {
                let bar = Bar;
                bar.fo<|>;
            }
            "#,
            DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" },
        );
    }
}
<|endoftext|>


<commit_before>use std::ops::Add;
use typenum::uint::Unsigned;
use typenum::consts::U1;

/// This enum serves to represent the type of a tensor. A tensor can have any number of indices, and each one can be either
/// covariant (a lower index), or contravariant (an upper index). For example, a vector is a tensor with only one contravariant index.
#[derive(Clone, Copy)]
pub enum IndexType {
    Covariant,
    Contravariant,
}

pub trait TensorIndex {
    fn index_type() -> IndexType;
}

pub struct ContravariantIndex;
impl TensorIndex for ContravariantIndex {
    fn index_type() -> IndexType {
        IndexType::Contravariant
    }
}

pub struct CovariantIndex;
impl TensorIndex for CovariantIndex {
    fn index_type() -> IndexType {
        IndexType::Covariant
    }
}

pub trait Variance {
    type Rank: Unsigned + Add<U1>;
    fn rank() -> usize {
        Self::Rank::to_usize()
    }
    fn variance() -> Vec<IndexType>;
}

impl Variance for ContravariantIndex {
    type Rank = U1;
    fn variance() -> Vec<IndexType> {
        vec![IndexType::Contravariant]
    }
}

impl Variance for CovariantIndex {
    type Rank = U1;
    fn variance() -> Vec<IndexType> {
        vec![IndexType::Covariant]
    }
}

impl<T, U> Variance for (T, U)
    where T: Variance,
          <T::Rank as Add<U1>>::Output: Unsigned + Add<U1>,
          U: TensorIndex
{
    type Rank = <T::Rank as Add<U1>>::Output;

    fn variance() -> Vec<IndexType> {
        let mut result = T::variance();
        result.push(U::index_type());
        result
    }
}<commit_msg>Added Concat trait for Variance<commit_after>use std::ops::Add;
use typenum::uint::Unsigned;
use typenum::consts::U1;

/// This enum serves to represent the type of a tensor. A tensor can have any number of indices, and each one can be either
/// covariant (a lower index), or contravariant (an upper index). For example, a vector is a tensor with only one contravariant index.
#[derive(Clone, Copy)]
pub enum IndexType {
    Covariant,
    Contravariant,
}

pub trait TensorIndex {
    fn index_type() -> IndexType;
}

pub struct ContravariantIndex;
impl TensorIndex for ContravariantIndex {
    fn index_type() -> IndexType {
        IndexType::Contravariant
    }
}

pub struct CovariantIndex;
impl TensorIndex for CovariantIndex {
    fn index_type() -> IndexType {
        IndexType::Covariant
    }
}

pub trait Variance {
    type Rank: Unsigned + Add<U1>;
    fn rank() -> usize {
        Self::Rank::to_usize()
    }
    fn variance() -> Vec<IndexType>;
}

impl Variance for ContravariantIndex {
    type Rank = U1;
    fn variance() -> Vec<IndexType> {
        vec![IndexType::Contravariant]
    }
}

impl Variance for CovariantIndex {
    type Rank = U1;
    fn variance() -> Vec<IndexType> {
        vec![IndexType::Covariant]
    }
}

impl<T, U> Variance for (T, U)
    where T: Variance,
          <T::Rank as Add<U1>>::Output: Unsigned + Add<U1>,
          U: TensorIndex
{
    type Rank = <T::Rank as Add<U1>>::Output;

    fn variance() -> Vec<IndexType> {
        let mut result = T::variance();
        result.push(U::index_type());
        result
    }
}

pub trait Concat<T> {
    type Output;
}

impl<T, U> Concat<U> for T
    where T: TensorIndex,
          U: TensorIndex
{
    type Output = (T, U);
}

impl<T, U, V> Concat<V> for (T, U)
    where T: Variance,
          U: TensorIndex,
          V: TensorIndex
{
    type Output = ((T, U), V);
}

impl<T, U, V> Concat<(U, V)> for T
    where T: TensorIndex + Concat<U>,
          U: Variance,
          V: TensorIndex,
          <T as Concat<U>>::Output: Concat<V>
{
    type Output = <<T as Concat<U>>::Output as Concat<V>>::Output;
}

impl<T, U, V, W> Concat<(V, W)> for (T, U)
    where T: Variance,
          U: TensorIndex,
          (T, U): Concat<V>,
          V: Variance,
          W: TensorIndex
{
    type Output = (<(T, U) as Concat<V>>::Output, W);
}<|endoftext|>


<commit_before>// Copyright 2019 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 super::*;
use std::fmt::Write;
use std::ops::Deref;

/// Sized, heap-allocated string type guaranteed to contain a well-formed [IETF-RFC3986] URI
/// or [network path](enum.UriType.html#variant.NetworkPath).
///
/// The unsized counterpart is [`Uri`](crate::Uri).
///
/// This type implements [`std::ops::Deref<Uri>`], so you can also use all of the
/// methods from [`Uri`] on this type.
///
/// [IETF-RFC3986]: https://tools.ietf.org/html/rfc3986
#[derive(Clone, Eq, Hash)]
pub struct UriBuf(pub(super) UriRefBuf);

impl_uri_buf_traits!(UriBuf, Uri);

impl Deref for UriBuf {
    type Target = Uri;

    fn deref(&self) -> &Self::Target {
        self.as_uri()
    }
}

impl AsRef<Uri> for UriBuf {
    fn as_ref(&self) -> &Uri {
        self.as_uri()
    }
}

impl From<&Uri> for UriBuf {
    fn from(x: &Uri) -> Self {
        x.to_uri_buf()
    }
}

impl std::fmt::Display for UriBuf {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
        self.write_to(f)
    }
}

/// # Unsafe Methods
///
/// `UriBuf` needs some unsafe methods in order to function properly. This section is where
/// they are all located.
impl UriBuf {
    /// Unchecked version of [`UriBuf::from_string`].
    ///
    /// # Safety
    ///
    /// This method is marked as unsafe because it allows you to construct a `UriBuf` with
    /// a value that is not a well-formed URI reference.
    #[inline(always)]
    pub unsafe fn from_string_unchecked(s: String) -> UriBuf {
        UriBuf(UriRefBuf::from_string_unchecked(s))
    }
}

impl UriBuf {
    /// Creates a new `UriBuf` from *unescaped* component values.
    pub fn new<Sch, Hos, Pat, Que, Frg>(
        scheme: Sch,
        host: Hos,
        port: Option<u16>,
        path: Pat,
        query: Option<Que>,
        fragment: Option<Frg>,
    ) -> UriBuf
    where
        Sch: Into<String>,
        Hos: AsRef<str>,
        Pat: AsRef<str>,
        Que: AsRef<str>,
        Frg: AsRef<str>,
    {
        let mut ret: String = Self::from_scheme_host_port(scheme, host, port).into();

        let mut path = path.as_ref();

        if path.starts_with('/') {
            path = &path[1..];
        }

        let path_segment_iter =
            path.split('/')
                .filter_map(|seg| if seg == "." { None } else { Some(seg) });

        for seg in path_segment_iter {
            ret.push('/');
            ret.extend(seg.escape_uri());
        }

        if let Some(query) = query {
            let mut first = true;
            ret.push('?');
            for seg in query.as_ref().split(|c| c == '&' || c == ';') {
                if first {
                    first = false;
                } else {
                    ret.push('&');
                }
                ret.extend(seg.escape_uri().for_query());
            }
        }

        if let Some(fragment) = fragment {
            ret.push('#');
            ret.extend(fragment.as_ref().escape_uri().for_fragment());
        }

        unsafe { Self::from_string_unchecked(ret) }
    }

    /// Constructs a `UriBuf` from a scheme and authority.
    ///
    /// The authority should not be percent encoded. If the given scheme contains invalid
    /// characters, this method will panic.
    ///
    /// # Example
    ///
    /// ```
    /// use async_coap_uri::prelude::*;
    /// let authority = "user@[2001:0db8:85a3::1%en2]:8080";
    ///
    /// let uri_buf = UriBuf::from_scheme_authority("http", authority);
    ///
    /// assert_eq!(uri_buf, uri!("http://user@[2001:0db8:85a3::1%25en2]:8080"));
    ///
    /// ```
    pub fn from_scheme_authority<Sch, Aut>(scheme: Sch, authority: Aut) -> UriBuf
    where
        Sch: Into<String>,
        Aut: AsRef<str>,
    {
        let mut ret = scheme.into();

        // Make sure that the scheme is proper. This is likely a string constant,
        // so we go ahead and panic if we detect that it is busted.
        assert_eq!(
            ret.find(|c: char| !(c.is_ascii_alphanumeric() || c == '+' || c == '-' || c == '.')),
            None,
            "Scheme contains invalid characters: {:?}",
            ret
        );

        ret.push_str("://");

        ret.extend(authority.as_ref().escape_uri().for_authority());

        unsafe { Self::from_string_unchecked(ret) }
    }

    /// Constructs a network path from a host and a relative reference.
    ///
    /// # Example
    ///
    /// ```
    /// use async_coap_uri::prelude::*;
    /// let host = "example.com";
    /// let rel_ref = rel_ref!("./foobar?q");
    ///
    /// let uri_buf = UriBuf::from_host_rel_ref(host, rel_ref);
    ///
    /// assert_eq!(uri_buf, uri!("//example.com/foobar?q"));
    ///
    /// ```
    pub fn from_host_rel_ref<Hos, RR>(host: Hos, rel_ref: RR) -> UriBuf
    where
        Hos: AsRef<str>,
        RR: AsRef<RelRef>,
    {
        let host = host.as_ref();
        let rel_ref = rel_ref
            .as_ref()
            .trim_leading_dot_slashes()
            .trim_leading_slashes();

        // UNWRAP-SAFETY: This is safe because we are fully
        // escaping the host and we already know rel_ref to
        // be well-formed.
        uri_format!("//{}/{}", host.escape_uri().full(), rel_ref).unwrap()
    }

    /// Constructs a `UriBuf` from a scheme, host and an optional port number.
    ///
    /// The host should not be percent encoded. If the given scheme contains invalid
    /// characters, this method will panic.
    pub fn from_scheme_host_port<Sch, Hos>(scheme: Sch, host: Hos, port: Option<u16>) -> UriBuf
    where
        Sch: Into<String>,
        Hos: AsRef<str>,
    {
        let mut ret = scheme.into();

        // Make sure that the scheme is proper. This is likely a string constant,
        // so we go ahead and panic if we detect that it is busted.
        assert_eq!(
            ret.find(|c: char| !(c.is_ascii_alphanumeric() || c == '+' || c == '-' || c == '.')),
            None,
            "Scheme contains invalid characters: {:?}",
            ret
        );

        ret.push_str("://");

        let mut host = host.as_ref();

        // Trim enclosing brackets.
        if host.starts_with('[') && host.ends_with(']') {
            host = &host[1..host.len()];
        }

        if host.find(':').is_some() {
            ret.push('[');
            ret.extend(host.escape_uri());
            ret.push(']');
        }

        if let Some(port) = port {
            write!(ret, ":{}", port).unwrap();
        }

        unsafe { Self::from_string_unchecked(ret) }
    }

    /// Attempts to create a new [`UriBuf`] from a string slice.
    pub fn from_str<S: AsRef<str>>(s: S) -> Result<UriBuf, ParseError> {
        let s = s.as_ref();
        let components = UriRawComponents::from_str(s)?;

        if components.uri_type().can_borrow_as_uri() {
            Ok(unsafe { Self::from_string_unchecked(s.to_string()) })
        } else {
            Err(ParseError::new("Missing scheme or authority", None))
        }
    }

    /// Attempts to create a new [`UriBuf`] from a [`String`].
    pub fn from_string(s: String) -> Result<UriBuf, ParseError> {
        let components = UriRawComponents::from_str(s.as_str())?;

        if components.uri_type().can_borrow_as_uri() {
            Ok(unsafe { Self::from_string_unchecked(s) })
        } else {
            Err(ParseError::new("Missing scheme or authority", None))
        }
    }

    /// Attempts to create a new [`UriBuf`] from a `UriRef` slice.
    pub fn from_uri<S: AsRef<UriRef>>(s: S) -> Option<UriBuf> {
        if s.as_ref().uri_type().can_borrow_as_uri() {
            Some(UriBuf(s.as_ref().to_uri_ref_buf()))
        } else {
            None
        }
    }
}

impl UriBuf {
    /// Borrows a [`Uri`] slice containing this URI.
    #[inline(always)]
    pub fn as_uri(&self) -> &Uri {
        unsafe { Uri::from_str_unchecked(self.as_str()) }
    }
}

/// # Manipulation
impl UriBuf {
    /// Using this URI as the base, performs "relative resolution" to the given instance
    /// implementing [`AnyUriRef`], updating the content of this `UriBuf` with the result.
    pub fn resolve<T: AnyUriRef + ?Sized>(&mut self, dest: &T) -> Result<(), ResolveError> {
        self.0.resolve(dest)
    }

    /// Replaces the path, query, and fragment with that from `rel`.
    pub fn replace_path(&mut self, rel: &RelRef) {
        self.0.replace_path(rel)
    }
}

inherits_uri_ref_buf!(UriBuf);
<commit_msg>async-coap-uri: impl FromStr for UriBuf<commit_after>// Copyright 2019 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 super::*;
use std::fmt::Write;
use std::ops::Deref;
use std::str::FromStr;

/// Sized, heap-allocated string type guaranteed to contain a well-formed [IETF-RFC3986] URI
/// or [network path](enum.UriType.html#variant.NetworkPath).
///
/// The unsized counterpart is [`Uri`](crate::Uri).
///
/// This type implements [`std::ops::Deref<Uri>`], so you can also use all of the
/// methods from [`Uri`] on this type.
///
/// [IETF-RFC3986]: https://tools.ietf.org/html/rfc3986
#[derive(Clone, Eq, Hash)]
pub struct UriBuf(pub(super) UriRefBuf);

impl_uri_buf_traits!(UriBuf, Uri);

impl Deref for UriBuf {
    type Target = Uri;

    fn deref(&self) -> &Self::Target {
        self.as_uri()
    }
}

impl AsRef<Uri> for UriBuf {
    fn as_ref(&self) -> &Uri {
        self.as_uri()
    }
}

impl From<&Uri> for UriBuf {
    fn from(x: &Uri) -> Self {
        x.to_uri_buf()
    }
}

impl FromStr for UriBuf {
    type Err = ParseError;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        Self::from_str(input)
    }
}
impl std::fmt::Display for UriBuf {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
        self.write_to(f)
    }
}

/// # Unsafe Methods
///
/// `UriBuf` needs some unsafe methods in order to function properly. This section is where
/// they are all located.
impl UriBuf {
    /// Unchecked version of [`UriBuf::from_string`].
    ///
    /// # Safety
    ///
    /// This method is marked as unsafe because it allows you to construct a `UriBuf` with
    /// a value that is not a well-formed URI reference.
    #[inline(always)]
    pub unsafe fn from_string_unchecked(s: String) -> UriBuf {
        UriBuf(UriRefBuf::from_string_unchecked(s))
    }
}

impl UriBuf {
    /// Creates a new `UriBuf` from *unescaped* component values.
    pub fn new<Sch, Hos, Pat, Que, Frg>(
        scheme: Sch,
        host: Hos,
        port: Option<u16>,
        path: Pat,
        query: Option<Que>,
        fragment: Option<Frg>,
    ) -> UriBuf
    where
        Sch: Into<String>,
        Hos: AsRef<str>,
        Pat: AsRef<str>,
        Que: AsRef<str>,
        Frg: AsRef<str>,
    {
        let mut ret: String = Self::from_scheme_host_port(scheme, host, port).into();

        let mut path = path.as_ref();

        if path.starts_with('/') {
            path = &path[1..];
        }

        let path_segment_iter =
            path.split('/')
                .filter_map(|seg| if seg == "." { None } else { Some(seg) });

        for seg in path_segment_iter {
            ret.push('/');
            ret.extend(seg.escape_uri());
        }

        if let Some(query) = query {
            let mut first = true;
            ret.push('?');
            for seg in query.as_ref().split(|c| c == '&' || c == ';') {
                if first {
                    first = false;
                } else {
                    ret.push('&');
                }
                ret.extend(seg.escape_uri().for_query());
            }
        }

        if let Some(fragment) = fragment {
            ret.push('#');
            ret.extend(fragment.as_ref().escape_uri().for_fragment());
        }

        unsafe { Self::from_string_unchecked(ret) }
    }

    /// Constructs a `UriBuf` from a scheme and authority.
    ///
    /// The authority should not be percent encoded. If the given scheme contains invalid
    /// characters, this method will panic.
    ///
    /// # Example
    ///
    /// ```
    /// use async_coap_uri::prelude::*;
    /// let authority = "user@[2001:0db8:85a3::1%en2]:8080";
    ///
    /// let uri_buf = UriBuf::from_scheme_authority("http", authority);
    ///
    /// assert_eq!(uri_buf, uri!("http://user@[2001:0db8:85a3::1%25en2]:8080"));
    ///
    /// ```
    pub fn from_scheme_authority<Sch, Aut>(scheme: Sch, authority: Aut) -> UriBuf
    where
        Sch: Into<String>,
        Aut: AsRef<str>,
    {
        let mut ret = scheme.into();

        // Make sure that the scheme is proper. This is likely a string constant,
        // so we go ahead and panic if we detect that it is busted.
        assert_eq!(
            ret.find(|c: char| !(c.is_ascii_alphanumeric() || c == '+' || c == '-' || c == '.')),
            None,
            "Scheme contains invalid characters: {:?}",
            ret
        );

        ret.push_str("://");

        ret.extend(authority.as_ref().escape_uri().for_authority());

        unsafe { Self::from_string_unchecked(ret) }
    }

    /// Constructs a network path from a host and a relative reference.
    ///
    /// # Example
    ///
    /// ```
    /// use async_coap_uri::prelude::*;
    /// let host = "example.com";
    /// let rel_ref = rel_ref!("./foobar?q");
    ///
    /// let uri_buf = UriBuf::from_host_rel_ref(host, rel_ref);
    ///
    /// assert_eq!(uri_buf, uri!("//example.com/foobar?q"));
    ///
    /// ```
    pub fn from_host_rel_ref<Hos, RR>(host: Hos, rel_ref: RR) -> UriBuf
    where
        Hos: AsRef<str>,
        RR: AsRef<RelRef>,
    {
        let host = host.as_ref();
        let rel_ref = rel_ref
            .as_ref()
            .trim_leading_dot_slashes()
            .trim_leading_slashes();

        // UNWRAP-SAFETY: This is safe because we are fully
        // escaping the host and we already know rel_ref to
        // be well-formed.
        uri_format!("//{}/{}", host.escape_uri().full(), rel_ref).unwrap()
    }

    /// Constructs a `UriBuf` from a scheme, host and an optional port number.
    ///
    /// The host should not be percent encoded. If the given scheme contains invalid
    /// characters, this method will panic.
    pub fn from_scheme_host_port<Sch, Hos>(scheme: Sch, host: Hos, port: Option<u16>) -> UriBuf
    where
        Sch: Into<String>,
        Hos: AsRef<str>,
    {
        let mut ret = scheme.into();

        // Make sure that the scheme is proper. This is likely a string constant,
        // so we go ahead and panic if we detect that it is busted.
        assert_eq!(
            ret.find(|c: char| !(c.is_ascii_alphanumeric() || c == '+' || c == '-' || c == '.')),
            None,
            "Scheme contains invalid characters: {:?}",
            ret
        );

        ret.push_str("://");

        let mut host = host.as_ref();

        // Trim enclosing brackets.
        if host.starts_with('[') && host.ends_with(']') {
            host = &host[1..host.len()];
        }

        if host.find(':').is_some() {
            ret.push('[');
            ret.extend(host.escape_uri());
            ret.push(']');
        }

        if let Some(port) = port {
            write!(ret, ":{}", port).unwrap();
        }

        unsafe { Self::from_string_unchecked(ret) }
    }

    /// Attempts to create a new [`UriBuf`] from a string slice.
    pub fn from_str<S: AsRef<str>>(s: S) -> Result<UriBuf, ParseError> {
        let s = s.as_ref();
        let components = UriRawComponents::from_str(s)?;

        if components.uri_type().can_borrow_as_uri() {
            Ok(unsafe { Self::from_string_unchecked(s.to_string()) })
        } else {
            Err(ParseError::new("Missing scheme or authority", None))
        }
    }

    /// Attempts to create a new [`UriBuf`] from a [`String`].
    pub fn from_string(s: String) -> Result<UriBuf, ParseError> {
        let components = UriRawComponents::from_str(s.as_str())?;

        if components.uri_type().can_borrow_as_uri() {
            Ok(unsafe { Self::from_string_unchecked(s) })
        } else {
            Err(ParseError::new("Missing scheme or authority", None))
        }
    }

    /// Attempts to create a new [`UriBuf`] from a `UriRef` slice.
    pub fn from_uri<S: AsRef<UriRef>>(s: S) -> Option<UriBuf> {
        if s.as_ref().uri_type().can_borrow_as_uri() {
            Some(UriBuf(s.as_ref().to_uri_ref_buf()))
        } else {
            None
        }
    }
}

impl UriBuf {
    /// Borrows a [`Uri`] slice containing this URI.
    #[inline(always)]
    pub fn as_uri(&self) -> &Uri {
        unsafe { Uri::from_str_unchecked(self.as_str()) }
    }
}

/// # Manipulation
impl UriBuf {
    /// Using this URI as the base, performs "relative resolution" to the given instance
    /// implementing [`AnyUriRef`], updating the content of this `UriBuf` with the result.
    pub fn resolve<T: AnyUriRef + ?Sized>(&mut self, dest: &T) -> Result<(), ResolveError> {
        self.0.resolve(dest)
    }

    /// Replaces the path, query, and fragment with that from `rel`.
    pub fn replace_path(&mut self, rel: &RelRef) {
        self.0.replace_path(rel)
    }
}

inherits_uri_ref_buf!(UriBuf);

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

    #[test]
    fn test_from_str() {
        assert_eq!(
            <UriBuf as FromStr>::from_str("https://www.google.com/"),
            UriBuf::from_str("https://www.google.com/")
        );
    }
}
<|endoftext|>