<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! DOM bindings for `CharacterData`.

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
use dom::bindings::codegen::InheritTypes::{CharacterDataDerived, ElementCast};
use dom::bindings::codegen::InheritTypes::NodeCast;
use dom::bindings::error::{Fallible, ErrorResult};
use dom::bindings::error::Error::IndexSize;
use dom::bindings::js::{JSRef, Temporary};
use dom::document::Document;
use dom::element::Element;
use dom::eventtarget::{EventTarget, EventTargetTypeId};
use dom::node::{Node, NodeHelpers, NodeTypeId};

use util::str::DOMString;

use std::borrow::ToOwned;
use std::cell::Ref;

#[dom_struct]
pub struct CharacterData {
    node: Node,
    data: DOMRefCell<DOMString>,
}

impl CharacterDataDerived for EventTarget {
    fn is_characterdata(&self) -> bool {
        match *self.type_id() {
            EventTargetTypeId::Node(NodeTypeId::Text) |
            EventTargetTypeId::Node(NodeTypeId::Comment) |
            EventTargetTypeId::Node(NodeTypeId::ProcessingInstruction) => true,
            _ => false
        }
    }
}

impl CharacterData {
    pub fn new_inherited(id: NodeTypeId, data: DOMString, document: JSRef<Document>) -> CharacterData {
        CharacterData {
            node: Node::new_inherited(id, document),
            data: DOMRefCell::new(data),
        }
    }

    #[inline]
    pub fn node<'a>(&'a self) -> &'a Node {
        &self.node
    }

    #[inline]
    pub fn data(&self) -> Ref<DOMString> {
        self.data.borrow()
    }

    #[inline]
    pub fn set_data(&self, data: DOMString) {
        *self.data.borrow_mut() = data;
    }

    #[inline]
    #[allow(unsafe_code)]
    pub unsafe fn data_for_layout<'a>(&'a self) -> &'a str {
        self.data.borrow_for_layout().as_slice()
    }

}

impl<'a> CharacterDataMethods for JSRef<'a, CharacterData> {
    fn Data(self) -> DOMString {
        // FIXME(https://github.com/rust-lang/rust/issues/23338)
        let data = self.data.borrow();
        data.clone()
    }

    fn SetData(self, arg: DOMString) -> ErrorResult {
        *self.data.borrow_mut() = arg;
        Ok(())
    }

    fn Length(self) -> u32 {
        // FIXME(https://github.com/rust-lang/rust/issues/23338)
        let data = self.data.borrow();
        data.chars().count() as u32
    }

    fn SubstringData(self, offset: u32, count: u32) -> Fallible<DOMString> {
        // FIXME(https://github.com/rust-lang/rust/issues/23338)
        let data = self.data.borrow();
        Ok(data.slice_chars(offset as usize, (offset + count) as usize).to_owned())
    }

    fn AppendData(self, arg: DOMString) -> ErrorResult {
        self.data.borrow_mut().push_str(arg.as_slice());
        Ok(())
    }

    fn InsertData(self, offset: u32, arg: DOMString) -> ErrorResult {
        self.ReplaceData(offset, 0, arg)
    }

    fn DeleteData(self, offset: u32, count: u32) -> ErrorResult {
        self.ReplaceData(offset, count, "".to_owned())
    }

    fn ReplaceData(self, offset: u32, count: u32, arg: DOMString) -> ErrorResult {
        let length = self.data.borrow().chars().count() as u32;
        if offset > length {
            return Err(IndexSize);
        }
        let count = if offset + count > length {
            length - offset
        } else {
            count
        };
        let mut data = self.data.borrow().slice_chars(0, offset as usize).to_owned();
        data.push_str(arg.as_slice());
        data.push_str(&self.data.borrow().slice_chars((offset + count) as usize, length as usize));
        *self.data.borrow_mut() = data;
        // FIXME: Once we have `Range`, we should implement step7 to step11
        Ok(())
    }

    // http://dom.spec.whatwg.org/#dom-childnode-remove
    fn Remove(self) {
        let node: JSRef<Node> = NodeCast::from_ref(self);
        node.remove_self();
    }

    // https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-previouselementsibling
    fn GetPreviousElementSibling(self) -> Option<Temporary<Element>> {
        NodeCast::from_ref(self).preceding_siblings()
                                .filter_map(ElementCast::to_temporary).next()
    }

    // https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-nextelementsibling
    fn GetNextElementSibling(self) -> Option<Temporary<Element>> {
        NodeCast::from_ref(self).following_siblings()
                                .filter_map(ElementCast::to_temporary).next()
    }
}

<commit_msg>Add links to CharacterData's spec<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! DOM bindings for `CharacterData`.

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
use dom::bindings::codegen::InheritTypes::{CharacterDataDerived, ElementCast};
use dom::bindings::codegen::InheritTypes::NodeCast;
use dom::bindings::error::{Fallible, ErrorResult};
use dom::bindings::error::Error::IndexSize;
use dom::bindings::js::{JSRef, Temporary};
use dom::document::Document;
use dom::element::Element;
use dom::eventtarget::{EventTarget, EventTargetTypeId};
use dom::node::{Node, NodeHelpers, NodeTypeId};

use util::str::DOMString;

use std::borrow::ToOwned;
use std::cell::Ref;

#[dom_struct]
pub struct CharacterData {
    node: Node,
    data: DOMRefCell<DOMString>,
}

impl CharacterDataDerived for EventTarget {
    fn is_characterdata(&self) -> bool {
        match *self.type_id() {
            EventTargetTypeId::Node(NodeTypeId::Text) |
            EventTargetTypeId::Node(NodeTypeId::Comment) |
            EventTargetTypeId::Node(NodeTypeId::ProcessingInstruction) => true,
            _ => false
        }
    }
}

impl CharacterData {
    pub fn new_inherited(id: NodeTypeId, data: DOMString, document: JSRef<Document>) -> CharacterData {
        CharacterData {
            node: Node::new_inherited(id, document),
            data: DOMRefCell::new(data),
        }
    }

    #[inline]
    pub fn node<'a>(&'a self) -> &'a Node {
        &self.node
    }

    #[inline]
    pub fn data(&self) -> Ref<DOMString> {
        self.data.borrow()
    }

    #[inline]
    pub fn set_data(&self, data: DOMString) {
        *self.data.borrow_mut() = data;
    }

    #[inline]
    #[allow(unsafe_code)]
    pub unsafe fn data_for_layout<'a>(&'a self) -> &'a str {
        self.data.borrow_for_layout().as_slice()
    }

}

impl<'a> CharacterDataMethods for JSRef<'a, CharacterData> {
    // https://dom.spec.whatwg.org/#dom-characterdata-data
    fn Data(self) -> DOMString {
        // FIXME(https://github.com/rust-lang/rust/issues/23338)
        let data = self.data.borrow();
        data.clone()
    }

    // https://dom.spec.whatwg.org/#dom-characterdata-data
    fn SetData(self, arg: DOMString) -> ErrorResult {
        *self.data.borrow_mut() = arg;
        Ok(())
    }

    // https://dom.spec.whatwg.org/#dom-characterdata-length
    fn Length(self) -> u32 {
        // FIXME(https://github.com/rust-lang/rust/issues/23338)
        let data = self.data.borrow();
        data.chars().count() as u32
    }

    // https://dom.spec.whatwg.org/#dom-characterdata-substringdata
    fn SubstringData(self, offset: u32, count: u32) -> Fallible<DOMString> {
        // FIXME(https://github.com/rust-lang/rust/issues/23338)
        let data = self.data.borrow();
        Ok(data.slice_chars(offset as usize, (offset + count) as usize).to_owned())
    }

    // https://dom.spec.whatwg.org/#dom-characterdata-appenddata
    fn AppendData(self, arg: DOMString) -> ErrorResult {
        self.data.borrow_mut().push_str(arg.as_slice());
        Ok(())
    }

    // https://dom.spec.whatwg.org/#dom-characterdata-insertdata
    fn InsertData(self, offset: u32, arg: DOMString) -> ErrorResult {
        self.ReplaceData(offset, 0, arg)
    }

    // https://dom.spec.whatwg.org/#dom-characterdata-deletedata
    fn DeleteData(self, offset: u32, count: u32) -> ErrorResult {
        self.ReplaceData(offset, count, "".to_owned())
    }

    // https://dom.spec.whatwg.org/#dom-characterdata-replacedata
    fn ReplaceData(self, offset: u32, count: u32, arg: DOMString) -> ErrorResult {
        let length = self.data.borrow().chars().count() as u32;
        if offset > length {
            return Err(IndexSize);
        }
        let count = if offset + count > length {
            length - offset
        } else {
            count
        };
        let mut data = self.data.borrow().slice_chars(0, offset as usize).to_owned();
        data.push_str(arg.as_slice());
        data.push_str(&self.data.borrow().slice_chars((offset + count) as usize, length as usize));
        *self.data.borrow_mut() = data;
        // FIXME: Once we have `Range`, we should implement step7 to step11
        Ok(())
    }

    // http://dom.spec.whatwg.org/#dom-childnode-remove
    fn Remove(self) {
        let node: JSRef<Node> = NodeCast::from_ref(self);
        node.remove_self();
    }

    // https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-previouselementsibling
    fn GetPreviousElementSibling(self) -> Option<Temporary<Element>> {
        NodeCast::from_ref(self).preceding_siblings()
                                .filter_map(ElementCast::to_temporary).next()
    }

    // https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-nextelementsibling
    fn GetNextElementSibling(self) -> Option<Temporary<Element>> {
        NodeCast::from_ref(self).following_siblings()
                                .filter_map(ElementCast::to_temporary).next()
    }
}

<|endoftext|>


<commit_before>use bson::{Bson, Document};
use mongodb::client::coll::options::WriteModel;
use mongodb::client::MongoClient;

#[test]
fn bulk_ordered_insert_only() {
    let client = MongoClient::new("localhost", 27017).unwrap();
    let db = client.db("test");
    let coll = db.collection("bulk_ordered_insert_only");

    coll.drop().unwrap();

    let models = (1..5).map(|i| WriteModel::InsertOne { document: doc! {
        "_id" => (i),
        "x" => (i * 11)
    }}).collect();

    coll.bulk_write(models, true);

    let cursor : Vec<_> = coll.find(None, None).unwrap().collect();

    assert_eq!(cursor.len(), 4);

    for (i, result) in cursor.into_iter().enumerate() {
        let doc = result.unwrap();
        let i = i + 1;

        match doc.get("_id") {
            Some(&Bson::I32(j)) => assert_eq!(i as i32, j),
            _ => panic!("Invalid id: {:?}", doc)
        }

        match doc.get("x") {
            Some(&Bson::I32(j)) => assert_eq!(11 * i as i32, j),
            _ => panic!("Invalid id: {:?}", doc)
        }
    }
}

#[test]
fn bulk_unordered_insert_only() {
    let client = MongoClient::new("localhost", 27017).unwrap();
    let db = client.db("test");
    let coll = db.collection("bulk_unordered_insert_only");

    coll.drop().unwrap();

    let models = (1..5).map(|i| WriteModel::InsertOne { document: doc! {
        "_id" => (i),
        "x" => (i * 11)
    }}).collect();

    coll.bulk_write(models, false);

    let cursor : Vec<_> = coll.find(None, None).unwrap().collect();

    assert_eq!(cursor.len(), 4);

    for (i, result) in cursor.into_iter().enumerate() {
        let doc = result.unwrap();
        let i = i + 1;

        match doc.get("_id") {
            Some(&Bson::I32(j)) => assert_eq!(i as i32, j),
            _ => panic!("Invalid id: {:?}", doc)
        }

        match doc.get("x") {
            Some(&Bson::I32(j)) => assert_eq!(11 * i as i32, j),
            _ => panic!("Invalid id: {:?}", doc)
        }
    }
}
<commit_msg>changed variable name to be more descriptive<commit_after>use bson::{Bson, Document};
use mongodb::client::coll::options::WriteModel;
use mongodb::client::MongoClient;

#[test]
fn bulk_ordered_insert_only() {
    let client = MongoClient::new("localhost", 27017).unwrap();
    let db = client.db("test");
    let coll = db.collection("bulk_ordered_insert_only");

    coll.drop().unwrap();

    let models = (1..5).map(|i| WriteModel::InsertOne { document: doc! {
        "_id" => (i),
        "x" => (i * 11)
    }}).collect();

    coll.bulk_write(models, true);

    let cursor : Vec<_> = coll.find(None, None).unwrap().collect();

    assert_eq!(cursor.len(), 4);

    for (i, result) in cursor.into_iter().enumerate() {
        let doc = result.unwrap();
        let expected_id = i + 1;

        match doc.get("_id") {
            Some(&Bson::I32(j)) => assert_eq!(expected_id as i32, j),
            _ => panic!("Invalid id: {:?}", doc)
        }

        match doc.get("x") {
            Some(&Bson::I32(j)) => assert_eq!(11 * expected_id as i32, j),
            _ => panic!("Invalid id: {:?}", doc)
        }
    }
}

#[test]
fn bulk_unordered_insert_only() {
    let client = MongoClient::new("localhost", 27017).unwrap();
    let db = client.db("test");
    let coll = db.collection("bulk_unordered_insert_only");

    coll.drop().unwrap();

    let models = (1..5).map(|i| WriteModel::InsertOne { document: doc! {
        "_id" => (i),
        "x" => (i * 11)
    }}).collect();

    coll.bulk_write(models, false);

    let cursor : Vec<_> = coll.find(None, None).unwrap().collect();

    assert_eq!(cursor.len(), 4);

    for (i, result) in cursor.into_iter().enumerate() {
        let doc = result.unwrap();
        let expected_id = i + 1;

        match doc.get("_id") {
            Some(&Bson::I32(j)) => assert_eq!(expected_id as i32, j),
            _ => panic!("Invalid id: {:?}", doc)
        }

        match doc.get("x") {
            Some(&Bson::I32(j)) => assert_eq!(11 * expected_id as i32, j),
            _ => panic!("Invalid id: {:?}", doc)
        }
    }
}
<|endoftext|>


<commit_before>extern crate tokio_io;
extern crate bytes;
extern crate futures;

use tokio_io::AsyncRead;
use tokio_io::codec::{FramedRead, Decoder};

use bytes::{BytesMut, Buf, IntoBuf, BigEndian};
use futures::Stream;
use futures::Async::{Ready, NotReady};

use std::io::{self, Read};
use std::collections::VecDeque;

macro_rules! mock {
    ($($x:expr,)*) => {{
        let mut v = VecDeque::new();
        v.extend(vec![$($x),*]);
        Mock { calls: v }
    }};
}

struct U32Decoder;

impl Decoder for U32Decoder {
    type Item = u32;

    fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<u32>> {
        if buf.len() < 4 {
            return Ok(None);
        }

        let n = buf.split_to(4).into_buf().get_u32::<BigEndian>();
        Ok(Some(n))
    }
}

#[test]
fn read_multi_frame_in_packet() {
    let mock = mock! {
        Ok(b"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02".to_vec()),
    };

    let mut framed = FramedRead::new(mock, U32Decoder);
    assert_eq!(Ready(Some(0)), framed.poll().unwrap());
    assert_eq!(Ready(Some(1)), framed.poll().unwrap());
    assert_eq!(Ready(Some(2)), framed.poll().unwrap());
    assert_eq!(Ready(None), framed.poll().unwrap());
}

#[test]
fn read_multi_frame_across_packets() {
    let mock = mock! {
        Ok(b"\x00\x00\x00\x00".to_vec()),
        Ok(b"\x00\x00\x00\x01".to_vec()),
        Ok(b"\x00\x00\x00\x02".to_vec()),
    };

    let mut framed = FramedRead::new(mock, U32Decoder);
    assert_eq!(Ready(Some(0)), framed.poll().unwrap());
    assert_eq!(Ready(Some(1)), framed.poll().unwrap());
    assert_eq!(Ready(Some(2)), framed.poll().unwrap());
    assert_eq!(Ready(None), framed.poll().unwrap());
}

#[test]
fn read_not_ready() {
    let mock = mock! {
        Err(io::Error::new(io::ErrorKind::WouldBlock, "")),
        Ok(b"\x00\x00\x00\x00".to_vec()),
        Ok(b"\x00\x00\x00\x01".to_vec()),
    };

    let mut framed = FramedRead::new(mock, U32Decoder);
    assert_eq!(NotReady, framed.poll().unwrap());
    assert_eq!(Ready(Some(0)), framed.poll().unwrap());
    assert_eq!(Ready(Some(1)), framed.poll().unwrap());
    assert_eq!(Ready(None), framed.poll().unwrap());
}

#[test]
fn read_partial_then_not_ready() {
    let mock = mock! {
        Ok(b"\x00\x00".to_vec()),
        Err(io::Error::new(io::ErrorKind::WouldBlock, "")),
        Ok(b"\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02".to_vec()),
    };

    let mut framed = FramedRead::new(mock, U32Decoder);
    assert_eq!(NotReady, framed.poll().unwrap());
    assert_eq!(Ready(Some(0)), framed.poll().unwrap());
    assert_eq!(Ready(Some(1)), framed.poll().unwrap());
    assert_eq!(Ready(Some(2)), framed.poll().unwrap());
    assert_eq!(Ready(None), framed.poll().unwrap());
}

#[test]
fn read_err() {
    let mock = mock! {
        Err(io::Error::new(io::ErrorKind::Other, "")),
    };

    let mut framed = FramedRead::new(mock, U32Decoder);
    assert_eq!(io::ErrorKind::Other, framed.poll().unwrap_err().kind());
}

#[test]
fn read_partial_then_err() {
    let mock = mock! {
        Ok(b"\x00\x00".to_vec()),
        Err(io::Error::new(io::ErrorKind::Other, "")),
    };

    let mut framed = FramedRead::new(mock, U32Decoder);
    assert_eq!(io::ErrorKind::Other, framed.poll().unwrap_err().kind());
}

#[test]
fn read_partial_would_block_then_err() {
    let mock = mock! {
        Ok(b"\x00\x00".to_vec()),
        Err(io::Error::new(io::ErrorKind::WouldBlock, "")),
        Err(io::Error::new(io::ErrorKind::Other, "")),
    };

    let mut framed = FramedRead::new(mock, U32Decoder);
    assert_eq!(NotReady, framed.poll().unwrap());
    assert_eq!(io::ErrorKind::Other, framed.poll().unwrap_err().kind());
}

#[test]
fn huge_size() {
    let data = [0; 32 * 1024];

    let mut framed = FramedRead::new(&data[..], BigDecoder);
    assert_eq!(Ready(Some(0)), framed.poll().unwrap());
    assert_eq!(Ready(None), framed.poll().unwrap());

    struct BigDecoder;

    impl Decoder for BigDecoder {
        type Item = u32;

        fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<u32>> {
            if buf.len() < 32 * 1024 {
                return Ok(None);
            }
            buf.split_to(32 * 1024);
            Ok(Some(0))
        }
    }
}

#[test]
fn data_remaining_is_error() {
    let data = [0; 5];

    let mut framed = FramedRead::new(&data[..], U32Decoder);
    assert_eq!(Ready(Some(0)), framed.poll().unwrap());
    assert!(framed.poll().is_err());
}

#[test]
fn multi_frames_on_eof() {
    struct MyDecoder(Vec<u32>);

    impl Decoder for MyDecoder {
        type Item = u32;

        fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<u32>> {
            unreachable!();
        }

        fn decode_eof(&mut self, buf: &mut BytesMut) -> io::Result<Option<u32>> {
            if self.0.is_empty() {
                return Ok(None);
            }

            Ok(Some(self.0.remove(0)))
        }
    }

    let mut framed = FramedRead::new(mock!(), MyDecoder(vec![0, 1, 2, 3]));
    assert_eq!(Ready(Some(0)), framed.poll().unwrap());
    assert_eq!(Ready(Some(1)), framed.poll().unwrap());
    assert_eq!(Ready(Some(2)), framed.poll().unwrap());
    assert_eq!(Ready(Some(3)), framed.poll().unwrap());
    assert_eq!(Ready(None), framed.poll().unwrap());
}

// ===== Mock ======

struct Mock {
    calls: VecDeque<io::Result<Vec<u8>>>,
}

impl Read for Mock {
    fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
        match self.calls.pop_front() {
            Some(Ok(data)) => {
                debug_assert!(dst.len() >= data.len());
                dst[..data.len()].copy_from_slice(&data[..]);
                Ok(data.len())
            }
            Some(Err(e)) => Err(e),
            None => Ok(0),
        }
    }
}

impl AsyncRead for Mock {
}
<commit_msg>Fix compile warnings<commit_after>extern crate tokio_io;
extern crate bytes;
extern crate futures;

use tokio_io::AsyncRead;
use tokio_io::codec::{FramedRead, Decoder};

use bytes::{BytesMut, Buf, IntoBuf, BigEndian};
use futures::Stream;
use futures::Async::{Ready, NotReady};

use std::io::{self, Read};
use std::collections::VecDeque;

macro_rules! mock {
    ($($x:expr,)*) => {{
        let mut v = VecDeque::new();
        v.extend(vec![$($x),*]);
        Mock { calls: v }
    }};
}

struct U32Decoder;

impl Decoder for U32Decoder {
    type Item = u32;

    fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<u32>> {
        if buf.len() < 4 {
            return Ok(None);
        }

        let n = buf.split_to(4).into_buf().get_u32::<BigEndian>();
        Ok(Some(n))
    }
}

#[test]
fn read_multi_frame_in_packet() {
    let mock = mock! {
        Ok(b"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02".to_vec()),
    };

    let mut framed = FramedRead::new(mock, U32Decoder);
    assert_eq!(Ready(Some(0)), framed.poll().unwrap());
    assert_eq!(Ready(Some(1)), framed.poll().unwrap());
    assert_eq!(Ready(Some(2)), framed.poll().unwrap());
    assert_eq!(Ready(None), framed.poll().unwrap());
}

#[test]
fn read_multi_frame_across_packets() {
    let mock = mock! {
        Ok(b"\x00\x00\x00\x00".to_vec()),
        Ok(b"\x00\x00\x00\x01".to_vec()),
        Ok(b"\x00\x00\x00\x02".to_vec()),
    };

    let mut framed = FramedRead::new(mock, U32Decoder);
    assert_eq!(Ready(Some(0)), framed.poll().unwrap());
    assert_eq!(Ready(Some(1)), framed.poll().unwrap());
    assert_eq!(Ready(Some(2)), framed.poll().unwrap());
    assert_eq!(Ready(None), framed.poll().unwrap());
}

#[test]
fn read_not_ready() {
    let mock = mock! {
        Err(io::Error::new(io::ErrorKind::WouldBlock, "")),
        Ok(b"\x00\x00\x00\x00".to_vec()),
        Ok(b"\x00\x00\x00\x01".to_vec()),
    };

    let mut framed = FramedRead::new(mock, U32Decoder);
    assert_eq!(NotReady, framed.poll().unwrap());
    assert_eq!(Ready(Some(0)), framed.poll().unwrap());
    assert_eq!(Ready(Some(1)), framed.poll().unwrap());
    assert_eq!(Ready(None), framed.poll().unwrap());
}

#[test]
fn read_partial_then_not_ready() {
    let mock = mock! {
        Ok(b"\x00\x00".to_vec()),
        Err(io::Error::new(io::ErrorKind::WouldBlock, "")),
        Ok(b"\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02".to_vec()),
    };

    let mut framed = FramedRead::new(mock, U32Decoder);
    assert_eq!(NotReady, framed.poll().unwrap());
    assert_eq!(Ready(Some(0)), framed.poll().unwrap());
    assert_eq!(Ready(Some(1)), framed.poll().unwrap());
    assert_eq!(Ready(Some(2)), framed.poll().unwrap());
    assert_eq!(Ready(None), framed.poll().unwrap());
}

#[test]
fn read_err() {
    let mock = mock! {
        Err(io::Error::new(io::ErrorKind::Other, "")),
    };

    let mut framed = FramedRead::new(mock, U32Decoder);
    assert_eq!(io::ErrorKind::Other, framed.poll().unwrap_err().kind());
}

#[test]
fn read_partial_then_err() {
    let mock = mock! {
        Ok(b"\x00\x00".to_vec()),
        Err(io::Error::new(io::ErrorKind::Other, "")),
    };

    let mut framed = FramedRead::new(mock, U32Decoder);
    assert_eq!(io::ErrorKind::Other, framed.poll().unwrap_err().kind());
}

#[test]
fn read_partial_would_block_then_err() {
    let mock = mock! {
        Ok(b"\x00\x00".to_vec()),
        Err(io::Error::new(io::ErrorKind::WouldBlock, "")),
        Err(io::Error::new(io::ErrorKind::Other, "")),
    };

    let mut framed = FramedRead::new(mock, U32Decoder);
    assert_eq!(NotReady, framed.poll().unwrap());
    assert_eq!(io::ErrorKind::Other, framed.poll().unwrap_err().kind());
}

#[test]
fn huge_size() {
    let data = [0; 32 * 1024];

    let mut framed = FramedRead::new(&data[..], BigDecoder);
    assert_eq!(Ready(Some(0)), framed.poll().unwrap());
    assert_eq!(Ready(None), framed.poll().unwrap());

    struct BigDecoder;

    impl Decoder for BigDecoder {
        type Item = u32;

        fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<u32>> {
            if buf.len() < 32 * 1024 {
                return Ok(None);
            }
            buf.split_to(32 * 1024);
            Ok(Some(0))
        }
    }
}

#[test]
fn data_remaining_is_error() {
    let data = [0; 5];

    let mut framed = FramedRead::new(&data[..], U32Decoder);
    assert_eq!(Ready(Some(0)), framed.poll().unwrap());
    assert!(framed.poll().is_err());
}

#[test]
fn multi_frames_on_eof() {
    struct MyDecoder(Vec<u32>);

    impl Decoder for MyDecoder {
        type Item = u32;

        fn decode(&mut self, _buf: &mut BytesMut) -> io::Result<Option<u32>> {
            unreachable!();
        }

        fn decode_eof(&mut self, _buf: &mut BytesMut) -> io::Result<Option<u32>> {
            if self.0.is_empty() {
                return Ok(None);
            }

            Ok(Some(self.0.remove(0)))
        }
    }

    let mut framed = FramedRead::new(mock!(), MyDecoder(vec![0, 1, 2, 3]));
    assert_eq!(Ready(Some(0)), framed.poll().unwrap());
    assert_eq!(Ready(Some(1)), framed.poll().unwrap());
    assert_eq!(Ready(Some(2)), framed.poll().unwrap());
    assert_eq!(Ready(Some(3)), framed.poll().unwrap());
    assert_eq!(Ready(None), framed.poll().unwrap());
}

// ===== Mock ======

struct Mock {
    calls: VecDeque<io::Result<Vec<u8>>>,
}

impl Read for Mock {
    fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
        match self.calls.pop_front() {
            Some(Ok(data)) => {
                debug_assert!(dst.len() >= data.len());
                dst[..data.len()].copy_from_slice(&data[..]);
                Ok(data.len())
            }
            Some(Err(e)) => Err(e),
            None => Ok(0),
        }
    }
}

impl AsyncRead for Mock {
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::env;
use std::io::{self, BufRead, BufReader, Write};
use std::str;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TryRecvError};

use jsonrpc_core::request::{Call, MethodCall, Notification};
use jsonrpc_core::version::Version;
use jsonrpc_core::params::Params;
use jsonrpc_core::response::{Output, Response};
use jsonrpc_core::id::Id;

use serde::Serialize;
use serde::de::DeserializeOwned;
use serde_json::ser::Serializer;
use serde_json::{from_str, from_value, to_value, Value};

use url::Url;

use languageserver_types::{DidOpenTextDocumentParams, TextDocumentItem};

use gluon_language_server::rpc::read_message;

extern crate gluon;
use self::gluon::new_vm;

pub fn test_url(uri: &str) -> Url {
    Url::from_file_path(&env::current_dir().unwrap().join(uri)).unwrap()
}

pub fn write_message<W, V>(writer: &mut W, value: V) -> io::Result<()>
where
    W: ?Sized + Write,
    V: Serialize,
{
    let mut vec = Vec::new();
    value.serialize(&mut Serializer::new(&mut vec)).unwrap();
    write!(
        writer,
        "Content-Length: {}\r\n\r\n{}",
        vec.len(),
        str::from_utf8(&vec).unwrap()
    )
}

pub fn method_call<T>(method: &str, id: u64, value: T) -> Call
where
    T: Serialize,
{
    let value = to_value(value);
    let params = match value {
        Ok(Value::Object(map)) => Params::Map(map),
        _ => panic!("Expected map"),
    };
    Call::MethodCall(MethodCall {
        jsonrpc: Some(Version::V2),
        method: method.into(),
        id: Id::Num(id),
        params: Some(params),
    })
}

pub fn notification<T>(method: &str, value: T) -> Call
where
    T: Serialize,
{
    let value = to_value(value);
    let params = match value {
        Ok(Value::Object(map)) => Params::Map(map),
        _ => panic!("Expected map"),
    };
    Call::Notification(Notification {
        jsonrpc: Some(Version::V2),
        method: method.into(),
        params: Some(params),
    })
}

pub fn did_open_uri<W: ?Sized>(stdin: &mut W, uri: Url, text: &str)
where
    W: Write,
{
    let did_open = notification(
        "textDocument/didOpen",
        DidOpenTextDocumentParams {
            text_document: TextDocumentItem {
                uri: uri,
                language_id: Some("gluon".into()),
                text: text.into(),
                version: Some(1),
            },
        },
    );

    write_message(stdin, did_open).unwrap();
}

pub fn did_open<W: ?Sized>(stdin: &mut W, uri: &str, text: &str)
where
    W: Write,
{
    did_open_uri(stdin, test_url(uri), text)
}

pub fn expect_response<R, T>(mut output: R) -> T
where
    T: DeserializeOwned,
    R: BufRead,
{
    while let Some(json) = read_message(&mut output).unwrap() {
        // Skip all notifications
        if let Ok(Notification { .. }) = from_str(&json) {
            continue;
        }

        if let Ok(Response::Single(Output::Success(response))) = from_str(&json) {
            return from_value(response.result).unwrap();
        } else {
            panic!("Expected response, got `{}`", json)
        }
    }
    panic!("Expected a response")
}

pub fn expect_notification<R, T>(mut output: R) -> T
where
    T: DeserializeOwned,
    R: BufRead,
{
    while let Some(json) = read_message(&mut output).unwrap() {
        if let Ok(Notification {
            params: Some(params),
            ..
        }) = from_str(&json)
        {
            let json_value = match params {
                Params::Map(map) => Value::Object(map),
                Params::Array(array) => Value::Array(array),
                Params::None => Value::Null,
            };
            return from_value(json_value).unwrap();
        } else {
            panic!("Expected notification, got `{}`", json)
        }
    }
    panic!("Expected a notification")
}

pub fn send_rpc<F>(f: F)
where
    F: FnOnce(&mut Write, &mut BufRead),
{
    let (stdin_read, mut stdin_write) = pipe();
    let (stdout_read, stdout_write) = pipe();
    let mut stdout_read = BufReader::new(stdout_read);

    ::std::thread::spawn(move || {
        let thread = new_vm();

        ::gluon_language_server::start_server(thread, stdin_read, stdout_write).unwrap();
    });

    {
        f(&mut stdin_write, &mut stdout_read);

        let exit = Call::Notification(Notification {
            jsonrpc: Some(Version::V2),
            method: "exit".into(),
            params: None,
        });
        write_message(&mut stdin_write, exit).unwrap();
        drop(stdin_write);
    }
}

pub struct ReadPipe {
    recv: Receiver<Vec<u8>>,
    buffer: VecDeque<u8>,
}

impl io::Read for ReadPipe {
    fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
        let l = buffer.len().min(self.buffer.len());
        for (to, from) in buffer.iter_mut().zip(self.buffer.drain(..l)) {
            *to = from;
        }
        match self.recv.try_recv() {
            Ok(buf) => {
                self.buffer.extend(buf);
                let extra = self.read(&mut buffer[l..]).unwrap_or(0);
                Ok(l + extra)
            }
            Err(TryRecvError::Disconnected) => Ok(0),
            Err(TryRecvError::Empty) => if l == 0 {
                match self.recv.recv() {
                    Ok(buf) => {
                        let l = buffer.len().min(buf.len());
                        buffer[..l].copy_from_slice(&buf[..l]);
                        self.buffer.extend(buf[l..].iter().cloned());
                        Ok(l)
                    }
                    Err(_) => Ok(0),
                }
            } else {
                Ok(l)
            },
        }
    }

    fn read_to_end(&mut self, buffer: &mut Vec<u8>) -> io::Result<usize> {
        let len = buffer.len();
        buffer.extend(self.buffer.drain(..));
        while let Ok(buf) = self.recv.recv() {
            buffer.extend(buf);
        }
        Ok(buffer.len() - len)
    }
}

#[derive(Clone)]
pub struct WritePipe {
    sender: SyncSender<Vec<u8>>,
}

impl io::Write for WritePipe {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        if data.is_empty() {
            return Ok(0);
        }
        self.sender
            .send(data.to_owned())
            .map_err(|_| io::Error::from(io::ErrorKind::NotConnected))?;
        Ok(data.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

fn pipe() -> (ReadPipe, WritePipe) {
    let (sender, receiver) = sync_channel(10);
    (
        ReadPipe {
            recv: receiver,
            buffer: VecDeque::new(),
        },
        WritePipe { sender },
    )
}
<commit_msg>Improve notification deserialization errors in tests<commit_after>use std::collections::VecDeque;
use std::env;
use std::io::{self, BufRead, BufReader, Write};
use std::str;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TryRecvError};

use jsonrpc_core::request::{Call, MethodCall, Notification};
use jsonrpc_core::version::Version;
use jsonrpc_core::params::Params;
use jsonrpc_core::response::{Output, Response};
use jsonrpc_core::id::Id;

use serde::Serialize;
use serde::de::DeserializeOwned;
use serde_json::ser::Serializer;
use serde_json::{from_str, from_value, to_value, Value};

use url::Url;

use languageserver_types::{DidOpenTextDocumentParams, TextDocumentItem};

use gluon_language_server::rpc::read_message;

extern crate gluon;
use self::gluon::new_vm;

pub fn test_url(uri: &str) -> Url {
    Url::from_file_path(&env::current_dir().unwrap().join(uri)).unwrap()
}

pub fn write_message<W, V>(writer: &mut W, value: V) -> io::Result<()>
where
    W: ?Sized + Write,
    V: Serialize,
{
    let mut vec = Vec::new();
    value.serialize(&mut Serializer::new(&mut vec)).unwrap();
    write!(
        writer,
        "Content-Length: {}\r\n\r\n{}",
        vec.len(),
        str::from_utf8(&vec).unwrap()
    )
}

pub fn method_call<T>(method: &str, id: u64, value: T) -> Call
where
    T: Serialize,
{
    let value = to_value(value);
    let params = match value {
        Ok(Value::Object(map)) => Params::Map(map),
        _ => panic!("Expected map"),
    };
    Call::MethodCall(MethodCall {
        jsonrpc: Some(Version::V2),
        method: method.into(),
        id: Id::Num(id),
        params: Some(params),
    })
}

pub fn notification<T>(method: &str, value: T) -> Call
where
    T: Serialize,
{
    let value = to_value(value);
    let params = match value {
        Ok(Value::Object(map)) => Params::Map(map),
        _ => panic!("Expected map"),
    };
    Call::Notification(Notification {
        jsonrpc: Some(Version::V2),
        method: method.into(),
        params: Some(params),
    })
}

pub fn did_open_uri<W: ?Sized>(stdin: &mut W, uri: Url, text: &str)
where
    W: Write,
{
    let did_open = notification(
        "textDocument/didOpen",
        DidOpenTextDocumentParams {
            text_document: TextDocumentItem {
                uri: uri,
                language_id: Some("gluon".into()),
                text: text.into(),
                version: Some(1),
            },
        },
    );

    write_message(stdin, did_open).unwrap();
}

pub fn did_open<W: ?Sized>(stdin: &mut W, uri: &str, text: &str)
where
    W: Write,
{
    did_open_uri(stdin, test_url(uri), text)
}

pub fn expect_response<R, T>(mut output: R) -> T
where
    T: DeserializeOwned,
    R: BufRead,
{
    while let Some(json) = read_message(&mut output).unwrap() {
        // Skip all notifications
        if let Ok(Notification { .. }) = from_str(&json) {
            continue;
        }

        if let Ok(Response::Single(Output::Success(response))) = from_str(&json) {
            return from_value(response.result).unwrap();
        } else {
            panic!("Expected response, got `{}`", json)
        }
    }
    panic!("Expected a response")
}

pub fn expect_notification<R, T>(mut output: R) -> T
where
    T: DeserializeOwned,
    R: BufRead,
{
    while let Some(json) = read_message(&mut output).unwrap() {
        match from_str(&json) {
            Ok(Notification {
                params: Some(params),
                ..
            }) => {
                let json_value = match params {
                    Params::Map(map) => Value::Object(map),
                    Params::Array(array) => Value::Array(array),
                    Params::None => Value::Null,
                };
                return from_value(json_value).unwrap();
            }
            Ok(_) => panic!("Expected notification\n{}", json),
            Err(err) => panic!("Expected notification, got `{}`\n{}", err, json),
        }
    }
    panic!("Expected a notification")
}

pub fn send_rpc<F>(f: F)
where
    F: FnOnce(&mut Write, &mut BufRead),
{
    let (stdin_read, mut stdin_write) = pipe();
    let (stdout_read, stdout_write) = pipe();
    let mut stdout_read = BufReader::new(stdout_read);

    ::std::thread::spawn(move || {
        let thread = new_vm();

        ::gluon_language_server::start_server(thread, stdin_read, stdout_write).unwrap();
    });

    {
        f(&mut stdin_write, &mut stdout_read);

        let exit = Call::Notification(Notification {
            jsonrpc: Some(Version::V2),
            method: "exit".into(),
            params: None,
        });
        write_message(&mut stdin_write, exit).unwrap();
        drop(stdin_write);
    }
}

pub struct ReadPipe {
    recv: Receiver<Vec<u8>>,
    buffer: VecDeque<u8>,
}

impl io::Read for ReadPipe {
    fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
        let l = buffer.len().min(self.buffer.len());
        for (to, from) in buffer.iter_mut().zip(self.buffer.drain(..l)) {
            *to = from;
        }
        match self.recv.try_recv() {
            Ok(buf) => {
                self.buffer.extend(buf);
                let extra = self.read(&mut buffer[l..]).unwrap_or(0);
                Ok(l + extra)
            }
            Err(TryRecvError::Disconnected) => Ok(0),
            Err(TryRecvError::Empty) => if l == 0 {
                match self.recv.recv() {
                    Ok(buf) => {
                        let l = buffer.len().min(buf.len());
                        buffer[..l].copy_from_slice(&buf[..l]);
                        self.buffer.extend(buf[l..].iter().cloned());
                        Ok(l)
                    }
                    Err(_) => Ok(0),
                }
            } else {
                Ok(l)
            },
        }
    }

    fn read_to_end(&mut self, buffer: &mut Vec<u8>) -> io::Result<usize> {
        let len = buffer.len();
        buffer.extend(self.buffer.drain(..));
        while let Ok(buf) = self.recv.recv() {
            buffer.extend(buf);
        }
        Ok(buffer.len() - len)
    }
}

#[derive(Clone)]
pub struct WritePipe {
    sender: SyncSender<Vec<u8>>,
}

impl io::Write for WritePipe {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        if data.is_empty() {
            return Ok(0);
        }
        self.sender
            .send(data.to_owned())
            .map_err(|_| io::Error::from(io::ErrorKind::NotConnected))?;
        Ok(data.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

fn pipe() -> (ReadPipe, WritePipe) {
    let (sender, receiver) = sync_channel(10);
    (
        ReadPipe {
            recv: receiver,
            buffer: VecDeque::new(),
        },
        WritePipe { sender },
    )
}
<|endoftext|>


<commit_before>//! TODO Fill in

use rustwlc::{Geometry, Point, Size, WlcOutput};
use std::fmt::{self, Display, Formatter};
use std::default::Default;
use std::rc::Rc;
use rlua::{self, Table, Lua, UserData, ToLua, Value, AnyUserData, UserDataMethods,
           MetaMethod};
use super::object::{self, Object, Objectable};
use super::property::Property;
use super::class::{self, Class, ClassBuilder};

pub const SCREENS_HANDLE: &'static str = "__screens";

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Output {
    pub name: String,
    pub mm_width: u32,
    pub mm_height: u32,
    // TODO The XID array?
}

impl From<WlcOutput> for Output {
    fn from(output: WlcOutput) -> Output {
        let resolution = output.get_resolution().unwrap();
        Output {
            name: output.get_name(),
            mm_width: resolution.w,
            mm_height: resolution.h
        }
    }
}

#[derive(Clone, Debug)]
pub struct Screen<'lua>(Object<'lua>);

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ScreenState {
    // Is this screen still valid and may be used
    pub valid: bool,
    // Screen geometry
    pub geometry: Geometry,
    // Screen workarea
    pub workarea: Geometry,
    // The screen outputs information
    pub outputs: Vec<Output>,
    // Some XID indetifying this screen
    pub xid: u32
}

impl_objectable!(Screen, ScreenState);

impl Display for ScreenState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Screen: {:p}", self)
    }
}

impl <'lua> ToLua<'lua> for Screen<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl Default for ScreenState {
    fn default() -> Self {
        ScreenState {
            valid: true,
            geometry: Geometry::zero(),
            workarea: Geometry::zero(),
            outputs: vec![],
            xid: 0
        }
    }
}

impl UserData for ScreenState {
    fn add_methods(methods: &mut UserDataMethods<Self>) {
        methods.add_meta_function(MetaMethod::NewIndex, object::default_newindex);
    }
}

impl <'lua> Screen<'lua> {
    fn new(lua: &Lua) -> rlua::Result<Object> {
        let class = class::class_setup(lua, "screen")?;
        Ok(Screen::allocate(lua, class)?.build())
    }

    fn init_screens(&mut self, output: WlcOutput, outputs: Vec<Output>) -> rlua::Result<()> {
        let mut state = self.state()?;
        let resolution = output.get_resolution().unwrap();
        state.outputs = outputs;
        state.geometry.size = resolution;
        state.workarea.size = resolution;
        self.set_state(state)
    }

    fn get_geometry(&self, lua: &'lua Lua) -> rlua::Result<Table<'lua>> {
        let state = self.state()?;
        let Point { x, y } = state.geometry.origin;
        let Size { w, h } = state.geometry.size;
        let table = lua.create_table()?;
        table.set("x", x)?;
        table.set("y", y)?;
        table.set("width", w)?;
        table.set("height", h)?;
        Ok(table)
    }

    fn get_workarea(&self, lua: &'lua Lua) -> rlua::Result<Table<'lua>> {
        let state = self.state()?;
        let Point { x, y } = state.workarea.origin;
        let Size { w, h } = state.workarea.size;
        let table = lua.create_table()?;
        table.set("x", x)?;
        table.set("y", y)?;
        table.set("width", w)?;
        table.set("height", h)?;
        Ok(table)
    }
}

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    let builder = Class::builder(lua, "screen", Some(Rc::new(Screen::new)), None, None)?;
    let res = property_setup(lua, method_setup(lua, builder)?)?
        .save_class("screen")?
        .build()?;
    let mut screens: Vec<Screen> = vec![];
    for output in WlcOutput::list() {
        let mut screen = Screen::cast(Screen::new(lua)?)?;
        screen.init_screens(output, vec![output.into()])?;
        // TODO Move to Screen impl like the others
        screens.push(screen);
    }
    lua.globals().set(SCREENS_HANDLE, screens.to_lua(lua)?)?;
    Ok(res)
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>)
                      -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    use super::dummy;
    builder.method("connect_signal".into(), lua.create_function(dummy)?)?
           .method("__call".into(), lua.create_function(iterate_over_screens)?)?
           .method("__index".into(), lua.create_function(index)?)
}

fn property_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>)
                        -> rlua::Result<ClassBuilder<'lua>> {
    builder
        .property(Property::new("geometry".into(),
                                None,
                                Some(lua.create_function(get_geometry)?),
                                None))?
        .property(Property::new("workarea".into(),
                                None,
                                Some(lua.create_function(get_workarea)?),
                                None))
}

fn get_geometry<'lua>(lua: &'lua Lua, object: AnyUserData<'lua>) -> rlua::Result<Table<'lua>> {
    let screen = Screen::cast(object.into())?;
    screen.get_geometry(lua)
}

fn get_workarea<'lua>(lua: &'lua Lua, object: AnyUserData<'lua>) -> rlua::Result<Table<'lua>> {
    let screen = Screen::cast(object.into())?;
    screen.get_workarea(lua)
}

/// Ok this requires some explanation...
/// Lua gives us the previous value in the loop, with the first one being nil
/// since there was nothing there before.
///
/// To ensure we loop over everything, we take the index of that value in our list,
/// increment it by 1 (starting at 0 if it's the start) and then once it falls outside
/// the bounds it will stop by returning nil.
fn iterate_over_screens<'lua>(lua: &'lua Lua,
                              (_, prev): (Value<'lua>, Value<'lua>))
                              -> rlua::Result<Value<'lua>> {
    let screens: Vec<Screen> = lua.globals().get::<_, Vec<AnyUserData>>(SCREENS_HANDLE)?
        .into_iter().map(|obj| Screen::cast(obj.into()).unwrap())
        .collect();
    let index = match prev {
        Value::Nil => 0,
        Value::UserData(ref object) => {
            if let Ok(screen) = Screen::cast(object.clone().into()) {
                screens.iter().position(|t| t.state().unwrap() == screen.state().unwrap())
                    .unwrap_or(screens.len()) + 1
            } else {
                panic!("Unexpected non-screen table in loop");
            }
        }
        _ => panic!("Unexpected non-screen or nil value in screens loop")
    };
    if index < screens.len() {
        warn!("here");
        screens[index].clone().to_lua(lua)
    } else {
        Ok(Value::Nil)
    }

}

fn index<'lua>(lua: &'lua Lua,
               (data, index): (AnyUserData<'lua>, Value<'lua>))
               -> rlua::Result<Value<'lua>> {
    let obj: Object = data.clone().into();
    let screens: Vec<Screen> = lua.globals().get::<_, Vec<AnyUserData>>(SCREENS_HANDLE)?
        .into_iter().map(|obj| Screen::cast(obj.into()).unwrap())
        .collect();
    match index {
        Value::String(ref string) => {
            let string = string.to_str()?;
            if string == "primary" {
                // TODO Emit primary changed signal
                if screens.len() > 0 {
                    return screens[0].clone().to_lua(lua)
                }
            }
            for screen in screens.iter() {
                let screen_state = screen.state()?;
                for output in &screen_state.outputs {
                    if output.name.as_str() == string {
                        return screen.clone().to_lua(lua)
                    }
                }
            }
        },
        // TODO Might need to do Number instead
        Value::Integer(screen_index) => {
            if screen_index < 1 || screen_index as usize > screens.len() {
                return Err(rlua::Error::RuntimeError(
                    format!("invalid screen number: {} (of {} existing)",
                            screen_index, screens.len())))
            }
            return screens[(screen_index - 1) as usize].clone().to_lua(lua)
        },
        Value::UserData(ref obj) => {
            // If this is a screen, just return it
            if let Ok(screen) = Screen::cast(obj.clone().into()) {
                return screen.to_lua(lua)
            }
        },
        // TODO This checke user data like in luaA_toudata in awesome
        _ => {}
    }
    // TODO checkudata
    let table = obj.table()?;
    let meta = table.get_metatable().expect("screen had no metatable");
    match meta.get(index.clone()) {
        Err(_) | Ok(Value::Nil) => super::object::default_index(lua, (data, index)),
        Ok(value) => Ok(value)
    }
}
<commit_msg>More indexing woes<commit_after>//! TODO Fill in

use rustwlc::{Geometry, Point, Size, WlcOutput};
use std::fmt::{self, Display, Formatter};
use std::default::Default;
use std::rc::Rc;
use rlua::{self, Table, Lua, UserData, ToLua, Value, AnyUserData, UserDataMethods,
           MetaMethod};
use super::object::{self, Object, Objectable};
use super::property::Property;
use super::class::{self, Class, ClassBuilder};

pub const SCREENS_HANDLE: &'static str = "__screens";

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Output {
    pub name: String,
    pub mm_width: u32,
    pub mm_height: u32,
    // TODO The XID array?
}

impl From<WlcOutput> for Output {
    fn from(output: WlcOutput) -> Output {
        let resolution = output.get_resolution().unwrap();
        Output {
            name: output.get_name(),
            mm_width: resolution.w,
            mm_height: resolution.h
        }
    }
}

#[derive(Clone, Debug)]
pub struct Screen<'lua>(Object<'lua>);

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ScreenState {
    // Is this screen still valid and may be used
    pub valid: bool,
    // Screen geometry
    pub geometry: Geometry,
    // Screen workarea
    pub workarea: Geometry,
    // The screen outputs information
    pub outputs: Vec<Output>,
    // Some XID indetifying this screen
    pub xid: u32
}

impl_objectable!(Screen, ScreenState);

impl Display for ScreenState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Screen: {:p}", self)
    }
}

impl <'lua> ToLua<'lua> for Screen<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl Default for ScreenState {
    fn default() -> Self {
        ScreenState {
            valid: true,
            geometry: Geometry::zero(),
            workarea: Geometry::zero(),
            outputs: vec![],
            xid: 0
        }
    }
}

impl UserData for ScreenState {
    fn add_methods(methods: &mut UserDataMethods<Self>) {
        methods.add_meta_function(MetaMethod::Index, index);
        methods.add_meta_function(MetaMethod::NewIndex, object::default_newindex);
    }
}

impl <'lua> Screen<'lua> {
    fn new(lua: &Lua) -> rlua::Result<Object> {
        let class = class::class_setup(lua, "screen")?;
        Ok(Screen::allocate(lua, class)?.build())
    }

    fn init_screens(&mut self, output: WlcOutput, outputs: Vec<Output>) -> rlua::Result<()> {
        let mut state = self.state()?;
        let resolution = output.get_resolution().unwrap();
        state.outputs = outputs;
        state.geometry.size = resolution;
        state.workarea.size = resolution;
        self.set_state(state)
    }

    fn get_geometry(&self, lua: &'lua Lua) -> rlua::Result<Table<'lua>> {
        let state = self.state()?;
        let Point { x, y } = state.geometry.origin;
        let Size { w, h } = state.geometry.size;
        let table = lua.create_table()?;
        table.set("x", x)?;
        table.set("y", y)?;
        table.set("width", w)?;
        table.set("height", h)?;
        Ok(table)
    }

    fn get_workarea(&self, lua: &'lua Lua) -> rlua::Result<Table<'lua>> {
        let state = self.state()?;
        let Point { x, y } = state.workarea.origin;
        let Size { w, h } = state.workarea.size;
        let table = lua.create_table()?;
        table.set("x", x)?;
        table.set("y", y)?;
        table.set("width", w)?;
        table.set("height", h)?;
        Ok(table)
    }
}

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    let builder = Class::builder(lua, "screen", Some(Rc::new(Screen::new)), None, None)?;
    let res = property_setup(lua, method_setup(lua, builder)?)?
        .save_class("screen")?
        .build()?;
    let mut screens: Vec<Screen> = vec![];
    for output in WlcOutput::list() {
        let mut screen = Screen::cast(Screen::new(lua)?)?;
        screen.init_screens(output, vec![output.into()])?;
        // TODO Move to Screen impl like the others
        screens.push(screen);
    }
    lua.globals().set(SCREENS_HANDLE, screens.to_lua(lua)?)?;
    Ok(res)
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>)
                      -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    use super::dummy;
    builder.method("connect_signal".into(), lua.create_function(dummy)?)?
           .method("__call".into(), lua.create_function(iterate_over_screens)?)?
           .method("__index".into(), lua.create_function(index)?)
}

fn property_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>)
                        -> rlua::Result<ClassBuilder<'lua>> {
    builder
        .property(Property::new("geometry".into(),
                                None,
                                Some(lua.create_function(get_geometry)?),
                                None))?
        .property(Property::new("workarea".into(),
                                None,
                                Some(lua.create_function(get_workarea)?),
                                None))
}

fn get_geometry<'lua>(lua: &'lua Lua, object: AnyUserData<'lua>) -> rlua::Result<Table<'lua>> {
    let screen = Screen::cast(object.into())?;
    screen.get_geometry(lua)
}

fn get_workarea<'lua>(lua: &'lua Lua, object: AnyUserData<'lua>) -> rlua::Result<Table<'lua>> {
    let screen = Screen::cast(object.into())?;
    screen.get_workarea(lua)
}

/// Ok this requires some explanation...
/// Lua gives us the previous value in the loop, with the first one being nil
/// since there was nothing there before.
///
/// To ensure we loop over everything, we take the index of that value in our list,
/// increment it by 1 (starting at 0 if it's the start) and then once it falls outside
/// the bounds it will stop by returning nil.
fn iterate_over_screens<'lua>(lua: &'lua Lua,
                              (_, prev): (Value<'lua>, Value<'lua>))
                              -> rlua::Result<Value<'lua>> {
    let screens: Vec<Screen> = lua.globals().get::<_, Vec<AnyUserData>>(SCREENS_HANDLE)?
        .into_iter().map(|obj| Screen::cast(obj.into()).unwrap())
        .collect();
    let index = match prev {
        Value::Nil => 0,
        Value::UserData(ref object) => {
            if let Ok(screen) = Screen::cast(object.clone().into()) {
                screens.iter().position(|t| t.state().unwrap() == screen.state().unwrap())
                    .unwrap_or(screens.len()) + 1
            } else {
                panic!("Unexpected non-screen table in loop");
            }
        }
        _ => panic!("Unexpected non-screen or nil value in screens loop")
    };
    if index < screens.len() {
        warn!("here");
        screens[index].clone().to_lua(lua)
    } else {
        Ok(Value::Nil)
    }

}

fn index<'lua>(lua: &'lua Lua,
               (data, index): (AnyUserData<'lua>, Value<'lua>))
               -> rlua::Result<Value<'lua>> {
    let obj: Object = data.clone().into();
    let screens: Vec<Screen> = lua.globals().get::<_, Vec<AnyUserData>>(SCREENS_HANDLE)?
        .into_iter().map(|obj| Screen::cast(obj.into()).unwrap())
        .collect();
    match index {
        Value::String(ref string) => {
            let string = string.to_str()?;
            if string == "primary" {
                // TODO Emit primary changed signal
                if screens.len() > 0 {
                    return screens[0].clone().to_lua(lua)
                }
            }
            for screen in screens.iter() {
                let screen_state = screen.state()?;
                for output in &screen_state.outputs {
                    if output.name.as_str() == string {
                        return screen.clone().to_lua(lua)
                    }
                }
            }
        },
        // TODO Might need to do Number instead
        Value::Integer(screen_index) => {
            if screen_index < 1 || screen_index as usize > screens.len() {
                return Err(rlua::Error::RuntimeError(
                    format!("invalid screen number: {} (of {} existing)",
                            screen_index, screens.len())))
            }
            return screens[(screen_index - 1) as usize].clone().to_lua(lua)
        },
        Value::UserData(ref obj) => {
            // If this is a screen, just return it
            if let Ok(screen) = Screen::cast(obj.clone().into()) {
                return screen.to_lua(lua)
            }
        },
        // TODO This checke user data like in luaA_toudata in awesome
        _ => {}
    }
    // TODO checkudata
    let table = obj.table()?;
    let meta = table.get_metatable().expect("screen had no metatable");
    match meta.get(index.clone()) {
        Err(_) | Ok(Value::Nil) => super::object::default_index(lua, (data, index)),
        Ok(value) => Ok(value)
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Freshening is the process of replacing unknown variables with fresh types. The idea is that
//! the type, after freshening, contains no inference variables but instead contains either a
//! value for each variable or fresh "arbitrary" types wherever a variable would have been.
//!
//! Freshening is used primarily to get a good type for inserting into a cache. The result
//! summarizes what the type inferencer knows "so far". The primary place it is used right now is
//! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type
//! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in
//! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending
//! on what type that type variable is ultimately assigned, the match may or may not succeed.
//!
//! To handle closures, freshened types also have to contain the signature and kind of any
//! closure in the local inference context, as otherwise the cache key might be invalidated.
//! The way this is done is somewhat hacky - the closure signature is appended to the substs,
//! as well as the closure kind "encoded" as a type. Also, special handling is needed when
//! the closure signature contains a reference to the original closure.
//!
//! Note that you should be careful not to allow the output of freshening to leak to the user in
//! error messages or in any other form. Freshening is only really useful as an internal detail.
//!
//! Because of the manipulation required to handle closures, doing arbitrary operations on
//! freshened types is not recommended. However, in addition to doing equality/hash
//! comparisons (for caching), it is possible to do a `ty::_match` operation between
//! 2 freshened types - this works even with the closure encoding.
//!
//! __An important detail concerning regions.__ The freshener also replaces *all* free regions with
//! 'erased. The reason behind this is that, in general, we do not take region relationships into
//! account when making type-overloaded decisions. This is important because of the design of the
//! region inferencer, which is not based on unification but rather on accumulating and then
//! solving a set of constraints. In contrast, the type inferencer assigns a value to each type
//! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type
//! inferencer knows "so far".

use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::fold::TypeFolder;
use ty::subst::Substs;
use util::nodemap::FxHashMap;
use hir::def_id::DefId;

use std::collections::hash_map::Entry;

use super::InferCtxt;
use super::unify_key::ToType;

pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
    freshen_count: u32,
    freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
    closure_set: Vec<DefId>,
}

impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
               -> TypeFreshener<'a, 'gcx, 'tcx> {
        TypeFreshener {
            infcx,
            freshen_count: 0,
            freshen_map: FxHashMap(),
            closure_set: vec![],
        }
    }

    fn freshen<F>(&mut self,
                  opt_ty: Option<Ty<'tcx>>,
                  key: ty::InferTy,
                  freshener: F)
                  -> Ty<'tcx> where
        F: FnOnce(u32) -> ty::InferTy,
    {
        if let Some(ty) = opt_ty {
            return ty.fold_with(self);
        }

        match self.freshen_map.entry(key) {
            Entry::Occupied(entry) => *entry.get(),
            Entry::Vacant(entry) => {
                let index = self.freshen_count;
                self.freshen_count += 1;
                let t = self.infcx.tcx.mk_infer(freshener(index));
                entry.insert(t);
                t
            }
        }
    }

    fn next_fresh<F>(&mut self,
                     freshener: F)
                     -> Ty<'tcx>
        where F: FnOnce(u32) -> ty::InferTy,
    {
        let index = self.freshen_count;
        self.freshen_count += 1;
        self.infcx.tcx.mk_infer(freshener(index))
    }

    fn freshen_closure_like<M, C>(&mut self,
                                  def_id: DefId,
                                  substs: ty::ClosureSubsts<'tcx>,
                                  t: Ty<'tcx>,
                                  markers: M,
                                  combine: C)
                                  -> Ty<'tcx>
        where M: FnOnce(&mut Self) -> (Ty<'tcx>, Ty<'tcx>),
              C: FnOnce(&'tcx Substs<'tcx>) -> Ty<'tcx>
    {
        let tcx = self.infcx.tcx;

        let closure_in_progress = self.infcx.in_progress_tables.map_or(false, |tables| {
            tcx.hir.as_local_node_id(def_id).map_or(false, |closure_id| {
                tables.borrow().local_id_root ==
                    Some(DefId::local(tcx.hir.node_to_hir_id(closure_id).owner))
            })
        });

        if !closure_in_progress {
            // If this closure belongs to another infcx, its kind etc. were
            // fully inferred and its signature/kind are exactly what's listed
            // in its infcx. So we don't need to add the markers for them.
            return t.super_fold_with(self);
        }

        // We are encoding a closure in progress. Because we want our freshening
        // key to contain all inference information needed to make sense of our
        // value, we need to encode the closure signature and kind. The way
        // we do that is to add them as 2 variables to the closure substs,
        // basically because it's there (and nobody cares about adding extra stuff
        // to substs).
        //
        // This means the "freshened" closure substs ends up looking like
        //     fresh_substs = [PARENT_SUBSTS* ; UPVARS* ; SIG_MARKER ; KIND_MARKER]
        let (marker_1, marker_2) = if self.closure_set.contains(&def_id) {
            // We found the closure def-id within its own signature. Just
            // leave a new freshened type - any matching operations would
            // have found and compared the exterior closure already to
            // get here.
            //
            // In that case, we already know what the signature would
            // be - the parent closure on the stack already contains a
            // "copy" of the signature, so there is no reason to encode
            // it again for injectivity. Just use a fresh type variable
            // to make everything comparable.
            //
            // For example (closure kinds omitted for clarity)
            //     t=[closure FOO sig=[closure BAR sig=[closure FOO ..]]]
            // Would get encoded to
            //     t=[closure FOO sig=[closure BAR sig=[closure FOO sig=$0]]]
            //
            // and we can decode by having
            //     $0=[closure BAR {sig doesn't exist in decode}]
            // and get
            //     t=[closure FOO]
            //     sig[FOO] = [closure BAR]
            //     sig[BAR] = [closure FOO]
            (self.next_fresh(ty::FreshTy), self.next_fresh(ty::FreshTy))
        } else {
            self.closure_set.push(def_id);
            let markers = markers(self);
            self.closure_set.pop();
            markers
        };

        combine(tcx.mk_substs(
            substs.substs.iter().map(|k| k.fold_with(self)).chain(
                [marker_1, marker_2].iter().cloned().map(From::from)
                    )))
    }
}

impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
        self.infcx.tcx
    }

    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
        match *r {
            ty::ReLateBound(..) => {
                // leave bound regions alone
                r
            }

            ty::ReStatic |
            ty::ReEarlyBound(..) |
            ty::ReFree(_) |
            ty::ReScope(_) |
            ty::ReVar(_) |
            ty::ReSkolemized(..) |
            ty::ReEmpty |
            ty::ReErased => {
                // replace all free regions with 'erased
                self.tcx().types.re_erased
            }
        }
    }

    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
        if !t.needs_infer() && !t.has_erasable_regions() &&
            !(t.has_closure_types() && self.infcx.in_progress_tables.is_some()) {
            return t;
        }

        let tcx = self.infcx.tcx;

        match t.sty {
            ty::TyInfer(ty::TyVar(v)) => {
                let opt_ty = self.infcx.type_variables.borrow_mut().probe(v);
                self.freshen(
                    opt_ty,
                    ty::TyVar(v),
                    ty::FreshTy)
            }

            ty::TyInfer(ty::IntVar(v)) => {
                self.freshen(
                    self.infcx.int_unification_table.borrow_mut()
                                                    .probe(v)
                                                    .map(|v| v.to_type(tcx)),
                    ty::IntVar(v),
                    ty::FreshIntTy)
            }

            ty::TyInfer(ty::FloatVar(v)) => {
                self.freshen(
                    self.infcx.float_unification_table.borrow_mut()
                                                      .probe(v)
                                                      .map(|v| v.to_type(tcx)),
                    ty::FloatVar(v),
                    ty::FreshFloatTy)
            }

            ty::TyInfer(ty::FreshTy(c)) |
            ty::TyInfer(ty::FreshIntTy(c)) |
            ty::TyInfer(ty::FreshFloatTy(c)) => {
                if c >= self.freshen_count {
                    bug!("Encountered a freshend type with id {} \
                          but our counter is only at {}",
                         c,
                         self.freshen_count);
                }
                t
            }

            ty::TyClosure(def_id, substs) => {
                self.freshen_closure_like(
                    def_id, substs, t,
                    |this| {
                        let closure_sig = this.infcx.fn_sig(def_id);
                        (tcx.mk_fn_ptr(closure_sig.fold_with(this)), tcx.types.char)
                    },
                    |substs| tcx.mk_closure(def_id, ty::ClosureSubsts { substs })
                )
            }

            ty::TyGenerator(def_id, substs, interior) => {
                self.freshen_closure_like(
                    def_id, substs, t,
                    |this| {
                        let gen_sig = this.infcx.generator_sig(def_id).unwrap();
                        // FIXME: want to revise this strategy when generator
                        // signatures can actually contain LBRs.
                        let sig = this.tcx().no_late_bound_regions(&gen_sig)
                            .unwrap_or_else(|| {
                                bug!("late-bound regions in signature of {:?}",
                                     def_id)
                            });
                        (sig.yield_ty, sig.return_ty).fold_with(this)
                    },
                    |substs| {
                        tcx.mk_generator(def_id, ty::ClosureSubsts { substs }, interior)
                    }
                )
            }

            ty::TyBool |
            ty::TyChar |
            ty::TyInt(..) |
            ty::TyUint(..) |
            ty::TyFloat(..) |
            ty::TyAdt(..) |
            ty::TyStr |
            ty::TyError |
            ty::TyArray(..) |
            ty::TySlice(..) |
            ty::TyRawPtr(..) |
            ty::TyRef(..) |
            ty::TyFnDef(..) |
            ty::TyFnPtr(_) |
            ty::TyDynamic(..) |
            ty::TyNever |
            ty::TyTuple(..) |
            ty::TyProjection(..) |
            ty::TyForeign(..) |
            ty::TyParam(..) |
            ty::TyAnon(..) => {
                t.super_fold_with(self)
            }
        }
    }
}
<commit_msg>`TyClosure` no longer needs to use `freshen_closure_like`<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Freshening is the process of replacing unknown variables with fresh types. The idea is that
//! the type, after freshening, contains no inference variables but instead contains either a
//! value for each variable or fresh "arbitrary" types wherever a variable would have been.
//!
//! Freshening is used primarily to get a good type for inserting into a cache. The result
//! summarizes what the type inferencer knows "so far". The primary place it is used right now is
//! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type
//! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in
//! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending
//! on what type that type variable is ultimately assigned, the match may or may not succeed.
//!
//! To handle closures, freshened types also have to contain the signature and kind of any
//! closure in the local inference context, as otherwise the cache key might be invalidated.
//! The way this is done is somewhat hacky - the closure signature is appended to the substs,
//! as well as the closure kind "encoded" as a type. Also, special handling is needed when
//! the closure signature contains a reference to the original closure.
//!
//! Note that you should be careful not to allow the output of freshening to leak to the user in
//! error messages or in any other form. Freshening is only really useful as an internal detail.
//!
//! Because of the manipulation required to handle closures, doing arbitrary operations on
//! freshened types is not recommended. However, in addition to doing equality/hash
//! comparisons (for caching), it is possible to do a `ty::_match` operation between
//! 2 freshened types - this works even with the closure encoding.
//!
//! __An important detail concerning regions.__ The freshener also replaces *all* free regions with
//! 'erased. The reason behind this is that, in general, we do not take region relationships into
//! account when making type-overloaded decisions. This is important because of the design of the
//! region inferencer, which is not based on unification but rather on accumulating and then
//! solving a set of constraints. In contrast, the type inferencer assigns a value to each type
//! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type
//! inferencer knows "so far".

use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::fold::TypeFolder;
use ty::subst::Substs;
use util::nodemap::FxHashMap;
use hir::def_id::DefId;

use std::collections::hash_map::Entry;

use super::InferCtxt;
use super::unify_key::ToType;

pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
    freshen_count: u32,
    freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
    closure_set: Vec<DefId>,
}

impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
               -> TypeFreshener<'a, 'gcx, 'tcx> {
        TypeFreshener {
            infcx,
            freshen_count: 0,
            freshen_map: FxHashMap(),
            closure_set: vec![],
        }
    }

    fn freshen<F>(&mut self,
                  opt_ty: Option<Ty<'tcx>>,
                  key: ty::InferTy,
                  freshener: F)
                  -> Ty<'tcx> where
        F: FnOnce(u32) -> ty::InferTy,
    {
        if let Some(ty) = opt_ty {
            return ty.fold_with(self);
        }

        match self.freshen_map.entry(key) {
            Entry::Occupied(entry) => *entry.get(),
            Entry::Vacant(entry) => {
                let index = self.freshen_count;
                self.freshen_count += 1;
                let t = self.infcx.tcx.mk_infer(freshener(index));
                entry.insert(t);
                t
            }
        }
    }

    fn next_fresh<F>(&mut self,
                     freshener: F)
                     -> Ty<'tcx>
        where F: FnOnce(u32) -> ty::InferTy,
    {
        let index = self.freshen_count;
        self.freshen_count += 1;
        self.infcx.tcx.mk_infer(freshener(index))
    }

    fn freshen_generator_like<M, C>(&mut self,
                                  def_id: DefId,
                                  substs: ty::ClosureSubsts<'tcx>,
                                  t: Ty<'tcx>,
                                  markers: M,
                                  combine: C)
                                  -> Ty<'tcx>
        where M: FnOnce(&mut Self) -> (Ty<'tcx>, Ty<'tcx>),
              C: FnOnce(&'tcx Substs<'tcx>) -> Ty<'tcx>
    {
        let tcx = self.infcx.tcx;

        let closure_in_progress = self.infcx.in_progress_tables.map_or(false, |tables| {
            tcx.hir.as_local_node_id(def_id).map_or(false, |closure_id| {
                tables.borrow().local_id_root ==
                    Some(DefId::local(tcx.hir.node_to_hir_id(closure_id).owner))
            })
        });

        if !closure_in_progress {
            // If this closure belongs to another infcx, its kind etc. were
            // fully inferred and its signature/kind are exactly what's listed
            // in its infcx. So we don't need to add the markers for them.
            return t.super_fold_with(self);
        }

        // We are encoding a closure in progress. Because we want our freshening
        // key to contain all inference information needed to make sense of our
        // value, we need to encode the closure signature and kind. The way
        // we do that is to add them as 2 variables to the closure substs,
        // basically because it's there (and nobody cares about adding extra stuff
        // to substs).
        //
        // This means the "freshened" closure substs ends up looking like
        //     fresh_substs = [PARENT_SUBSTS* ; UPVARS* ; SIG_MARKER ; KIND_MARKER]
        let (marker_1, marker_2) = if self.closure_set.contains(&def_id) {
            // We found the closure def-id within its own signature. Just
            // leave a new freshened type - any matching operations would
            // have found and compared the exterior closure already to
            // get here.
            //
            // In that case, we already know what the signature would
            // be - the parent closure on the stack already contains a
            // "copy" of the signature, so there is no reason to encode
            // it again for injectivity. Just use a fresh type variable
            // to make everything comparable.
            //
            // For example (closure kinds omitted for clarity)
            //     t=[closure FOO sig=[closure BAR sig=[closure FOO ..]]]
            // Would get encoded to
            //     t=[closure FOO sig=[closure BAR sig=[closure FOO sig=$0]]]
            //
            // and we can decode by having
            //     $0=[closure BAR {sig doesn't exist in decode}]
            // and get
            //     t=[closure FOO]
            //     sig[FOO] = [closure BAR]
            //     sig[BAR] = [closure FOO]
            (self.next_fresh(ty::FreshTy), self.next_fresh(ty::FreshTy))
        } else {
            self.closure_set.push(def_id);
            let markers = markers(self);
            self.closure_set.pop();
            markers
        };

        combine(tcx.mk_substs(
            substs.substs.iter().map(|k| k.fold_with(self)).chain(
                [marker_1, marker_2].iter().cloned().map(From::from)
                    )))
    }
}

impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
        self.infcx.tcx
    }

    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
        match *r {
            ty::ReLateBound(..) => {
                // leave bound regions alone
                r
            }

            ty::ReStatic |
            ty::ReEarlyBound(..) |
            ty::ReFree(_) |
            ty::ReScope(_) |
            ty::ReVar(_) |
            ty::ReSkolemized(..) |
            ty::ReEmpty |
            ty::ReErased => {
                // replace all free regions with 'erased
                self.tcx().types.re_erased
            }
        }
    }

    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
        if !t.needs_infer() && !t.has_erasable_regions() &&
            !(t.has_closure_types() && self.infcx.in_progress_tables.is_some()) {
            return t;
        }

        let tcx = self.infcx.tcx;

        match t.sty {
            ty::TyInfer(ty::TyVar(v)) => {
                let opt_ty = self.infcx.type_variables.borrow_mut().probe(v);
                self.freshen(
                    opt_ty,
                    ty::TyVar(v),
                    ty::FreshTy)
            }

            ty::TyInfer(ty::IntVar(v)) => {
                self.freshen(
                    self.infcx.int_unification_table.borrow_mut()
                                                    .probe(v)
                                                    .map(|v| v.to_type(tcx)),
                    ty::IntVar(v),
                    ty::FreshIntTy)
            }

            ty::TyInfer(ty::FloatVar(v)) => {
                self.freshen(
                    self.infcx.float_unification_table.borrow_mut()
                                                      .probe(v)
                                                      .map(|v| v.to_type(tcx)),
                    ty::FloatVar(v),
                    ty::FreshFloatTy)
            }

            ty::TyInfer(ty::FreshTy(c)) |
            ty::TyInfer(ty::FreshIntTy(c)) |
            ty::TyInfer(ty::FreshFloatTy(c)) => {
                if c >= self.freshen_count {
                    bug!("Encountered a freshend type with id {} \
                          but our counter is only at {}",
                         c,
                         self.freshen_count);
                }
                t
            }

            ty::TyGenerator(def_id, substs, interior) => {
                self.freshen_generator_like(
                    def_id, substs, t,
                    |this| {
                        let gen_sig = this.infcx.generator_sig(def_id).unwrap();
                        // FIXME: want to revise this strategy when generator
                        // signatures can actually contain LBRs.
                        let sig = this.tcx().no_late_bound_regions(&gen_sig)
                            .unwrap_or_else(|| {
                                bug!("late-bound regions in signature of {:?}",
                                     def_id)
                            });
                        (sig.yield_ty, sig.return_ty).fold_with(this)
                    },
                    |substs| {
                        tcx.mk_generator(def_id, ty::ClosureSubsts { substs }, interior)
                    }
                )
            }

            ty::TyBool |
            ty::TyChar |
            ty::TyInt(..) |
            ty::TyUint(..) |
            ty::TyFloat(..) |
            ty::TyAdt(..) |
            ty::TyStr |
            ty::TyError |
            ty::TyArray(..) |
            ty::TySlice(..) |
            ty::TyRawPtr(..) |
            ty::TyRef(..) |
            ty::TyFnDef(..) |
            ty::TyFnPtr(_) |
            ty::TyDynamic(..) |
            ty::TyNever |
            ty::TyTuple(..) |
            ty::TyProjection(..) |
            ty::TyForeign(..) |
            ty::TyParam(..) |
            ty::TyClosure(..) |
            ty::TyAnon(..) => {
                t.super_fold_with(self)
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use std::io::prelude::*;
use std::io;

use externalfiles::ExternalHtml;

#[derive(Clone)]
pub struct Layout {
    pub logo: String,
    pub favicon: String,
    pub external_html: ExternalHtml,
    pub krate: String,
    pub playground_url: String,
}

pub struct Page<'a> {
    pub title: &'a str,
    pub ty: &'a str,
    pub root_path: &'a str,
    pub description: &'a str,
    pub keywords: &'a str
}

pub fn render<T: fmt::Display, S: fmt::Display>(
    dst: &mut io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T)
    -> io::Result<()>
{
    write!(dst,
r##"<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="generator" content="rustdoc">
    <meta name="description" content="{description}">
    <meta name="keywords" content="{keywords}">

    <title>{title}</title>

    <link rel="stylesheet" type="text/css" href="{root_path}main.css">

    {favicon}
    {in_header}

    {before_content}

        {logo}
        {sidebar}

        <form class="search-form js-only">

                <input class="search-input" name="search"
                       autocomplete="off"
                       placeholder="Click or press 'S' to search, '?' for more options..."
                       type="search">

        </form>

{content}

Keyboard shortcuts

?

Show this help dialog

S

Focus the search field

⇤

Move up in search results

⇥

Move down in search results

⏎

Go to active search result

Search tricks

                Prefix searches with a type followed by a colon (e.g.
                fn:) to restrict the search to a given type.

                Accepted types are: fn, mod,
                struct, enum,
                trait, typedef (or
                tdef).

    {after_content}

    {play_js}

"##,
    content   = *t,
    root_path = page.root_path,
    ty        = page.ty,
    logo      = if layout.logo.is_empty() {
        "".to_string()
    } else {
        format!("\
                 ",
                page.root_path, layout.krate,
                layout.logo)
    },
    title     = page.title,
    description = page.description,
    keywords = page.keywords,
    favicon   = if layout.favicon.is_empty() {
        "".to_string()
    } else {
        format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
    },
    in_header = layout.external_html.in_header,
    before_content = layout.external_html.before_content,
    after_content = layout.external_html.after_content,
    sidebar   = *sidebar,
    krate     = layout.krate,
    play_url  = layout.playground_url,
    play_js   = if layout.playground_url.is_empty() {
        "".to_string()
    } else {
        format!(r#""#, page.root_path)
    },
    )
}

pub fn redirect(dst: &mut io::Write, url: &str) -> io::Result<()> {
    //

"##,
    url = url,
    )
}
<commit_msg>Rollup merge of #25146 - piatra:doc-search-patch, r=steveklabnik<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use std::io::prelude::*;
use std::io;

use externalfiles::ExternalHtml;

#[derive(Clone)]
pub struct Layout {
    pub logo: String,
    pub favicon: String,
    pub external_html: ExternalHtml,
    pub krate: String,
    pub playground_url: String,
}

pub struct Page<'a> {
    pub title: &'a str,
    pub ty: &'a str,
    pub root_path: &'a str,
    pub description: &'a str,
    pub keywords: &'a str
}

pub fn render<T: fmt::Display, S: fmt::Display>(
    dst: &mut io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T)
    -> io::Result<()>
{
    write!(dst,
r##"<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="generator" content="rustdoc">
    <meta name="description" content="{description}">
    <meta name="keywords" content="{keywords}">

    <title>{title}</title>

    <link rel="stylesheet" type="text/css" href="{root_path}main.css">

    {favicon}
    {in_header}

    {before_content}

        {logo}
        {sidebar}

        <form class="search-form js-only">

                <input class="search-input" name="search"
                       autocomplete="off"
                       placeholder="Click or press 'S' to search, '?' for more options..."
                       type="search">

        </form>

{content}

Keyboard shortcuts

?

Show this help dialog

S

Focus the search field

⇤

Move up in search results

⇥

Move down in search results

⏎

Go to active search result

Search tricks

                Prefix searches with a type followed by a colon (e.g.
                fn:) to restrict the search to a given type.

                Accepted types are: fn, mod,
                struct, enum,
                trait, typedef (or
                tdef).

                Search functions by type signature (e.g.
                vec -> usize)

    {after_content}

    {play_js}

"##,
    content   = *t,
    root_path = page.root_path,
    ty        = page.ty,
    logo      = if layout.logo.is_empty() {
        "".to_string()
    } else {
        format!("\
                 ",
                page.root_path, layout.krate,
                layout.logo)
    },
    title     = page.title,
    description = page.description,
    keywords = page.keywords,
    favicon   = if layout.favicon.is_empty() {
        "".to_string()
    } else {
        format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
    },
    in_header = layout.external_html.in_header,
    before_content = layout.external_html.before_content,
    after_content = layout.external_html.after_content,
    sidebar   = *sidebar,
    krate     = layout.krate,
    play_url  = layout.playground_url,
    play_js   = if layout.playground_url.is_empty() {
        "".to_string()
    } else {
        format!(r#""#, page.root_path)
    },
    )
}

pub fn redirect(dst: &mut io::Write, url: &str) -> io::Result<()> {
    //

"##,
    url = url,
    )
}
<|endoftext|>