<commit_before>#![cfg(windows)]

extern crate winapi;
extern crate gleam;

use com::{ComPtr, ToResult, HResult, as_ptr};
use std::ptr;
use std::rc::Rc;
use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1;
use winapi::shared::dxgi1_2::IDXGIFactory2;
use winapi::shared::minwindef::{TRUE, FALSE};
use winapi::shared::windef::HWND;
use winapi::um::d3d11::ID3D11Device;
use winapi::um::dcomp::IDCompositionDevice;
use winapi::um::dcomp::IDCompositionTarget;
use winapi::um::dcomp::IDCompositionVisual;

pub mod com;
mod egl;

pub struct DirectComposition {
    d3d_device: ComPtr<ID3D11Device>,
    dxgi_factory: ComPtr<IDXGIFactory2>,

    egl: Rc<egl::SharedEglThings>,
    pub gleam: Rc<gleam::gl::Gl>,

    composition_device: ComPtr<IDCompositionDevice>,
    root_visual: ComPtr<IDCompositionVisual>,

    #[allow(unused)]  // Needs to be kept alive
    composition_target: ComPtr<IDCompositionTarget>,
}

impl DirectComposition {
    /// Initialize DirectComposition in the given window
    ///
    /// # Safety
    ///
    /// `hwnd` must be a valid handle to a window.
    pub unsafe fn new(hwnd: HWND) -> HResult<Self> {
        let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice(
            ptr::null_mut(),
            winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE,
            ptr::null_mut(),
            winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT |
            if cfg!(debug_assertions) {
                winapi::um::d3d11::D3D11_CREATE_DEVICE_DEBUG
            } else {
                0
            },
            ptr::null_mut(),
            0,
            winapi::um::d3d11::D3D11_SDK_VERSION,
            ptr_ptr,
            &mut 0,
            ptr::null_mut(),
        ))?;

        let egl = egl::SharedEglThings::new(d3d_device.as_raw());
        let gleam = gleam::gl::GlesFns::load_with(|name| egl.get_proc_address(name));

        let dxgi_device = d3d_device.cast::<winapi::shared::dxgi::IDXGIDevice>()?;

        // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404556(v=vs.85).aspx#code-snippet-1
        // “Because you can create a Direct3D device without creating a swap chain,
        //  you might need to retrieve the factory that is used to create the device
        //  in order to create a swap chain.”
        let adapter = ComPtr::new_with(|ptr_ptr| dxgi_device.GetAdapter(ptr_ptr))?;
        let dxgi_factory = ComPtr::<IDXGIFactory2>::new_with_uuid(|uuid, ptr_ptr| {
            adapter.GetParent(uuid, ptr_ptr)
        })?;

        // Create the DirectComposition device object.
        let composition_device = ComPtr::<IDCompositionDevice>::new_with_uuid(|uuid, ptr_ptr| {
            winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr)
        })?;

        // Create the composition target object based on the
        // specified application window.
        let composition_target = ComPtr::new_with(|ptr_ptr| {
            composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr)
        })?;

        let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr))?;
        composition_target.SetRoot(&*root_visual).to_result()?;

        Ok(DirectComposition {
            d3d_device, dxgi_factory,
            egl, gleam,
            composition_device, composition_target, root_visual,
        })
    }

    /// Execute changes to the DirectComposition scene.
    pub fn commit(&self) -> HResult<()> {
        unsafe {
            self.composition_device.Commit().to_result()
        }
    }

    pub fn create_d3d_visual(&self, width: u32, height: u32) -> HResult<D3DVisual> {
        unsafe {
            let desc = DXGI_SWAP_CHAIN_DESC1 {
                Width: width,
                Height: height,
                Format: winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM,
                Stereo: FALSE,
                SampleDesc: winapi::shared::dxgitype::DXGI_SAMPLE_DESC {
                    Count: 1,
                    Quality: 0,
                },
                BufferUsage: winapi::shared::dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT,
                BufferCount: 2,
                Scaling: winapi::shared::dxgi1_2::DXGI_SCALING_STRETCH,
                SwapEffect: winapi::shared::dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
                AlphaMode:  winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_PREMULTIPLIED,
                Flags: 0,
            };
            let swap_chain = ComPtr::<winapi::shared::dxgi1_2::IDXGISwapChain1>::new_with(|ptr_ptr| {
                self.dxgi_factory.CreateSwapChainForComposition(
                    as_ptr(&self.d3d_device),
                    &desc,
                    ptr::null_mut(),
                    ptr_ptr,
                )
            })?;
            let back_buffer = ComPtr::<winapi::um::d3d11::ID3D11Texture2D>::new_with_uuid(|uuid, ptr_ptr| {
                swap_chain.GetBuffer(0, uuid, ptr_ptr)
            })?;
            let egl = egl::PerVisualEglThings::new(self.egl.clone(), &*back_buffer, width, height);

            let visual = ComPtr::new_with(|ptr_ptr| self.composition_device.CreateVisual(ptr_ptr))?;
            visual.SetContent(&*****swap_chain).to_result()?;
            self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).to_result()?;

            Ok(D3DVisual { visual, swap_chain, back_buffer, egl })
        }
    }
}

/// A DirectComposition "visual" configured for rendering with Direct3D.
pub struct D3DVisual {
    visual: ComPtr<IDCompositionVisual>,
    swap_chain: ComPtr<winapi::shared::dxgi1_2::IDXGISwapChain1>,

    #[allow(unused)]  // FIXME: does this need to be kept alive?
    back_buffer: ComPtr<winapi::um::d3d11::ID3D11Texture2D>,

    egl: egl::PerVisualEglThings,
}

impl D3DVisual {
    pub fn set_offset_x(&self, offset_x: f32) -> HResult<()> {
        unsafe {
            self.visual.SetOffsetX_1(offset_x).to_result()
        }
    }

    pub fn set_offset_y(&self, offset_y: f32) -> HResult<()> {
        unsafe {
            self.visual.SetOffsetY_1(offset_y).to_result()
        }
    }

    pub fn make_current(&self) {
        self.egl.make_current()
    }

    pub fn present(&self) {
        unsafe {
            self.swap_chain.Present(0, 0).to_result().unwrap()
        }
    }
}
<commit_msg>Call glFinish() before IDXGISwapChain::Present<commit_after>#![cfg(windows)]

extern crate winapi;
extern crate gleam;

use com::{ComPtr, ToResult, HResult, as_ptr};
use std::ptr;
use std::rc::Rc;
use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1;
use winapi::shared::dxgi1_2::IDXGIFactory2;
use winapi::shared::minwindef::{TRUE, FALSE};
use winapi::shared::windef::HWND;
use winapi::um::d3d11::ID3D11Device;
use winapi::um::dcomp::IDCompositionDevice;
use winapi::um::dcomp::IDCompositionTarget;
use winapi::um::dcomp::IDCompositionVisual;

pub mod com;
mod egl;

pub struct DirectComposition {
    d3d_device: ComPtr<ID3D11Device>,
    dxgi_factory: ComPtr<IDXGIFactory2>,

    egl: Rc<egl::SharedEglThings>,
    pub gleam: Rc<gleam::gl::Gl>,

    composition_device: ComPtr<IDCompositionDevice>,
    root_visual: ComPtr<IDCompositionVisual>,

    #[allow(unused)]  // Needs to be kept alive
    composition_target: ComPtr<IDCompositionTarget>,
}

impl DirectComposition {
    /// Initialize DirectComposition in the given window
    ///
    /// # Safety
    ///
    /// `hwnd` must be a valid handle to a window.
    pub unsafe fn new(hwnd: HWND) -> HResult<Self> {
        let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice(
            ptr::null_mut(),
            winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE,
            ptr::null_mut(),
            winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT |
            if cfg!(debug_assertions) {
                winapi::um::d3d11::D3D11_CREATE_DEVICE_DEBUG
            } else {
                0
            },
            ptr::null_mut(),
            0,
            winapi::um::d3d11::D3D11_SDK_VERSION,
            ptr_ptr,
            &mut 0,
            ptr::null_mut(),
        ))?;

        let egl = egl::SharedEglThings::new(d3d_device.as_raw());
        let gleam = gleam::gl::GlesFns::load_with(|name| egl.get_proc_address(name));

        let dxgi_device = d3d_device.cast::<winapi::shared::dxgi::IDXGIDevice>()?;

        // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404556(v=vs.85).aspx#code-snippet-1
        // “Because you can create a Direct3D device without creating a swap chain,
        //  you might need to retrieve the factory that is used to create the device
        //  in order to create a swap chain.”
        let adapter = ComPtr::new_with(|ptr_ptr| dxgi_device.GetAdapter(ptr_ptr))?;
        let dxgi_factory = ComPtr::<IDXGIFactory2>::new_with_uuid(|uuid, ptr_ptr| {
            adapter.GetParent(uuid, ptr_ptr)
        })?;

        // Create the DirectComposition device object.
        let composition_device = ComPtr::<IDCompositionDevice>::new_with_uuid(|uuid, ptr_ptr| {
            winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr)
        })?;

        // Create the composition target object based on the
        // specified application window.
        let composition_target = ComPtr::new_with(|ptr_ptr| {
            composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr)
        })?;

        let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr))?;
        composition_target.SetRoot(&*root_visual).to_result()?;

        Ok(DirectComposition {
            d3d_device, dxgi_factory,
            egl, gleam,
            composition_device, composition_target, root_visual,
        })
    }

    /// Execute changes to the DirectComposition scene.
    pub fn commit(&self) -> HResult<()> {
        unsafe {
            self.composition_device.Commit().to_result()
        }
    }

    pub fn create_d3d_visual(&self, width: u32, height: u32) -> HResult<D3DVisual> {
        unsafe {
            let desc = DXGI_SWAP_CHAIN_DESC1 {
                Width: width,
                Height: height,
                Format: winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM,
                Stereo: FALSE,
                SampleDesc: winapi::shared::dxgitype::DXGI_SAMPLE_DESC {
                    Count: 1,
                    Quality: 0,
                },
                BufferUsage: winapi::shared::dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT,
                BufferCount: 2,
                Scaling: winapi::shared::dxgi1_2::DXGI_SCALING_STRETCH,
                SwapEffect: winapi::shared::dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
                AlphaMode:  winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_PREMULTIPLIED,
                Flags: 0,
            };
            let swap_chain = ComPtr::<winapi::shared::dxgi1_2::IDXGISwapChain1>::new_with(|ptr_ptr| {
                self.dxgi_factory.CreateSwapChainForComposition(
                    as_ptr(&self.d3d_device),
                    &desc,
                    ptr::null_mut(),
                    ptr_ptr,
                )
            })?;
            let back_buffer = ComPtr::<winapi::um::d3d11::ID3D11Texture2D>::new_with_uuid(|uuid, ptr_ptr| {
                swap_chain.GetBuffer(0, uuid, ptr_ptr)
            })?;
            let egl = egl::PerVisualEglThings::new(self.egl.clone(), &*back_buffer, width, height);
            let gleam = self.gleam.clone();

            let visual = ComPtr::new_with(|ptr_ptr| self.composition_device.CreateVisual(ptr_ptr))?;
            visual.SetContent(&*****swap_chain).to_result()?;
            self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).to_result()?;

            Ok(D3DVisual { visual, swap_chain, back_buffer, egl, gleam })
        }
    }
}

/// A DirectComposition "visual" configured for rendering with Direct3D.
pub struct D3DVisual {
    visual: ComPtr<IDCompositionVisual>,
    swap_chain: ComPtr<winapi::shared::dxgi1_2::IDXGISwapChain1>,

    #[allow(unused)]  // FIXME: does this need to be kept alive?
    back_buffer: ComPtr<winapi::um::d3d11::ID3D11Texture2D>,

    egl: egl::PerVisualEglThings,
    pub gleam: Rc<gleam::gl::Gl>,
}

impl D3DVisual {
    pub fn set_offset_x(&self, offset_x: f32) -> HResult<()> {
        unsafe {
            self.visual.SetOffsetX_1(offset_x).to_result()
        }
    }

    pub fn set_offset_y(&self, offset_y: f32) -> HResult<()> {
        unsafe {
            self.visual.SetOffsetY_1(offset_y).to_result()
        }
    }

    pub fn make_current(&self) {
        self.egl.make_current()
    }

    pub fn present(&self) {
        self.gleam.finish();
        unsafe {
            self.swap_chain.Present(0, 0).to_result().unwrap()
        }
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(test, deny(warnings))]
#![cfg_attr(test, allow(unstable))]

extern crate time;
extern crate conduit;
extern crate "conduit-middleware" as middleware;

use conduit::{Request, Method};
use middleware::Middleware;
use std::borrow::Cow;
use std::error::Error;
use std::io::util::NullReader;
use std::string::CowString;
use time::{Tm, strptime, ParseError};

type Response = Result<conduit::Response, Box<Error+Send>>;

#[allow(missing_copy_implementations)]
pub struct ConditionalGet;

impl Middleware for ConditionalGet {
    fn after(&self, req: &mut Request, res: Response) -> Response {
        let mut res = try!(res);

        match req.method() {
            Method::Get | Method::Head => {
                if is_ok(&res) && is_fresh(req, &res) {
                    res.status = (304, "Not Modified");
                    res.headers.remove("Content-Type");
                    res.headers.remove("Content-Length");
                    res.body = Box::new(NullReader);
                }
            },
            _ => ()
        }

        Ok(res)
    }
}

fn is_ok(response: &conduit::Response) -> bool {
    match *response {
        conduit::Response { status: (200, _), .. } => true,
        _ => false
    }
}

fn is_fresh(req: &Request, res: &conduit::Response) -> bool {
    let modified_since = req.headers().find("If-Modified-Since").map(header_val);
    let none_match     = req.headers().find("If-None-Match").map(header_val);

    if modified_since.as_ref().or_else(|| none_match.as_ref()).is_none() {
        return false;
    }

    let mut success = true;

    modified_since.and_then(|modified_since| {
        parse_http_date(modified_since).map_err(|_| { success = false; }).ok()
    }).map(|parsed| {
        success = success && is_modified_since(parsed, res);
    });

    none_match.map(|none_match| {
        success = success && etag_matches(none_match, res);
    });

    success
}

fn etag_matches<S: Str>(none_match: S, res: &conduit::Response) -> bool {
    res.headers.get("ETag").map(|etag| {
        res_header_val(etag).as_slice() == none_match.as_slice()
    }).unwrap_or(false)
}

fn is_modified_since(modified_since: Tm, res: &conduit::Response) -> bool {
    res.headers.get("Last-Modified").and_then(|last_modified| {
        parse_http_date(res_header_val(last_modified).as_slice()).ok()
    }).map(|last_modified| {
        modified_since.to_timespec() >= last_modified.to_timespec()
    }).unwrap_or(false)
}

fn header_val<'a>(header: Vec<&'a str>) -> CowString<'a> {
    if header.len() == 1 {
        Cow::Borrowed(header[0])
    } else {
        Cow::Owned(header.concat())
    }
}

fn res_header_val<'a>(header: &'a Vec<String>) -> CowString<'a> {
    if header.len() == 1 {
        Cow::Borrowed(header[0].as_slice())
    } else {
        Cow::Owned(header.concat())
    }
}

fn parse_http_date<S: Str>(string: S) -> Result<Tm, ()> {
    let string = string.as_slice();

    parse_rfc1123(string)
        .or_else(|_| parse_rfc850(string))
        .or_else(|_| parse_asctime(string))
        .map_err(|_| ())
}

fn parse_rfc1123(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d %b %Y %T GMT")
}

fn parse_rfc850(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d-%m-%y %T GMT")
}

fn parse_asctime(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a %m%t%d %T %Y")
}

#[cfg(test)]
mod tests {
    extern crate "conduit-test" as test;

    use std::collections::HashMap;
    use std::error::Error;
    use std::io::MemReader;
    use time;
    use time::Tm;
    use conduit;
    use conduit::{Request, Response, Handler, Method};
    use middleware::MiddlewareBuilder;

    use super::ConditionalGet;

    macro_rules! returning {
        ($code:expr, $($header:expr => $value:expr),+) => ({
            let mut headers = HashMap::new();
            $(headers.insert($header.to_string(), vec!($value.to_string()));)+
            let handler = SimpleHandler::new(headers, $code, "hello");
            let mut stack = MiddlewareBuilder::new(handler);
            stack.add(ConditionalGet);
            stack
        });
        ($($header:expr => $value:expr),+) => ({
            returning!((200, "OK"), $($header => $value),+)
        })
    }

    macro_rules! request {
        ($($header:expr => $value:expr),+) => ({
            let mut req = test::MockRequest::new(Method::Get, "/");
            $(req.header($header, $value.to_string().as_slice());)+
            req
        })
    }

    #[test]
    fn test_sends_304() {
        let handler = returning!("Last-Modified" => httpdate(time::now()));
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_if_older_than_now() {
        let handler = returning!("Last-Modified" => before_now());
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_etag() {
        let handler = returning!("ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time_but_not_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag_but_not_time() {
        let handler = returning!("Last-Modified" => now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag() {
        let handler = returning!("ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time() {
        let handler = returning!("Last-Modified" => now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now()
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_fresh_time_and_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_non_200() {
        let code = (302, "Found");
        let handler = returning!(code, "Last-Modified" => before_now(), "ETag" => "1234");
        expect(code, handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_malformed_timestamp() {
        let bad_stamp = time::now().strftime("%Y-%m-%d %H:%M:%S %z").unwrap().to_string();
        let handler = returning!("Last-Modified" => before_now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => bad_stamp
        ) as &mut conduit::Request));
    }

    fn expect_304(response: Result<Response, Box<Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let body = response.body.read_to_string().ok().expect("No body");

        assert_eq!(response.status, (304, "Not Modified"));
        assert_eq!(body.as_slice(), "");
    }

    fn expect_200(response: Result<Response, Box<Error+Send>>) {
        expect((200, "OK"), response);
    }

    fn expect(status: (u32, &'static str), response: Result<Response, Box<Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let body = response.body.read_to_string().ok().expect("No body");

        assert_eq!(response.status, status);
        assert_eq!(body.as_slice(), "hello");
    }

    struct SimpleHandler {
        map: HashMap<String, Vec<String>>,
        status: Status,
        body: &'static str
    }

    type Status = (u32, &'static str);

    impl SimpleHandler {
        fn new(map: HashMap<String, Vec<String>>, status: Status, body: &'static str) -> SimpleHandler {
            SimpleHandler { map: map, status: status, body: body }
        }
    }

    impl Handler for SimpleHandler {
        fn call(&self, _: &mut Request) -> Result<Response, Box<Error+Send>> {
            Ok(Response {
                status: self.status,
                headers: self.map.clone(),
                body: Box::new(MemReader::new(self.body.to_string().into_bytes())),
            })
        }
    }

    fn before_now() -> String {
        let mut now = time::now();
        now.tm_year -= 1;
        httpdate(now)
    }

    fn now() -> String {
        httpdate(time::now())
    }

    fn httpdate(time: Tm) -> String {
        time.strftime("%a, %d-%m-%y %T GMT").unwrap().to_string()
    }
}
<commit_msg>Add some feature gates<commit_after>#![feature(io, core)]
#![cfg_attr(test, feature(collections))]
#![cfg_attr(test, deny(warnings))]

extern crate time;
extern crate conduit;
extern crate "conduit-middleware" as middleware;

use conduit::{Request, Method};
use middleware::Middleware;
use std::borrow::Cow;
use std::error::Error;
use std::old_io::util::NullReader;
use std::string::CowString;
use time::{Tm, strptime, ParseError};

type Response = Result<conduit::Response, Box<Error+Send>>;

#[allow(missing_copy_implementations)]
pub struct ConditionalGet;

impl Middleware for ConditionalGet {
    fn after(&self, req: &mut Request, res: Response) -> Response {
        let mut res = try!(res);

        match req.method() {
            Method::Get | Method::Head => {
                if is_ok(&res) && is_fresh(req, &res) {
                    res.status = (304, "Not Modified");
                    res.headers.remove("Content-Type");
                    res.headers.remove("Content-Length");
                    res.body = Box::new(NullReader);
                }
            },
            _ => ()
        }

        Ok(res)
    }
}

fn is_ok(response: &conduit::Response) -> bool {
    match *response {
        conduit::Response { status: (200, _), .. } => true,
        _ => false
    }
}

fn is_fresh(req: &Request, res: &conduit::Response) -> bool {
    let modified_since = req.headers().find("If-Modified-Since").map(header_val);
    let none_match     = req.headers().find("If-None-Match").map(header_val);

    if modified_since.as_ref().or_else(|| none_match.as_ref()).is_none() {
        return false;
    }

    let mut success = true;

    modified_since.and_then(|modified_since| {
        parse_http_date(modified_since).map_err(|_| { success = false; }).ok()
    }).map(|parsed| {
        success = success && is_modified_since(parsed, res);
    });

    none_match.map(|none_match| {
        success = success && etag_matches(none_match, res);
    });

    success
}

fn etag_matches<S: Str>(none_match: S, res: &conduit::Response) -> bool {
    res.headers.get("ETag").map(|etag| {
        res_header_val(etag).as_slice() == none_match.as_slice()
    }).unwrap_or(false)
}

fn is_modified_since(modified_since: Tm, res: &conduit::Response) -> bool {
    res.headers.get("Last-Modified").and_then(|last_modified| {
        parse_http_date(res_header_val(last_modified).as_slice()).ok()
    }).map(|last_modified| {
        modified_since.to_timespec() >= last_modified.to_timespec()
    }).unwrap_or(false)
}

fn header_val<'a>(header: Vec<&'a str>) -> CowString<'a> {
    if header.len() == 1 {
        Cow::Borrowed(header[0])
    } else {
        Cow::Owned(header.concat())
    }
}

fn res_header_val<'a>(header: &'a Vec<String>) -> CowString<'a> {
    if header.len() == 1 {
        Cow::Borrowed(header[0].as_slice())
    } else {
        Cow::Owned(header.concat())
    }
}

fn parse_http_date<S: Str>(string: S) -> Result<Tm, ()> {
    let string = string.as_slice();

    parse_rfc1123(string)
        .or_else(|_| parse_rfc850(string))
        .or_else(|_| parse_asctime(string))
        .map_err(|_| ())
}

fn parse_rfc1123(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d %b %Y %T GMT")
}

fn parse_rfc850(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d-%m-%y %T GMT")
}

fn parse_asctime(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a %m%t%d %T %Y")
}

#[cfg(test)]
mod tests {
    extern crate "conduit-test" as test;

    use std::collections::HashMap;
    use std::error::Error;
    use std::old_io::MemReader;
    use time;
    use time::Tm;
    use conduit;
    use conduit::{Request, Response, Handler, Method};
    use middleware::MiddlewareBuilder;

    use super::ConditionalGet;

    macro_rules! returning {
        ($code:expr, $($header:expr => $value:expr),+) => ({
            let mut headers = HashMap::new();
            $(headers.insert($header.to_string(), vec!($value.to_string()));)+
            let handler = SimpleHandler::new(headers, $code, "hello");
            let mut stack = MiddlewareBuilder::new(handler);
            stack.add(ConditionalGet);
            stack
        });
        ($($header:expr => $value:expr),+) => ({
            returning!((200, "OK"), $($header => $value),+)
        })
    }

    macro_rules! request {
        ($($header:expr => $value:expr),+) => ({
            let mut req = test::MockRequest::new(Method::Get, "/");
            $(req.header($header, $value.to_string().as_slice());)+
            req
        })
    }

    #[test]
    fn test_sends_304() {
        let handler = returning!("Last-Modified" => httpdate(time::now()));
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_if_older_than_now() {
        let handler = returning!("Last-Modified" => before_now());
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_etag() {
        let handler = returning!("ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time_but_not_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag_but_not_time() {
        let handler = returning!("Last-Modified" => now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag() {
        let handler = returning!("ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time() {
        let handler = returning!("Last-Modified" => now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now()
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_fresh_time_and_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_non_200() {
        let code = (302, "Found");
        let handler = returning!(code, "Last-Modified" => before_now(), "ETag" => "1234");
        expect(code, handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_malformed_timestamp() {
        let bad_stamp = time::now().strftime("%Y-%m-%d %H:%M:%S %z").unwrap().to_string();
        let handler = returning!("Last-Modified" => before_now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => bad_stamp
        ) as &mut conduit::Request));
    }

    fn expect_304(response: Result<Response, Box<Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let body = response.body.read_to_string().ok().expect("No body");

        assert_eq!(response.status, (304, "Not Modified"));
        assert_eq!(body.as_slice(), "");
    }

    fn expect_200(response: Result<Response, Box<Error+Send>>) {
        expect((200, "OK"), response);
    }

    fn expect(status: (u32, &'static str), response: Result<Response, Box<Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let body = response.body.read_to_string().ok().expect("No body");

        assert_eq!(response.status, status);
        assert_eq!(body.as_slice(), "hello");
    }

    struct SimpleHandler {
        map: HashMap<String, Vec<String>>,
        status: Status,
        body: &'static str
    }

    type Status = (u32, &'static str);

    impl SimpleHandler {
        fn new(map: HashMap<String, Vec<String>>, status: Status, body: &'static str) -> SimpleHandler {
            SimpleHandler { map: map, status: status, body: body }
        }
    }

    impl Handler for SimpleHandler {
        fn call(&self, _: &mut Request) -> Result<Response, Box<Error+Send>> {
            Ok(Response {
                status: self.status,
                headers: self.map.clone(),
                body: Box::new(MemReader::new(self.body.to_string().into_bytes())),
            })
        }
    }

    fn before_now() -> String {
        let mut now = time::now();
        now.tm_year -= 1;
        httpdate(now)
    }

    fn now() -> String {
        httpdate(time::now())
    }

    fn httpdate(time: Tm) -> String {
        time.strftime("%a, %d-%m-%y %T GMT").unwrap().to_string()
    }
}
<|endoftext|>


<commit_before>// #![deny(warnings)]

#[macro_use]
extern crate error_chain;
extern crate fern;
#[macro_use]
extern crate log;
extern crate log_panics;
extern crate libc;
extern crate time;
extern crate x11;
extern crate xcb;
extern crate xcb_util;
extern crate xdg;

use std::cell::RefCell;
use std::cmp;
use std::rc::Rc;

pub mod cmd;
mod debug;
pub mod errors;
mod groups;
mod keys;
pub mod layout;
mod stack;
mod window;
mod x;

use errors::*;
use groups::Group;
use keys::{KeyCombo, KeyHandlers};
use layout::Layout;
use stack::Stack;
use x::{Connection, Event, StrutPartial, WindowId, WindowType};

pub use groups::GroupBuilder;
pub use keys::ModKey;

pub mod keysym {
    pub use x11::keysym::*;
}

/// Initializes a logger using the default configuration.
///
/// Outputs to stdout and $XDG_DATA/lanta/lanta.log by default.
/// You should feel free to initialize your own logger, instead of using this.
pub fn intiailize_logger() -> Result<()> {
    log_panics::init();

    let xdg_dirs = xdg::BaseDirectories::with_prefix("lanta")?;
    let log_path = xdg_dirs
        .place_data_file("lanta.log")
        .chain_err(|| "Could not create log file")?;

    let logger_config = fern::DispatchConfig {
        format: Box::new(
            |msg: &str, level: &log::LogLevel, _location: &log::LogLocation| {
                format!("[{}] [{}] {}", time::now().rfc3339(), level, msg)
            },
        ),
        output: vec![
            fern::OutputConfig::stdout(),
            fern::OutputConfig::file(&log_path),
        ],
        level: log::LogLevelFilter::Trace,
    };
    Ok(fern::init_global_logger(
        logger_config,
        log::LogLevelFilter::Trace,
    )?)
}

#[macro_export]
macro_rules! keys {
    [ $( ([$( $mod:ident ),*], $key:ident, $cmd:expr) ),+ $(,)*] => (
        vec![
            $( (vec![$( $mod ),*], ::lanta::keysym::$key, $cmd) ),+
        ]
    )
}

#[macro_export]
macro_rules! groups {
    {
        $keys:ident,
        $movemodkey:ident,
        [
            $(( [$( $modkey:ident ),+], $key:ident, $name:expr, $layout:expr )),+
            $(,)*
        ]
    }  => {{
        $keys.extend(keys![
            // Switch to group:
            $(
                ([$($modkey),+], $key, ::lanta::cmd::lazy::switch_group($name))
            ),+,
            // Move window to group:
            $(
                ([$($modkey),+, $movemodkey], $key, ::lanta::cmd::lazy::move_window_to_group($name))
            ),+
        ]);
        vec![
            $(
                ::lanta::GroupBuilder::new($name, $layout)
            ),+
        ]
    }}
}

#[derive(Clone, Copy, Debug, Default)]
pub struct Viewport {
    pub x: u32,
    pub y: u32,
    pub width: u32,
    pub height: u32,
}

struct Dock {
    window_id: WindowId,
    strut_partial: Option<StrutPartial>,
}

#[derive(Default)]
struct Screen {
    vec: RefCell<Vec<Dock>>,
}

impl Screen {
    pub fn add_dock(&mut self, conn: &Connection, window_id: WindowId) {
        let strut_partial = conn.get_strut_partial(&window_id);
        self.vec.borrow_mut().push(Dock {
            window_id,
            strut_partial,
        });
    }

    pub fn remove_dock(&mut self, window_id: &WindowId) {
        self.vec.borrow_mut().retain(|d| &d.window_id != window_id);
    }

    /// Figure out the usable area of the screen based on the STRUT_PARTIAL of
    /// all docks.
    pub fn viewport(&self, screen_width: u32, screen_height: u32) -> Viewport {
        let (left, right, top, bottom) = self.vec
            .borrow()
            .iter()
            .filter_map(|o| o.strut_partial.as_ref())
            .fold((0, 0, 0, 0), |(left, right, top, bottom), s| {
                // We don't bother looking at the start/end members of the
                // StrutPartial - treating it more like a Strut.
                (
                    cmp::max(left, s.left()),
                    cmp::max(right, s.right()),
                    cmp::max(top, s.top()),
                    cmp::max(bottom, s.bottom()),
                )
            });
        let viewport = Viewport {
            x: left,
            y: top,
            width: screen_width - left - right,
            height: screen_height - top - bottom,
        };
        debug!("Calculated Viewport as {:?}", viewport);
        viewport
    }
}

pub struct Lanta {
    connection: Rc<Connection>,
    keys: KeyHandlers,
    groups: Stack<Group>,
    screen: Screen,
}

impl Lanta {
    pub fn new<K>(keys: K, groups: Vec<GroupBuilder>, layouts: Vec<Box<Layout>>) -> Result<Self>
    where
        K: Into<KeyHandlers>,
    {
        let keys = keys.into();
        let connection = Rc::new(Connection::connect()?);
        connection.install_as_wm(&keys)?;

        let groups = Stack::from(
            groups
                .into_iter()
                .map(|group: GroupBuilder| {
                    group.build(connection.clone(), layouts.clone())
                })
                .collect::<Vec<Group>>(),
        );

        let mut wm = Lanta {
            connection: connection.clone(),
            keys: keys,
            groups: groups,
            screen: Screen::default(),
        };

        // Learn about existing top-level windows.
        let existing_windows = connection.top_level_windows()?;
        for window in existing_windows {
            wm.manage_window(window);
        }
        let viewport = wm.viewport();
        wm.group_mut().activate(viewport);
        wm.connection.update_ewmh_desktops(&wm.groups);

        Ok(wm)
    }

    fn viewport(&self) -> Viewport {
        let (width, height) = self.connection
            .get_window_geometry(self.connection.root_window_id());
        self.screen.viewport(width, height)
    }

    pub fn group(&self) -> &Group {
        self.groups.focused().expect("Invariant: No active group!")
    }

    pub fn group_mut(&mut self) -> &mut Group {
        self.groups
            .focused_mut()
            .expect("Invariant: No active group!")
    }

    pub fn switch_group<'a, S>(&'a mut self, name: S)
    where
        S: Into<&'a str>,
    {
        let name = name.into();

        // If we're already on this group, do nothing.
        if self.group().name() == name {
            return;
        }

        self.group_mut().deactivate();
        self.groups.focus(|group| group.name() == name);
        let viewport = self.viewport();
        self.group_mut().activate(viewport);
        self.connection.update_ewmh_desktops(&self.groups);
    }

    /// Move the focused window from the active group to another named group.
    ///
    /// If the other named group does not exist, then the window is
    /// (unfortunately) lost.
    pub fn move_focused_to_group<'a, S>(&'a mut self, name: S)
    where
        S: Into<&'a str>,
    {
        let name = name.into();

        // If the group is currently active, then do nothing. This avoids flicker as we
        // unmap/remap.
        if name == self.group().name() {
            return;
        }

        let removed = self.group_mut().remove_focused();
        let new_group_opt = self.groups.iter_mut().find(|group| group.name() == name);
        match new_group_opt {
            Some(new_group) => {
                removed.map(|window| new_group.add_window(window));
            }
            None => {
                // It would be nice to put the window back in its group (or avoid taking it out
                // of its group until we've checked the new group exists), but it's difficult
                // to do this while keeping the borrow checker happy.
                error!("Moved window to non-existent group: {}", name);
            }
        }
    }

    /// Returns whether the window is a member of any group.
    fn is_window_managed(&self, window_id: &WindowId) -> bool {
        self.groups.iter().any(|g| g.contains(window_id))
    }

    pub fn manage_window(&mut self, window_id: WindowId) {
        debug!("Managing window: {}", window_id);

        // If we are already managing the window, then do nothing. We do not
        // want the window to end up in two groups at once. We shouldn't
        // be called in such cases, so treat it as an error.
        if self.is_window_managed(&window_id) {
            error!(
                "Asked to manage window that's already managed: {}",
                window_id
            );
            return;
        }

        let window_types = self.connection.get_window_types(&window_id);
        let dock = window_types.contains(&WindowType::Dock);

        self.connection
            .enable_window_key_events(&window_id, &self.keys);

        if dock {
            self.screen.add_dock(&self.connection, window_id);
            let viewport = self.viewport();
            self.group_mut().update_viewport(viewport);
        } else {
            self.connection.enable_window_tracking(&window_id);
            self.group_mut().add_window(window_id);
        }
    }

    pub fn unmanage_window(&mut self, window_id: WindowId) {
        debug!("Unmanaging window: {}", window_id);

        // Remove the window from whichever Group it is in. Special case for
        // docks which aren't in any group.
        self.groups
            .iter_mut()
            .find(|group| group.contains(&window_id))
            .map(|group| group.remove_window(&window_id));
        self.screen.remove_dock(&window_id);

        // The viewport may have changed.
        let viewport = self.viewport();
        self.group_mut().update_viewport(viewport);
    }

    pub fn run(mut self) {
        info!("Started WM, entering event loop.");
        let event_loop_connection = self.connection.clone();
        let event_loop = event_loop_connection.get_event_loop();
        for event in event_loop {
            match event {
                Event::MapRequest(window_id) => self.on_map_request(window_id),
                Event::UnmapNotify(window_id) => self.on_unmap_notify(window_id),
                Event::DestroyNotify(window_id) => self.on_destroy_notify(window_id),
                Event::KeyPress(key) => self.on_key_press(key),
                Event::EnterNotify(window_id) => self.on_enter_notify(window_id),
            }
        }
        info!("Event loop exiting");
    }

    fn on_map_request(&mut self, window_id: WindowId) {
        if !self.is_window_managed(&window_id) {
            // If the window isn't in any group, then add it to the current group.
            // (This will have the side-effect of mapping the window, as new windows are focused
            // and focused windows are mapped).
            self.manage_window(window_id);
        } else if self.group().contains(&window_id) {
            // Otherwise, if the window is in the active group, focus it. The application probably
            // wants us to make it prominent. Log as there may be misbehaving applications that
            // constantly re-map windows and cause focus issues.
            info!("Window {} asked to be mapped but is already mapped: focusing.", window_id);
            self.group_mut().focus(&window_id);
        }
    }

    fn on_unmap_notify(&mut self, window_id: WindowId) {
        // We only receive an unmap notify event when the window is actually
        // unmapped by its application. When our layouts unmap windows, they
        // (should) do it by disabling event tracking first.
        self.unmanage_window(window_id);
    }

    fn on_destroy_notify(&mut self, window_id: WindowId) {
        self.unmanage_window(window_id);
    }

    fn on_key_press(&mut self, key: KeyCombo) {
        self.keys.get(&key).map(move |handler| (handler)(self));
    }

    fn on_enter_notify(&mut self, window_id: WindowId) {
        self.group_mut().focus(&window_id);
    }
}
<commit_msg>Map docks explicitly.<commit_after>// #![deny(warnings)]

#[macro_use]
extern crate error_chain;
extern crate fern;
#[macro_use]
extern crate log;
extern crate log_panics;
extern crate libc;
extern crate time;
extern crate x11;
extern crate xcb;
extern crate xcb_util;
extern crate xdg;

use std::cell::RefCell;
use std::cmp;
use std::rc::Rc;

pub mod cmd;
mod debug;
pub mod errors;
mod groups;
mod keys;
pub mod layout;
mod stack;
mod window;
mod x;

use errors::*;
use groups::Group;
use keys::{KeyCombo, KeyHandlers};
use layout::Layout;
use stack::Stack;
use x::{Connection, Event, StrutPartial, WindowId, WindowType};

pub use groups::GroupBuilder;
pub use keys::ModKey;

pub mod keysym {
    pub use x11::keysym::*;
}

/// Initializes a logger using the default configuration.
///
/// Outputs to stdout and $XDG_DATA/lanta/lanta.log by default.
/// You should feel free to initialize your own logger, instead of using this.
pub fn intiailize_logger() -> Result<()> {
    log_panics::init();

    let xdg_dirs = xdg::BaseDirectories::with_prefix("lanta")?;
    let log_path = xdg_dirs
        .place_data_file("lanta.log")
        .chain_err(|| "Could not create log file")?;

    let logger_config = fern::DispatchConfig {
        format: Box::new(
            |msg: &str, level: &log::LogLevel, _location: &log::LogLocation| {
                format!("[{}] [{}] {}", time::now().rfc3339(), level, msg)
            },
        ),
        output: vec![
            fern::OutputConfig::stdout(),
            fern::OutputConfig::file(&log_path),
        ],
        level: log::LogLevelFilter::Trace,
    };
    Ok(fern::init_global_logger(
        logger_config,
        log::LogLevelFilter::Trace,
    )?)
}

#[macro_export]
macro_rules! keys {
    [ $( ([$( $mod:ident ),*], $key:ident, $cmd:expr) ),+ $(,)*] => (
        vec![
            $( (vec![$( $mod ),*], ::lanta::keysym::$key, $cmd) ),+
        ]
    )
}

#[macro_export]
macro_rules! groups {
    {
        $keys:ident,
        $movemodkey:ident,
        [
            $(( [$( $modkey:ident ),+], $key:ident, $name:expr, $layout:expr )),+
            $(,)*
        ]
    }  => {{
        $keys.extend(keys![
            // Switch to group:
            $(
                ([$($modkey),+], $key, ::lanta::cmd::lazy::switch_group($name))
            ),+,
            // Move window to group:
            $(
                ([$($modkey),+, $movemodkey], $key, ::lanta::cmd::lazy::move_window_to_group($name))
            ),+
        ]);
        vec![
            $(
                ::lanta::GroupBuilder::new($name, $layout)
            ),+
        ]
    }}
}

#[derive(Clone, Copy, Debug, Default)]
pub struct Viewport {
    pub x: u32,
    pub y: u32,
    pub width: u32,
    pub height: u32,
}

struct Dock {
    window_id: WindowId,
    strut_partial: Option<StrutPartial>,
}

#[derive(Default)]
struct Screen {
    vec: RefCell<Vec<Dock>>,
}

impl Screen {
    pub fn add_dock(&mut self, conn: &Connection, window_id: WindowId) {
        let strut_partial = conn.get_strut_partial(&window_id);
        self.vec.borrow_mut().push(Dock {
            window_id,
            strut_partial,
        });
    }

    pub fn remove_dock(&mut self, window_id: &WindowId) {
        self.vec.borrow_mut().retain(|d| &d.window_id != window_id);
    }

    /// Figure out the usable area of the screen based on the STRUT_PARTIAL of
    /// all docks.
    pub fn viewport(&self, screen_width: u32, screen_height: u32) -> Viewport {
        let (left, right, top, bottom) = self.vec
            .borrow()
            .iter()
            .filter_map(|o| o.strut_partial.as_ref())
            .fold((0, 0, 0, 0), |(left, right, top, bottom), s| {
                // We don't bother looking at the start/end members of the
                // StrutPartial - treating it more like a Strut.
                (
                    cmp::max(left, s.left()),
                    cmp::max(right, s.right()),
                    cmp::max(top, s.top()),
                    cmp::max(bottom, s.bottom()),
                )
            });
        let viewport = Viewport {
            x: left,
            y: top,
            width: screen_width - left - right,
            height: screen_height - top - bottom,
        };
        debug!("Calculated Viewport as {:?}", viewport);
        viewport
    }
}

pub struct Lanta {
    connection: Rc<Connection>,
    keys: KeyHandlers,
    groups: Stack<Group>,
    screen: Screen,
}

impl Lanta {
    pub fn new<K>(keys: K, groups: Vec<GroupBuilder>, layouts: Vec<Box<Layout>>) -> Result<Self>
    where
        K: Into<KeyHandlers>,
    {
        let keys = keys.into();
        let connection = Rc::new(Connection::connect()?);
        connection.install_as_wm(&keys)?;

        let groups = Stack::from(
            groups
                .into_iter()
                .map(|group: GroupBuilder| {
                    group.build(connection.clone(), layouts.clone())
                })
                .collect::<Vec<Group>>(),
        );

        let mut wm = Lanta {
            connection: connection.clone(),
            keys: keys,
            groups: groups,
            screen: Screen::default(),
        };

        // Learn about existing top-level windows.
        let existing_windows = connection.top_level_windows()?;
        for window in existing_windows {
            wm.manage_window(window);
        }
        let viewport = wm.viewport();
        wm.group_mut().activate(viewport);
        wm.connection.update_ewmh_desktops(&wm.groups);

        Ok(wm)
    }

    fn viewport(&self) -> Viewport {
        let (width, height) = self.connection
            .get_window_geometry(self.connection.root_window_id());
        self.screen.viewport(width, height)
    }

    pub fn group(&self) -> &Group {
        self.groups.focused().expect("Invariant: No active group!")
    }

    pub fn group_mut(&mut self) -> &mut Group {
        self.groups
            .focused_mut()
            .expect("Invariant: No active group!")
    }

    pub fn switch_group<'a, S>(&'a mut self, name: S)
    where
        S: Into<&'a str>,
    {
        let name = name.into();

        // If we're already on this group, do nothing.
        if self.group().name() == name {
            return;
        }

        self.group_mut().deactivate();
        self.groups.focus(|group| group.name() == name);
        let viewport = self.viewport();
        self.group_mut().activate(viewport);
        self.connection.update_ewmh_desktops(&self.groups);
    }

    /// Move the focused window from the active group to another named group.
    ///
    /// If the other named group does not exist, then the window is
    /// (unfortunately) lost.
    pub fn move_focused_to_group<'a, S>(&'a mut self, name: S)
    where
        S: Into<&'a str>,
    {
        let name = name.into();

        // If the group is currently active, then do nothing. This avoids flicker as we
        // unmap/remap.
        if name == self.group().name() {
            return;
        }

        let removed = self.group_mut().remove_focused();
        let new_group_opt = self.groups.iter_mut().find(|group| group.name() == name);
        match new_group_opt {
            Some(new_group) => {
                removed.map(|window| new_group.add_window(window));
            }
            None => {
                // It would be nice to put the window back in its group (or avoid taking it out
                // of its group until we've checked the new group exists), but it's difficult
                // to do this while keeping the borrow checker happy.
                error!("Moved window to non-existent group: {}", name);
            }
        }
    }

    /// Returns whether the window is a member of any group.
    fn is_window_managed(&self, window_id: &WindowId) -> bool {
        self.groups.iter().any(|g| g.contains(window_id))
    }

    pub fn manage_window(&mut self, window_id: WindowId) {
        debug!("Managing window: {}", window_id);

        // If we are already managing the window, then do nothing. We do not
        // want the window to end up in two groups at once. We shouldn't
        // be called in such cases, so treat it as an error.
        if self.is_window_managed(&window_id) {
            error!(
                "Asked to manage window that's already managed: {}",
                window_id
            );
            return;
        }

        let window_types = self.connection.get_window_types(&window_id);
        let dock = window_types.contains(&WindowType::Dock);

        self.connection
            .enable_window_key_events(&window_id, &self.keys);

        if dock {
            self.connection.map_window(&window_id);
            self.screen.add_dock(&self.connection, window_id);
            let viewport = self.viewport();
            self.group_mut().update_viewport(viewport);
        } else {
            self.connection.enable_window_tracking(&window_id);
            self.group_mut().add_window(window_id);
        }
    }

    pub fn unmanage_window(&mut self, window_id: WindowId) {
        debug!("Unmanaging window: {}", window_id);

        // Remove the window from whichever Group it is in. Special case for
        // docks which aren't in any group.
        self.groups
            .iter_mut()
            .find(|group| group.contains(&window_id))
            .map(|group| group.remove_window(&window_id));
        self.screen.remove_dock(&window_id);

        // The viewport may have changed.
        let viewport = self.viewport();
        self.group_mut().update_viewport(viewport);
    }

    pub fn run(mut self) {
        info!("Started WM, entering event loop.");
        let event_loop_connection = self.connection.clone();
        let event_loop = event_loop_connection.get_event_loop();
        for event in event_loop {
            match event {
                Event::MapRequest(window_id) => self.on_map_request(window_id),
                Event::UnmapNotify(window_id) => self.on_unmap_notify(window_id),
                Event::DestroyNotify(window_id) => self.on_destroy_notify(window_id),
                Event::KeyPress(key) => self.on_key_press(key),
                Event::EnterNotify(window_id) => self.on_enter_notify(window_id),
            }
        }
        info!("Event loop exiting");
    }

    fn on_map_request(&mut self, window_id: WindowId) {
        if !self.is_window_managed(&window_id) {
            // If the window isn't in any group, then add it to the current group.
            // (This will have the side-effect of mapping the window, as new windows are focused
            // and focused windows are mapped).
            self.manage_window(window_id);
        } else if self.group().contains(&window_id) {
            // Otherwise, if the window is in the active group, focus it. The application probably
            // wants us to make it prominent. Log as there may be misbehaving applications that
            // constantly re-map windows and cause focus issues.
            info!("Window {} asked to be mapped but is already mapped: focusing.", window_id);
            self.group_mut().focus(&window_id);
        }
    }

    fn on_unmap_notify(&mut self, window_id: WindowId) {
        // We only receive an unmap notify event when the window is actually
        // unmapped by its application. When our layouts unmap windows, they
        // (should) do it by disabling event tracking first.
        self.unmanage_window(window_id);
    }

    fn on_destroy_notify(&mut self, window_id: WindowId) {
        self.unmanage_window(window_id);
    }

    fn on_key_press(&mut self, key: KeyCombo) {
        self.keys.get(&key).map(move |handler| (handler)(self));
    }

    fn on_enter_notify(&mut self, window_id: WindowId) {
        self.group_mut().focus(&window_id);
    }
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};

pub struct DeepWalk {
    root: PathBuf,
}

impl DeepWalk {
    pub fn new<P: AsRef<Path>>(root: P) -> Self {
        DeepWalk { root: root.as_ref().to_path_buf() }
    }
}

impl IntoIterator for DeepWalk {
    type Item = Result<Entry, Error>;
    type IntoIter = Iter;

    fn into_iter(self) -> Iter {
        Iter { root: self.root }
    }
}

pub struct Iter {
    root: PathBuf,
}

impl Iterator for Iter {
    type Item = Result<Entry, Error>;

    fn next(&mut self) -> Option<Result<Entry, Error>> {
        None
    }
}

pub struct Entry {
    //
}

pub struct Error {
    //
}

#[cfg(test)]
mod tests {
    use super::DeepWalk;
    use std::path::Path;

    fn get_test_roots() -> &'static[&'static str] {
        const DATA: &'static[&'static str] = &["", "a", "test", "eee/aaa", "some/long/path"];
        DATA
    }

    #[test]
    fn deep_walk_new() {
        for val in get_test_roots() {
            assert_eq!(DeepWalk::new(val).root, Path::new(val));
        }
    }

    #[test]
    fn deep_walk_into_iterator() {
        for val in get_test_roots() {
            assert_eq!(DeepWalk::new(val).into_iter().root, Path::new(val));
        }
    }
}
<commit_msg>TODO comment<commit_after>use std::path::{Path, PathBuf};

pub struct DeepWalk {
    root: PathBuf,
}

impl DeepWalk {
    pub fn new<P: AsRef<Path>>(root: P) -> Self {
        DeepWalk { root: root.as_ref().to_path_buf() }
    }
}

impl IntoIterator for DeepWalk {
    type Item = Result<Entry, Error>;
    type IntoIter = Iter;

    fn into_iter(self) -> Iter {
        Iter { root: self.root }
    }
}

pub struct Iter {
    root: PathBuf,
}

// TODO: Remove and implement Iterator for DeepWalk.
impl Iterator for Iter {
    type Item = Result<Entry, Error>;

    fn next(&mut self) -> Option<Result<Entry, Error>> {
        None
    }
}

pub struct Entry {
    //
}

pub struct Error {
    //
}

#[cfg(test)]
mod tests {
    use super::DeepWalk;
    use std::path::Path;

    fn get_test_roots() -> &'static[&'static str] {
        const DATA: &'static[&'static str] = &["", "a", "test", "eee/aaa", "some/long/path"];
        DATA
    }

    #[test]
    fn deep_walk_new() {
        for val in get_test_roots() {
            assert_eq!(DeepWalk::new(val).root, Path::new(val));
        }
    }

    #[test]
    fn deep_walk_into_iterator() {
        for val in get_test_roots() {
            assert_eq!(DeepWalk::new(val).into_iter().root, Path::new(val));
        }
    }
}
<|endoftext|>


<commit_before>// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! # Intecture API
//!
//! The Intecture API is the interface between your code and your managed
//! hosts. The library is organised into a set of 'primitives', which
//! are the building blocks used to configure your systems.
//! Developers should implement these primitives in their source code
//! in order to configure and maintain their managed hosts.
//!
//! ## Communication
//!
//! The API communicates with the Agent service on your managed hosts
//! via a ZeroMQ "REQ" (REQuest) socket. No other socket types are
//! supported by the Intecture Agent.
//!
//! **Note:** The Agent service must be running when you call any
//! Intecture API primitives, or the program will hang while it
//! attempts to connect to a non-existent socket.

#[cfg(feature = "remote-run")]
extern crate czmq;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate mustache;
extern crate regex;
extern crate rustc_serialize;
extern crate serde;
extern crate serde_json;
#[cfg(test)]
extern crate tempdir;
extern crate tempfile;
extern crate zdaemon;
extern crate zfilexfer;

#[macro_use]
mod ffi_helpers;
pub mod command;
mod config;
pub mod directory;
pub mod error;
pub mod file;
#[macro_use]
mod host;
#[cfg(all(test, feature = "remote-run"))]
mod mock_env;
pub mod package;
pub mod service;
mod target;
pub mod template;

pub use command::{Command, CommandResult};
pub use directory::{Directory, DirectoryOpts};
pub use error::Error;
pub use file::{File, FileOwner};
pub use host::Host;
pub use host::ffi::{get_value, get_value_keys, get_value_type};
#[cfg(feature = "local-run")]
pub use host::ffi::host_local;
#[cfg(feature = "remote-run")]
pub use host::ffi::{host_connect, host_connect_endpoint, host_close};
pub use mustache::{MapBuilder, VecBuilder};
pub use package::Package;
pub use package::providers::{Provider, ProviderFactory, Providers};
pub use serde_json::Value;
pub use service::{Service, ServiceRunnable};
pub use template::Template;
pub use zfilexfer::FileOptions;

#[cfg(feature = "remote-run")]
use zdaemon::ConfigFile;

#[cfg(all(test, feature = "remote-run"))]
lazy_static! {
    static ref _MOCK_ENV: mock_env::MockEnv = mock_env::MockEnv::new();
}

#[cfg(feature = "remote-run")]
lazy_static! {
    static ref PROJECT_CONFIG: config::Config = config::Config::load("project.json").expect("Could not load project.json");
}
<commit_msg>What the hell happened to the copyright??<commit_after>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! # Intecture API
//!
//! The Intecture API is the interface between your code and your managed
//! hosts. The library is organised into a set of 'primitives', which
//! are the building blocks used to configure your systems.
//! Developers should implement these primitives in their source code
//! in order to configure and maintain their managed hosts.
//!
//! ## Communication
//!
//! The API communicates with the Agent service on your managed hosts
//! via a ZeroMQ "REQ" (REQuest) socket. No other socket types are
//! supported by the Intecture Agent.
//!
//! **Note:** The Agent service must be running when you call any
//! Intecture API primitives, or the program will hang while it
//! attempts to connect to a non-existent socket.

#[cfg(feature = "remote-run")]
extern crate czmq;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate mustache;
extern crate regex;
extern crate rustc_serialize;
extern crate serde;
extern crate serde_json;
#[cfg(test)]
extern crate tempdir;
extern crate tempfile;
extern crate zdaemon;
extern crate zfilexfer;

#[macro_use]
mod ffi_helpers;
pub mod command;
mod config;
pub mod directory;
pub mod error;
pub mod file;
#[macro_use]
mod host;
#[cfg(all(test, feature = "remote-run"))]
mod mock_env;
pub mod package;
pub mod service;
mod target;
pub mod template;

pub use command::{Command, CommandResult};
pub use directory::{Directory, DirectoryOpts};
pub use error::Error;
pub use file::{File, FileOwner};
pub use host::Host;
pub use host::ffi::{get_value, get_value_keys, get_value_type};
#[cfg(feature = "local-run")]
pub use host::ffi::host_local;
#[cfg(feature = "remote-run")]
pub use host::ffi::{host_connect, host_connect_endpoint, host_close};
pub use mustache::{MapBuilder, VecBuilder};
pub use package::Package;
pub use package::providers::{Provider, ProviderFactory, Providers};
pub use serde_json::Value;
pub use service::{Service, ServiceRunnable};
pub use template::Template;
pub use zfilexfer::FileOptions;

#[cfg(feature = "remote-run")]
use zdaemon::ConfigFile;

#[cfg(all(test, feature = "remote-run"))]
lazy_static! {
    static ref _MOCK_ENV: mock_env::MockEnv = mock_env::MockEnv::new();
}

#[cfg(feature = "remote-run")]
lazy_static! {
    static ref PROJECT_CONFIG: config::Config = config::Config::load("project.json").expect("Could not load project.json");
}
<|endoftext|>


<commit_before>#![feature(box_syntax)]
#![feature(core)]
extern crate core;
use core::fmt::Debug;

pub struct Expectation<Lhs: Debug>(Lhs);

pub struct To<Lhs: Debug>(Lhs);

pub trait Matcher<Lhs> {
    fn matches(&self, rhs: &Lhs) -> bool;
    fn fail_msg(&self, rhs: &Lhs) -> String;
}

pub trait WithLen {
    fn match_len(&self) -> usize;
}

impl<T> WithLen for Vec<T> {
    fn match_len(&self) -> usize { self.len() }
}

impl WithLen for String {
    fn match_len(&self) -> usize { self.chars().count() }
}

impl<'a> WithLen for &'a str {
    fn match_len(&self) -> usize { self.chars().count() }
}

pub struct Contains<T>(T);

impl<T: Debug + PartialEq> Matcher<Vec<T>> for Contains<T> {
    fn matches(&self, lhs: &Vec<T>) -> bool {
        lhs.iter().any(|i| *i == self.0)
    }

    fn fail_msg(&self, lhs: &Vec<T>) -> String {
        format!("expected {:?} to contain {:?}", lhs, self.0)
    }
}

impl Matcher<String> for Contains<char> {
    fn matches(&self, lhs: &String) -> bool {
        lhs.chars().any(|i| i == self.0)
    }

    fn fail_msg(&self, lhs: &String) -> String {
        format!("expected {:?} to contain {:?}", lhs, self.0)
    }
}

impl Matcher<String> for Contains<String> {
    fn matches(&self, lhs: &String) -> bool {
        lhs.contains(&*self.0)
    }

    fn fail_msg(&self, lhs: &String) -> String {
        format!("expected {:?} to contain {:?}", lhs, self.0)
    }
}

pub struct Empty;

impl<Lhs: Debug + WithLen> Matcher<Lhs> for Empty {
    fn matches(&self, rhs: &Lhs) -> bool {
        rhs.match_len() == 0
    }

    fn fail_msg(&self, rhs: &Lhs) -> String {
        format!("expected {:?} to be empty", rhs)
    }
}

pub struct LessThan<Lhs: Debug>(Lhs);

impl<Lhs: Debug + PartialOrd> Matcher<Lhs> for LessThan<Lhs> {
    fn matches(&self, lhs: &Lhs) -> bool {
        *lhs < self.0
    }

    fn fail_msg(&self, lhs: &Lhs) -> String {
        format!("expected {:?} to be less than {:?}", lhs, self.0)
    }
}

pub struct GreaterThan<Lhs: Debug>(Lhs);

impl<Lhs: Debug + PartialOrd> Matcher<Lhs> for GreaterThan<Lhs> {
    fn matches(&self, lhs: &Lhs) -> bool {
        *lhs > self.0
    }

    fn fail_msg(&self, lhs: &Lhs) -> String {
        format!("expected {:?} to be greater than {:?}", lhs, self.0)
    }
}

pub struct Equal<Lhs: Debug>(Lhs);

impl<Lhs: Debug + PartialEq> Matcher<Lhs> for Equal<Lhs> {
    fn matches(&self, rhs: &Lhs) -> bool {
        &self.0 == rhs
    }

    fn fail_msg(&self, rhs: &Lhs) -> String {
        format!("expected {:?} to equal {:?}", rhs, self.0)
    }
}

pub struct AllOf<A: Debug>(Vec<Box<Matcher<A>>>);

impl<Lhs: Debug> Matcher<Lhs> for AllOf<Lhs> {
    fn matches(&self, lhs: &Lhs) -> bool {
        self.0.iter().all(|bm| bm.matches(lhs))
    }

    fn fail_msg(&self, lhs: &Lhs) -> String {
        format!("expected all of {:?}",
                self.0.iter().map(|m| m.fail_msg(lhs)).collect::<Vec<String>>())
    }
}

pub struct AnyOf<A: Debug>(Vec<Box<Matcher<A>>>);

impl<Lhs: Debug> Matcher<Lhs> for AnyOf<Lhs> {
    fn matches(&self, lhs: &Lhs) -> bool {
        self.0.iter().any(|bm| bm.matches(lhs))
    }

    fn fail_msg(&self, lhs: &Lhs) -> String {
        format!("expected one of {:?}",
                self.0.iter().map(|m| m.fail_msg(lhs)).collect::<Vec<String>>())
    }
}

pub struct Not<A>(Box<Matcher<A>>);

impl<Lhs: Debug> Matcher<Lhs> for Not<Lhs> {
    fn matches(&self, rhs: &Lhs) -> bool {
        !self.0.matches(rhs)
    }

    fn fail_msg(&self, rhs: &Lhs) -> String {
        format!("not {}", self.0.fail_msg(rhs))
    }
}

impl<Lhs: Debug> Expectation<Lhs> {
    pub fn is<T>(&self, matcher: Box<T>) where T: Matcher<Lhs> {
        self.to(matcher)
    }

    pub fn to<T>(&self, matcher: Box<T>) where T: Matcher<Lhs> {
        if !matcher.matches(&self.0) {
            panic!(matcher.fail_msg(&self.0))
        }
    }
}

pub fn expect<T: Debug>(lhs: T) -> Expectation<T> {
    Expectation(lhs)
}

pub fn equal<T: Debug>(rhs: T) -> Box<Equal<T>> {
    box Equal(rhs)
}

pub fn not<T: Debug>(rhs: Box<Matcher<T>>) -> Box<Not<T>> {
    box Not(rhs)
}

pub fn empty() -> Box<Empty> {
    box Empty
}

pub fn contain<T: Debug>(rhs: T) -> Box<Contains<T>> {
    box Contains(rhs)
}

pub fn greater_than<T: Debug>(rhs: T) -> Box<GreaterThan<T>> {
    box GreaterThan(rhs)
}

pub fn less_than<T: Debug>(rhs: T) -> Box<LessThan<T>> {
    box LessThan(rhs)
}

pub fn any_of<T: Debug>(rhs: Vec<Box<Matcher<T>>>) -> Box<AnyOf<T>> {
    box AnyOf(rhs)
}

pub fn all_of<T: Debug>(rhs: Vec<Box<Matcher<T>>>) -> Box<AllOf<T>> {
    box AllOf(rhs)
}

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

    #[test]
    fn test_expect_equality() {
        expect(1).to(equal(1));
    }

    #[test]
    #[should_panic(expected="expected 1 to equal 2")]
    fn test_expect_not_equality_to_fail() {
        expect(1).to(equal(2));
    }

    #[test]
    fn test_partial_eq_equality() {
        #[derive(PartialEq, Debug)]
        struct Foo { a: u16, b: String }

        expect(Foo{ a: 10u16, b: "Hello".to_string()})
            .to(equal(Foo{ a: 10u16, b: "Hello".to_string()}));
    }

    #[test]
    fn test_invert_equality() {
        expect(1).to(not(equal(2)));
    }

    #[test]
    fn test_invert_invert_equality() {
        expect(1).to(not(not(equal(1))));
    }

    #[test]
    #[should_panic(expected="not expected 1 to equal 1")]
    fn test_invert_equality_equal_to_fail() {
        expect(1).to(not(equal(1)));
    }

    #[test]
    fn test_empty() {
        let v: Vec<usize> = Vec::new();
        expect(v).is(empty());
    }

    #[test]
    fn test_not_empty() {
        let v = vec![1, 2, 3];
        expect(v).is(not(empty()));
    }

    #[test]
    #[should_panic(expected="expected [1, 2, 3] to be empty")]
    fn test_not_empty_vec_fails() {
        expect(vec![1, 2, 3]).is(empty());
    }

    #[test]
    fn test_empty_string() {
        expect("".to_string()).is(empty());
    }

    #[test]
    fn test_not_empty_string() {
        expect("not-empty".to_string()).is(not(empty()));
    }

    #[test]
    fn test_empty_str() {
        expect("").is(empty());
    }

    #[test]
    #[should_panic(expected="expected \"hey diddle diddle\" to be empty")]
    fn test_not_empty_str_fails() {
        expect("hey diddle diddle").is(empty())
    }

    #[test]
    fn test_not_empty_str() {
        expect("not-empty").is(not(empty()));
    }

    #[test]
    fn test_contains() {
        expect(vec![1, 2, 3]).to(contain(1));
    }

    #[test]
    fn test_not_contains() {
        expect(vec![1, 2, 3]).to(not(contain(10)));
    }

    #[test]
    #[should_panic(expected="expected [1, 2, 3] to contain 5")]
    fn test_not_contains_fails() {
        expect(vec![1, 2, 3]).to(contain(5));
    }

    #[test]
    fn test_contains_string_char() {
        expect("Hello, world!".to_string()).to(contain('H'));
    }

    #[test]
    fn test_not_contains_string_char() {
        expect("Hello, world!".to_string()).to(not(contain('Z')));
    }

    #[test]
    #[should_panic(expected="expected \"fe fi fo fum\" to contain 'z'")]
    fn test_not_contains_char_fails() {
        expect("fe fi fo fum".to_string()).to(contain('z'));
    }

    #[test]
    fn test_contains_string_substring() {
        expect("Hello, world!".to_string()).to(contain("Hello".to_string()));
    }

    #[test]
    fn test_not_contains_string_substring() {
        expect("Hello, world!".to_string()).to(not(contain("not-in-there".to_string())));
    }

    #[test]
    #[should_panic(expected="expected \"fe fi fo fum\" to contain \"substring\"")]
    fn test_not_contains_substring_fails() {
        expect("fe fi fo fum".to_string()).to(contain("substring".to_string()));
    }

    #[test]
    fn test_greater_than_int() {
        expect(5).is(greater_than(1));
    }

    #[test]
    fn test_not_greater_than_int() {
        expect(5).is(not(greater_than(10)));
    }

    #[test]
    #[should_panic(expected="expected 5 to be greater than 6")]
    fn test_not_greater_than_fails() {
        expect(5).is(greater_than(6));
    }

    #[test]
    fn test_less_than_int() {
        expect(5).is(less_than(10));
    }

    #[test]
    fn test_not_less_than_int() {
        expect(5).is(not(less_than(1)));
    }

    #[test]
    #[should_panic(expected="expected 10 to be less than 6")]
    fn test_not_less_than_fails() {
        expect(10).is(less_than(6));
    }

    #[test]
    fn test_any_of() {
        expect(5).is(any_of(vec![less_than(0),
                                 greater_than(1)]))
    }

    #[test]
    fn test_any_of_none() {
        expect(5).is(not(any_of(vec![less_than(0),
                                     greater_than(100)])))
    }

    #[test]
    fn test_all_of() {
        expect(5).is(all_of(vec![less_than(1000),
                                 greater_than(1)]))
    }

    #[test]
    fn test_not_all_of() {
        expect(5).is(not(all_of(vec![less_than(1000),
                                     greater_than(10)])))
    }
}
<commit_msg>Rename WithLen to Collection<commit_after>#![feature(box_syntax)]
#![feature(core)]
extern crate core;
use core::fmt::Debug;

pub struct Expectation<Lhs: Debug>(Lhs);

pub struct To<Lhs: Debug>(Lhs);

pub trait Matcher<Lhs> {
    fn matches(&self, rhs: &Lhs) -> bool;
    fn fail_msg(&self, rhs: &Lhs) -> String;
}

pub trait Collection {
    fn match_len(&self) -> usize;
}

impl<T> Collection for Vec<T> {
    fn match_len(&self) -> usize { self.len() }
}

impl Collection for String {
    fn match_len(&self) -> usize { self.chars().count() }
}

impl<'a> Collection for &'a str {
    fn match_len(&self) -> usize { self.chars().count() }
}

pub struct Contains<T>(T);

impl<T: Debug + PartialEq> Matcher<Vec<T>> for Contains<T> {
    fn matches(&self, lhs: &Vec<T>) -> bool {
        lhs.iter().any(|i| *i == self.0)
    }

    fn fail_msg(&self, lhs: &Vec<T>) -> String {
        format!("expected {:?} to contain {:?}", lhs, self.0)
    }
}

impl Matcher<String> for Contains<char> {
    fn matches(&self, lhs: &String) -> bool {
        lhs.chars().any(|i| i == self.0)
    }

    fn fail_msg(&self, lhs: &String) -> String {
        format!("expected {:?} to contain {:?}", lhs, self.0)
    }
}

impl Matcher<String> for Contains<String> {
    fn matches(&self, lhs: &String) -> bool {
        lhs.contains(&*self.0)
    }

    fn fail_msg(&self, lhs: &String) -> String {
        format!("expected {:?} to contain {:?}", lhs, self.0)
    }
}

pub struct Empty;

impl<Lhs: Debug + Collection> Matcher<Lhs> for Empty {
    fn matches(&self, rhs: &Lhs) -> bool {
        rhs.match_len() == 0
    }

    fn fail_msg(&self, rhs: &Lhs) -> String {
        format!("expected {:?} to be empty", rhs)
    }
}

pub struct LessThan<Lhs: Debug>(Lhs);

impl<Lhs: Debug + PartialOrd> Matcher<Lhs> for LessThan<Lhs> {
    fn matches(&self, lhs: &Lhs) -> bool {
        *lhs < self.0
    }

    fn fail_msg(&self, lhs: &Lhs) -> String {
        format!("expected {:?} to be less than {:?}", lhs, self.0)
    }
}

pub struct GreaterThan<Lhs: Debug>(Lhs);

impl<Lhs: Debug + PartialOrd> Matcher<Lhs> for GreaterThan<Lhs> {
    fn matches(&self, lhs: &Lhs) -> bool {
        *lhs > self.0
    }

    fn fail_msg(&self, lhs: &Lhs) -> String {
        format!("expected {:?} to be greater than {:?}", lhs, self.0)
    }
}

pub struct Equal<Lhs: Debug>(Lhs);

impl<Lhs: Debug + PartialEq> Matcher<Lhs> for Equal<Lhs> {
    fn matches(&self, rhs: &Lhs) -> bool {
        &self.0 == rhs
    }

    fn fail_msg(&self, rhs: &Lhs) -> String {
        format!("expected {:?} to equal {:?}", rhs, self.0)
    }
}

pub struct AllOf<A: Debug>(Vec<Box<Matcher<A>>>);

impl<Lhs: Debug> Matcher<Lhs> for AllOf<Lhs> {
    fn matches(&self, lhs: &Lhs) -> bool {
        self.0.iter().all(|bm| bm.matches(lhs))
    }

    fn fail_msg(&self, lhs: &Lhs) -> String {
        format!("expected all of {:?}",
                self.0.iter().map(|m| m.fail_msg(lhs)).collect::<Vec<String>>())
    }
}

pub struct AnyOf<A: Debug>(Vec<Box<Matcher<A>>>);

impl<Lhs: Debug> Matcher<Lhs> for AnyOf<Lhs> {
    fn matches(&self, lhs: &Lhs) -> bool {
        self.0.iter().any(|bm| bm.matches(lhs))
    }

    fn fail_msg(&self, lhs: &Lhs) -> String {
        format!("expected one of {:?}",
                self.0.iter().map(|m| m.fail_msg(lhs)).collect::<Vec<String>>())
    }
}

pub struct Not<A>(Box<Matcher<A>>);

impl<Lhs: Debug> Matcher<Lhs> for Not<Lhs> {
    fn matches(&self, rhs: &Lhs) -> bool {
        !self.0.matches(rhs)
    }

    fn fail_msg(&self, rhs: &Lhs) -> String {
        format!("not {}", self.0.fail_msg(rhs))
    }
}

impl<Lhs: Debug> Expectation<Lhs> {
    pub fn is<T>(&self, matcher: Box<T>) where T: Matcher<Lhs> {
        self.to(matcher)
    }

    pub fn to<T>(&self, matcher: Box<T>) where T: Matcher<Lhs> {
        if !matcher.matches(&self.0) {
            panic!(matcher.fail_msg(&self.0))
        }
    }
}

pub fn expect<T: Debug>(lhs: T) -> Expectation<T> {
    Expectation(lhs)
}

pub fn equal<T: Debug>(rhs: T) -> Box<Equal<T>> {
    box Equal(rhs)
}

pub fn not<T: Debug>(rhs: Box<Matcher<T>>) -> Box<Not<T>> {
    box Not(rhs)
}

pub fn empty() -> Box<Empty> {
    box Empty
}

pub fn contain<T: Debug>(rhs: T) -> Box<Contains<T>> {
    box Contains(rhs)
}

pub fn greater_than<T: Debug>(rhs: T) -> Box<GreaterThan<T>> {
    box GreaterThan(rhs)
}

pub fn less_than<T: Debug>(rhs: T) -> Box<LessThan<T>> {
    box LessThan(rhs)
}

pub fn any_of<T: Debug>(rhs: Vec<Box<Matcher<T>>>) -> Box<AnyOf<T>> {
    box AnyOf(rhs)
}

pub fn all_of<T: Debug>(rhs: Vec<Box<Matcher<T>>>) -> Box<AllOf<T>> {
    box AllOf(rhs)
}

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

    #[test]
    fn test_expect_equality() {
        expect(1).to(equal(1));
    }

    #[test]
    #[should_panic(expected="expected 1 to equal 2")]
    fn test_expect_not_equality_to_fail() {
        expect(1).to(equal(2));
    }

    #[test]
    fn test_partial_eq_equality() {
        #[derive(PartialEq, Debug)]
        struct Foo { a: u16, b: String }

        expect(Foo{ a: 10u16, b: "Hello".to_string()})
            .to(equal(Foo{ a: 10u16, b: "Hello".to_string()}));
    }

    #[test]
    fn test_invert_equality() {
        expect(1).to(not(equal(2)));
    }

    #[test]
    fn test_invert_invert_equality() {
        expect(1).to(not(not(equal(1))));
    }

    #[test]
    #[should_panic(expected="not expected 1 to equal 1")]
    fn test_invert_equality_equal_to_fail() {
        expect(1).to(not(equal(1)));
    }

    #[test]
    fn test_empty() {
        let v: Vec<usize> = Vec::new();
        expect(v).is(empty());
    }

    #[test]
    fn test_not_empty() {
        let v = vec![1, 2, 3];
        expect(v).is(not(empty()));
    }

    #[test]
    #[should_panic(expected="expected [1, 2, 3] to be empty")]
    fn test_not_empty_vec_fails() {
        expect(vec![1, 2, 3]).is(empty());
    }

    #[test]
    fn test_empty_string() {
        expect("".to_string()).is(empty());
    }

    #[test]
    fn test_not_empty_string() {
        expect("not-empty".to_string()).is(not(empty()));
    }

    #[test]
    fn test_empty_str() {
        expect("").is(empty());
    }

    #[test]
    #[should_panic(expected="expected \"hey diddle diddle\" to be empty")]
    fn test_not_empty_str_fails() {
        expect("hey diddle diddle").is(empty())
    }

    #[test]
    fn test_not_empty_str() {
        expect("not-empty").is(not(empty()));
    }

    #[test]
    fn test_contains() {
        expect(vec![1, 2, 3]).to(contain(1));
    }

    #[test]
    fn test_not_contains() {
        expect(vec![1, 2, 3]).to(not(contain(10)));
    }

    #[test]
    #[should_panic(expected="expected [1, 2, 3] to contain 5")]
    fn test_not_contains_fails() {
        expect(vec![1, 2, 3]).to(contain(5));
    }

    #[test]
    fn test_contains_string_char() {
        expect("Hello, world!".to_string()).to(contain('H'));
    }

    #[test]
    fn test_not_contains_string_char() {
        expect("Hello, world!".to_string()).to(not(contain('Z')));
    }

    #[test]
    #[should_panic(expected="expected \"fe fi fo fum\" to contain 'z'")]
    fn test_not_contains_char_fails() {
        expect("fe fi fo fum".to_string()).to(contain('z'));
    }

    #[test]
    fn test_contains_string_substring() {
        expect("Hello, world!".to_string()).to(contain("Hello".to_string()));
    }

    #[test]
    fn test_not_contains_string_substring() {
        expect("Hello, world!".to_string()).to(not(contain("not-in-there".to_string())));
    }

    #[test]
    #[should_panic(expected="expected \"fe fi fo fum\" to contain \"substring\"")]
    fn test_not_contains_substring_fails() {
        expect("fe fi fo fum".to_string()).to(contain("substring".to_string()));
    }

    #[test]
    fn test_greater_than_int() {
        expect(5).is(greater_than(1));
    }

    #[test]
    fn test_not_greater_than_int() {
        expect(5).is(not(greater_than(10)));
    }

    #[test]
    #[should_panic(expected="expected 5 to be greater than 6")]
    fn test_not_greater_than_fails() {
        expect(5).is(greater_than(6));
    }

    #[test]
    fn test_less_than_int() {
        expect(5).is(less_than(10));
    }

    #[test]
    fn test_not_less_than_int() {
        expect(5).is(not(less_than(1)));
    }

    #[test]
    #[should_panic(expected="expected 10 to be less than 6")]
    fn test_not_less_than_fails() {
        expect(10).is(less_than(6));
    }

    #[test]
    fn test_any_of() {
        expect(5).is(any_of(vec![less_than(0),
                                 greater_than(1)]))
    }

    #[test]
    fn test_any_of_none() {
        expect(5).is(not(any_of(vec![less_than(0),
                                     greater_than(100)])))
    }

    #[test]
    fn test_all_of() {
        expect(5).is(all_of(vec![less_than(1000),
                                 greater_than(1)]))
    }

    #[test]
    fn test_not_all_of() {
        expect(5).is(not(all_of(vec![less_than(1000),
                                     greater_than(10)])))
    }
}
<|endoftext|>


<commit_before>// compile-flags: -Zunleash-the-miri-inside-of-you

#![feature(core_intrinsics, rustc_attrs, const_raw_ptr_deref)]

use std::cell::UnsafeCell;
use std::intrinsics::rustc_peek;

#[repr(C)]
struct PartialInteriorMut {
    zst: [i32; 0],
    cell: UnsafeCell<i32>,
}

#[rustc_mir(rustc_peek_indirectly_mutable,stop_after_dataflow)]
#[rustc_mir(borrowck_graphviz_postflow="indirect.dot")]
const BOO: i32 = {
    let x = PartialInteriorMut {
        zst: [],
        cell: UnsafeCell::new(0),
    };

    let p_zst: *const _ = &x.zst ; // Doesn't cause `x` to get marked as indirectly mutable.

    let rmut_cell = unsafe {
        // Take advantage of the fact that `zst` and `cell` are at the same location in memory.
        // This trick would work with any size type if miri implemented `ptr::offset`.
        let p_cell = p_zst as *const UnsafeCell<i32>;

        let pmut_cell = (*p_cell).get();
        &mut *pmut_cell
    };

    *rmut_cell = 42;  // Mutates `x` indirectly even though `x` is not marked indirectly mutable!!!
    let val = *rmut_cell;
    unsafe { rustc_peek(x) }; //~ ERROR rustc_peek: bit not set

    val
};

fn main() {
    println!("{}", BOO);
}
<commit_msg>Remove `borrowck_graphviz_postflow` from test<commit_after>// compile-flags: -Zunleash-the-miri-inside-of-you

#![feature(core_intrinsics, rustc_attrs, const_raw_ptr_deref)]

use std::cell::UnsafeCell;
use std::intrinsics::rustc_peek;

#[repr(C)]
struct PartialInteriorMut {
    zst: [i32; 0],
    cell: UnsafeCell<i32>,
}

#[rustc_mir(rustc_peek_indirectly_mutable,stop_after_dataflow)]
const BOO: i32 = {
    let x = PartialInteriorMut {
        zst: [],
        cell: UnsafeCell::new(0),
    };

    let p_zst: *const _ = &x.zst ; // Doesn't cause `x` to get marked as indirectly mutable.

    let rmut_cell = unsafe {
        // Take advantage of the fact that `zst` and `cell` are at the same location in memory.
        // This trick would work with any size type if miri implemented `ptr::offset`.
        let p_cell = p_zst as *const UnsafeCell<i32>;

        let pmut_cell = (*p_cell).get();
        &mut *pmut_cell
    };

    *rmut_cell = 42;  // Mutates `x` indirectly even though `x` is not marked indirectly mutable!!!
    let val = *rmut_cell;
    unsafe { rustc_peek(x) }; //~ ERROR rustc_peek: bit not set

    val
};

fn main() {
    println!("{}", BOO);
}
<|endoftext|>