<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/. */

#![feature(unsafe_destructor, plugin, box_syntax, int_uint)]
#![feature(old_impl_check)]

#![deny(unsafe_blocks)]
#![deny(unused_imports)]
#![deny(unused_variables)]
#![allow(non_snake_case)]
#![allow(missing_copy_implementations)]
#![allow(unstable)]

#![doc="The script crate contains all matters DOM."]

#[macro_use]
extern crate log;

extern crate core;
extern crate devtools_traits;
extern crate cssparser;
extern crate collections;
extern crate geom;
extern crate html5ever;
extern crate encoding;
extern crate hyper;
extern crate js;
extern crate libc;
extern crate msg;
extern crate net;
extern crate serialize;
extern crate time;
extern crate canvas;
extern crate script_traits;
#[no_link] #[plugin] #[macro_use]
extern crate "plugins" as servo_plugins;
extern crate "net" as servo_net;
extern crate util;
#[macro_use]
extern crate style;
extern crate "msg" as servo_msg;
extern crate url;
extern crate uuid;
extern crate string_cache;
#[no_link] #[macro_use] #[plugin]
extern crate string_cache_macros;

pub mod cors;

/// The implementation of the DOM.
#[macro_use]
pub mod dom {
    #[macro_use]
    pub mod macros;

    /// The code to expose the DOM to JavaScript through IDL bindings.
    #[allow(unsafe_blocks)]
    #[deny(missing_docs)]
    pub mod bindings {
        pub mod cell;
        pub mod global;
        pub mod js;
        pub mod refcounted;
        pub mod utils;
        pub mod callback;
        pub mod error;
        pub mod conversions;
        pub mod proxyhandler;
        pub mod str;
        pub mod structuredclone;
        pub mod trace;

        /// Generated JS-Rust bindings.
        #[allow(missing_docs)]
        pub mod codegen {
            #[allow(unrooted_must_root)]
            pub mod Bindings;
            pub mod InterfaceTypes;
            pub mod InheritTypes;
            pub mod PrototypeList;
            pub mod RegisterBindings;
            pub mod UnionTypes;
        }
    }

    #[path="bindings/codegen/InterfaceTypes.rs"]
    pub mod types;

    pub mod activation;
    pub mod attr;
    pub mod blob;
    pub mod browsercontext;
    pub mod canvasrenderingcontext2d;
    pub mod characterdata;
    pub mod cssstyledeclaration;
    pub mod domrect;
    pub mod domrectlist;
    pub mod domstringmap;
    pub mod comment;
    pub mod console;
    mod create;
    pub mod customevent;
    pub mod dedicatedworkerglobalscope;
    pub mod document;
    pub mod documentfragment;
    pub mod documenttype;
    pub mod domexception;
    pub mod domimplementation;
    pub mod domparser;
    pub mod domtokenlist;
    pub mod element;
    pub mod errorevent;
    pub mod event;
    pub mod eventdispatcher;
    pub mod eventtarget;
    pub mod file;
    pub mod formdata;
    pub mod htmlanchorelement;
    pub mod htmlappletelement;
    pub mod htmlareaelement;
    pub mod htmlaudioelement;
    pub mod htmlbaseelement;
    pub mod htmlbodyelement;
    pub mod htmlbrelement;
    pub mod htmlbuttonelement;
    pub mod htmlcanvaselement;
    pub mod htmlcollection;
    pub mod htmldataelement;
    pub mod htmldatalistelement;
    pub mod htmldirectoryelement;
    pub mod htmldivelement;
    pub mod htmldlistelement;
    pub mod htmlelement;
    pub mod htmlembedelement;
    pub mod htmlfieldsetelement;
    pub mod htmlfontelement;
    pub mod htmlformelement;
    pub mod htmlframeelement;
    pub mod htmlframesetelement;
    pub mod htmlheadelement;
    pub mod htmlheadingelement;
    pub mod htmlhrelement;
    pub mod htmlhtmlelement;
    pub mod htmliframeelement;
    pub mod htmlimageelement;
    pub mod htmlinputelement;
    pub mod htmllabelelement;
    pub mod htmllegendelement;
    pub mod htmllielement;
    pub mod htmllinkelement;
    pub mod htmlmapelement;
    pub mod htmlmediaelement;
    pub mod htmlmetaelement;
    pub mod htmlmeterelement;
    pub mod htmlmodelement;
    pub mod htmlobjectelement;
    pub mod htmlolistelement;
    pub mod htmloptgroupelement;
    pub mod htmloptionelement;
    pub mod htmloutputelement;
    pub mod htmlparagraphelement;
    pub mod htmlparamelement;
    pub mod htmlpreelement;
    pub mod htmlprogresselement;
    pub mod htmlquoteelement;
    pub mod htmlscriptelement;
    pub mod htmlselectelement;
    pub mod htmlserializer;
    pub mod htmlspanelement;
    pub mod htmlsourceelement;
    pub mod htmlstyleelement;
    pub mod htmltableelement;
    pub mod htmltablecaptionelement;
    pub mod htmltablecellelement;
    pub mod htmltabledatacellelement;
    pub mod htmltableheadercellelement;
    pub mod htmltablecolelement;
    pub mod htmltablerowelement;
    pub mod htmltablesectionelement;
    pub mod htmltemplateelement;
    pub mod htmltextareaelement;
    pub mod htmltimeelement;
    pub mod htmltitleelement;
    pub mod htmltrackelement;
    pub mod htmlulistelement;
    pub mod htmlvideoelement;
    pub mod htmlunknownelement;
    pub mod keyboardevent;
    pub mod location;
    pub mod messageevent;
    pub mod mouseevent;
    pub mod namednodemap;
    pub mod navigator;
    pub mod navigatorinfo;
    pub mod node;
    pub mod nodeiterator;
    pub mod nodelist;
    pub mod processinginstruction;
    pub mod performance;
    pub mod performancetiming;
    pub mod progressevent;
    pub mod range;
    pub mod screen;
    pub mod servohtmlparser;
    pub mod storage;
    pub mod text;
    pub mod treewalker;
    pub mod uievent;
    pub mod urlhelper;
    pub mod urlsearchparams;
    pub mod validitystate;
    pub mod virtualmethods;
    pub mod websocket;
    pub mod window;
    pub mod worker;
    pub mod workerglobalscope;
    pub mod workerlocation;
    pub mod workernavigator;
    pub mod xmlhttprequest;
    pub mod xmlhttprequesteventtarget;
    pub mod xmlhttprequestupload;

    pub mod testbinding;
}

pub mod parse;

pub mod layout_interface;
pub mod page;
pub mod script_task;
mod timers;
pub mod textinput;
mod devtools;

#[cfg(all(test, target_word_size = "64"))]
mod tests;
<commit_msg>Require snake case in bindings code.<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/. */

#![feature(unsafe_destructor, plugin, box_syntax, int_uint)]
#![feature(old_impl_check)]

#![deny(unsafe_blocks)]
#![deny(unused_imports)]
#![deny(unused_variables)]
#![allow(non_snake_case)]
#![allow(missing_copy_implementations)]
#![allow(unstable)]

#![doc="The script crate contains all matters DOM."]

#[macro_use]
extern crate log;

extern crate core;
extern crate devtools_traits;
extern crate cssparser;
extern crate collections;
extern crate geom;
extern crate html5ever;
extern crate encoding;
extern crate hyper;
extern crate js;
extern crate libc;
extern crate msg;
extern crate net;
extern crate serialize;
extern crate time;
extern crate canvas;
extern crate script_traits;
#[no_link] #[plugin] #[macro_use]
extern crate "plugins" as servo_plugins;
extern crate "net" as servo_net;
extern crate util;
#[macro_use]
extern crate style;
extern crate "msg" as servo_msg;
extern crate url;
extern crate uuid;
extern crate string_cache;
#[no_link] #[macro_use] #[plugin]
extern crate string_cache_macros;

pub mod cors;

/// The implementation of the DOM.
#[macro_use]
pub mod dom {
    #[macro_use]
    pub mod macros;

    /// The code to expose the DOM to JavaScript through IDL bindings.
    #[allow(unsafe_blocks)]
    #[deny(missing_docs, non_snake_case)]
    pub mod bindings {
        pub mod cell;
        pub mod global;
        pub mod js;
        pub mod refcounted;
        pub mod utils;
        pub mod callback;
        pub mod error;
        pub mod conversions;
        pub mod proxyhandler;
        pub mod str;
        pub mod structuredclone;
        pub mod trace;

        /// Generated JS-Rust bindings.
        #[allow(missing_docs, non_snake_case)]
        pub mod codegen {
            #[allow(unrooted_must_root)]
            pub mod Bindings;
            pub mod InterfaceTypes;
            pub mod InheritTypes;
            pub mod PrototypeList;
            pub mod RegisterBindings;
            pub mod UnionTypes;
        }
    }

    #[path="bindings/codegen/InterfaceTypes.rs"]
    pub mod types;

    pub mod activation;
    pub mod attr;
    pub mod blob;
    pub mod browsercontext;
    pub mod canvasrenderingcontext2d;
    pub mod characterdata;
    pub mod cssstyledeclaration;
    pub mod domrect;
    pub mod domrectlist;
    pub mod domstringmap;
    pub mod comment;
    pub mod console;
    mod create;
    pub mod customevent;
    pub mod dedicatedworkerglobalscope;
    pub mod document;
    pub mod documentfragment;
    pub mod documenttype;
    pub mod domexception;
    pub mod domimplementation;
    pub mod domparser;
    pub mod domtokenlist;
    pub mod element;
    pub mod errorevent;
    pub mod event;
    pub mod eventdispatcher;
    pub mod eventtarget;
    pub mod file;
    pub mod formdata;
    pub mod htmlanchorelement;
    pub mod htmlappletelement;
    pub mod htmlareaelement;
    pub mod htmlaudioelement;
    pub mod htmlbaseelement;
    pub mod htmlbodyelement;
    pub mod htmlbrelement;
    pub mod htmlbuttonelement;
    pub mod htmlcanvaselement;
    pub mod htmlcollection;
    pub mod htmldataelement;
    pub mod htmldatalistelement;
    pub mod htmldirectoryelement;
    pub mod htmldivelement;
    pub mod htmldlistelement;
    pub mod htmlelement;
    pub mod htmlembedelement;
    pub mod htmlfieldsetelement;
    pub mod htmlfontelement;
    pub mod htmlformelement;
    pub mod htmlframeelement;
    pub mod htmlframesetelement;
    pub mod htmlheadelement;
    pub mod htmlheadingelement;
    pub mod htmlhrelement;
    pub mod htmlhtmlelement;
    pub mod htmliframeelement;
    pub mod htmlimageelement;
    pub mod htmlinputelement;
    pub mod htmllabelelement;
    pub mod htmllegendelement;
    pub mod htmllielement;
    pub mod htmllinkelement;
    pub mod htmlmapelement;
    pub mod htmlmediaelement;
    pub mod htmlmetaelement;
    pub mod htmlmeterelement;
    pub mod htmlmodelement;
    pub mod htmlobjectelement;
    pub mod htmlolistelement;
    pub mod htmloptgroupelement;
    pub mod htmloptionelement;
    pub mod htmloutputelement;
    pub mod htmlparagraphelement;
    pub mod htmlparamelement;
    pub mod htmlpreelement;
    pub mod htmlprogresselement;
    pub mod htmlquoteelement;
    pub mod htmlscriptelement;
    pub mod htmlselectelement;
    pub mod htmlserializer;
    pub mod htmlspanelement;
    pub mod htmlsourceelement;
    pub mod htmlstyleelement;
    pub mod htmltableelement;
    pub mod htmltablecaptionelement;
    pub mod htmltablecellelement;
    pub mod htmltabledatacellelement;
    pub mod htmltableheadercellelement;
    pub mod htmltablecolelement;
    pub mod htmltablerowelement;
    pub mod htmltablesectionelement;
    pub mod htmltemplateelement;
    pub mod htmltextareaelement;
    pub mod htmltimeelement;
    pub mod htmltitleelement;
    pub mod htmltrackelement;
    pub mod htmlulistelement;
    pub mod htmlvideoelement;
    pub mod htmlunknownelement;
    pub mod keyboardevent;
    pub mod location;
    pub mod messageevent;
    pub mod mouseevent;
    pub mod namednodemap;
    pub mod navigator;
    pub mod navigatorinfo;
    pub mod node;
    pub mod nodeiterator;
    pub mod nodelist;
    pub mod processinginstruction;
    pub mod performance;
    pub mod performancetiming;
    pub mod progressevent;
    pub mod range;
    pub mod screen;
    pub mod servohtmlparser;
    pub mod storage;
    pub mod text;
    pub mod treewalker;
    pub mod uievent;
    pub mod urlhelper;
    pub mod urlsearchparams;
    pub mod validitystate;
    pub mod virtualmethods;
    pub mod websocket;
    pub mod window;
    pub mod worker;
    pub mod workerglobalscope;
    pub mod workerlocation;
    pub mod workernavigator;
    pub mod xmlhttprequest;
    pub mod xmlhttprequesteventtarget;
    pub mod xmlhttprequestupload;

    pub mod testbinding;
}

pub mod parse;

pub mod layout_interface;
pub mod page;
pub mod script_task;
mod timers;
pub mod textinput;
mod devtools;

#[cfg(all(test, target_word_size = "64"))]
mod tests;
<|endoftext|>


<commit_before>// Copyright (c) Carl-Erwin Griffith
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER

// {
//   Derived from : Bjoern Hoehrmann work
//   Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
//   See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.

const UTF8_ACCEPT: u32 = 0;
const UTF8_REJECT: u32 = 1;

#[rustfmt::skip]
static UTF8D: &'static [u8] = &[
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
  8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
  0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
  0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
  0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
  1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
  1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
  1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
];

/*
    state UTF8_ACCEPT => initial state or decoding successful
    state UTF8_REJECT => error
    state other => intermediate states need more inputs
*/
#[inline]
pub fn decode_byte(state: u32, byte: u8, codep: &mut u32) -> u32 {
    let cp_type = u32::from(UTF8D[byte as usize]);

    *codep = if state != UTF8_ACCEPT {
        u32::from(byte & 0x3f) | (*codep << 6)
    } else {
        (0xff >> cp_type) & u32::from(byte)
    };

    u32::from(UTF8D[256 + (state * 16) as usize + cp_type as usize])
}

// }

#[inline]
pub fn is_codepoint_start(byte: u8) -> bool {
    if byte < 0x80 {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xE0 && byte <= 0xEC {
        return true;
    }

    if byte >= 0xED && byte <= 0xEF {
        return true;
    }

    if byte >= 0xF0 && byte <= 0xF4 {
        return true;
    }

    false
}

// return 0 on error, or the number of written bytes
pub fn encode(codepoint: u32, out: &mut [u8; 4]) -> usize {
    if codepoint < 0x80 {
        out[0] = codepoint as u8;
        return 1;
    }

    if codepoint < 0x800 {
        out[0] = 0xC0 | (codepoint >> 6) as u8;
        out[1] = 0x80 | (codepoint & 0x3F) as u8;
        return 2;
    }

    if codepoint < 0xFFFF {
        out[0] = 0xE0 | (codepoint >> 12) as u8;
        out[1] = 0x80 | (codepoint >> 6) as u8;
        out[2] = 0x80 | (codepoint & 0x3F) as u8;
        return 3;
    }

    if codepoint < 0x0010_FFFF {
        out[0] = 0xF0 | (codepoint >> 18) as u8;
        out[1] = 0x80 | (codepoint >> 12) as u8;
        out[2] = 0x80 | (codepoint >> 6) as u8;
        out[3] = 0x80 | (codepoint & 0x3F) as u8;
        return 4;
    }

    0
}

// TODO: change this with temporary (cp, offset, size) until from_offset
pub fn get_previous_codepoint_start(data: &[u8], from_offset: u64) -> u64 {
    //                 cp    size   offset
    let mut cp_info: [(char, usize, u64); 8] = [
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
    ];
    let mut nr_cpinfo = 0;

    // rewind up to 4 bytes
    // and decode forward / save offset
    let mut off = if from_offset > 4 { from_offset - 4 } else { 0 };
    while off < from_offset {
        let (cp, _, size) = get_codepoint(data, off);

        cp_info[nr_cpinfo] = (cp, size, off);
        nr_cpinfo += 1;

        off += size as u64;
    }

    if nr_cpinfo != 0 {
        cp_info[nr_cpinfo - 1].2
    } else {
        from_offset
    }
}

pub fn get_next_codepoint_start(data: &[u8], from_offset: u64) -> u64 {
    let (_, _, size) = get_codepoint(data, from_offset);
    from_offset + size as u64
}

pub fn get_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {
    let mut state = 0;
    let mut codep = 0;
    let mut size = 0;

    for b in data.iter().skip(from_offset as usize) {
        size += 1;
        state = decode_byte(state, *b, &mut codep);
        match state {
            UTF8_ACCEPT => {
                break;
            }

            UTF8_REJECT => {
                // decode error : invalid sequence
                codep = 0xfffd;
                size = 1; // force restart @ next byte
                break;
            }
            _ => {}
        }
    }

    // TODO return Result<(char, usize), status> -> state != 1|0 -> need mode data
    (::core::codec::text::u32_to_char(codep), from_offset, size)
}

pub fn get_prev_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {
    let offset = get_previous_codepoint_start(data, from_offset);
    get_codepoint(data, offset)
}

#[test]
fn test_codec_encode() {
    let expect_cp: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    let mut mut_cp: [u8; 4] = [0x00, 0x00, 0x00, 0x00];

    let n = encode(0x20ac as u32, &mut mut_cp);
    assert_eq!(n, 3);
    assert_eq!(mut_cp, expect_cp);
}

#[test]
fn test_codec_decode() {
    use core::codec::text::u32_to_char;

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    let sequence: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    for b in &sequence {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(state, *b, &mut codep);
        match state {
            UTF8_ACCEPT => {
                break;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence");
                break;
            }
            _ => {
                continue;
            }
        }
    }

    println!("decoded codepoint value {:x}", codep);
    let c = u32_to_char(codep);
    println!("decoded codepoint char {}", c);

    assert_eq!(codep, 0x20ac);
}

#[test]
fn test2_codec_decode() {
    let data: [u8; 27] = [
        0xe2, 0x82, 0xac, 0xe2, 0x82, 0x61, 0x0a, 0x82, 0xac, 0xe2, 0x82, 0x61, 0x0a, 0xac, 0xe2,
        0x82, 0x61, 0x0a, 0xe2, 0x82, 0x61, 0x0a, 0x82, 0x61, 0x0a, 0x61, 0x0a,
    ];

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    for b in &data {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(state, *b, &mut codep);
        println!("state  '{}'", state);
        match state {
            UTF8_ACCEPT => {
                println!("decoded cp = '{:?}'", codep);
                state = 0;
                codep = 0;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence, restart");
                state = 0;
                codep = 0;
                state = decode_byte(state, *b, &mut codep);
                match state {
                    UTF8_ACCEPT => {
                        println!("decoded cp = '{:?}'", codep);
                        state = 0;
                        codep = 0;
                    }
                    UTF8_REJECT => {
                        println!("invalid utf8 sequence, restart");
                        state = 0;
                        codep = 0;
                    }
                    _ => {}
                }
            }

            _ => {
                continue;
            }
        }
    }
}

#[test]
fn test_backward_decode() {
    let data: [u8; 24] = [
        0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac,
        0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac,
    ];

    let mut start_offset: u64 = 6;
    println!(
        "start_offset {} byte is '{:x}'",
        start_offset, data[start_offset as usize] as u32
    );

    let off = get_previous_codepoint_start(&data, start_offset as u64);
    println!(
        "start_offset({}) - off({}) = {}",
        start_offset,
        off,
        start_offset - off
    );
    let delta = start_offset - off;
    start_offset -= delta;

    println!("new start_offset({})", start_offset);
}
<commit_msg>add comment<commit_after>// Copyright (c) Carl-Erwin Griffith
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER

// {
//   Derived from : Bjoern Hoehrmann work
//   Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
//   See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.

const UTF8_ACCEPT: u32 = 0;
const UTF8_REJECT: u32 = 1;

#[rustfmt::skip]
static UTF8D: &'static [u8] = &[
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
  8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
  0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
  0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
  0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
  1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
  1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
  1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
];

/*
    state UTF8_ACCEPT => initial state or decoding successful
    state UTF8_REJECT => error
    state other => intermediate states need more inputs
*/
#[inline]
pub fn decode_byte(state: u32, byte: u8, codep: &mut u32) -> u32 {
    let cp_type = u32::from(UTF8D[byte as usize]);

    *codep = if state != UTF8_ACCEPT {
        u32::from(byte & 0x3f) | (*codep << 6)
    } else {
        (0xff >> cp_type) & u32::from(byte)
    };

    u32::from(UTF8D[256 + (state * 16) as usize + cp_type as usize])
}

// } end-of-derived code

#[inline]
pub fn is_codepoint_start(byte: u8) -> bool {
    if byte < 0x80 {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xE0 && byte <= 0xEC {
        return true;
    }

    if byte >= 0xED && byte <= 0xEF {
        return true;
    }

    if byte >= 0xF0 && byte <= 0xF4 {
        return true;
    }

    false
}

// return 0 on error, or the number of written bytes
pub fn encode(codepoint: u32, out: &mut [u8; 4]) -> usize {
    if codepoint < 0x80 {
        out[0] = codepoint as u8;
        return 1;
    }

    if codepoint < 0x800 {
        out[0] = 0xC0 | (codepoint >> 6) as u8;
        out[1] = 0x80 | (codepoint & 0x3F) as u8;
        return 2;
    }

    if codepoint < 0xFFFF {
        out[0] = 0xE0 | (codepoint >> 12) as u8;
        out[1] = 0x80 | (codepoint >> 6) as u8;
        out[2] = 0x80 | (codepoint & 0x3F) as u8;
        return 3;
    }

    if codepoint < 0x0010_FFFF {
        out[0] = 0xF0 | (codepoint >> 18) as u8;
        out[1] = 0x80 | (codepoint >> 12) as u8;
        out[2] = 0x80 | (codepoint >> 6) as u8;
        out[3] = 0x80 | (codepoint & 0x3F) as u8;
        return 4;
    }

    0
}

// TODO: change this with temporary (cp, offset, size) until from_offset
pub fn get_previous_codepoint_start(data: &[u8], from_offset: u64) -> u64 {
    //                 cp    size   offset
    let mut cp_info: [(char, usize, u64); 8] = [
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
    ];
    let mut nr_cpinfo = 0;

    // rewind up to 4 bytes
    // and decode forward / save offset
    let mut off = if from_offset > 4 { from_offset - 4 } else { 0 };
    while off < from_offset {
        let (cp, _, size) = get_codepoint(data, off);

        cp_info[nr_cpinfo] = (cp, size, off);
        nr_cpinfo += 1;

        off += size as u64;
    }

    if nr_cpinfo != 0 {
        cp_info[nr_cpinfo - 1].2
    } else {
        from_offset
    }
}

pub fn get_next_codepoint_start(data: &[u8], from_offset: u64) -> u64 {
    let (_, _, size) = get_codepoint(data, from_offset);
    from_offset + size as u64
}

pub fn get_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {
    let mut state = 0;
    let mut codep = 0;
    let mut size = 0;

    for b in data.iter().skip(from_offset as usize) {
        size += 1;
        state = decode_byte(state, *b, &mut codep);
        match state {
            UTF8_ACCEPT => {
                break;
            }

            UTF8_REJECT => {
                // decode error : invalid sequence
                codep = 0xfffd;
                size = 1; // force restart @ next byte
                break;
            }
            _ => {}
        }
    }

    // TODO return Result<(char, usize), status> -> state != 1|0 -> need mode data
    (::core::codec::text::u32_to_char(codep), from_offset, size)
}

pub fn get_prev_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {
    let offset = get_previous_codepoint_start(data, from_offset);
    get_codepoint(data, offset)
}

#[test]
fn test_codec_encode() {
    let expect_cp: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    let mut mut_cp: [u8; 4] = [0x00, 0x00, 0x00, 0x00];

    let n = encode(0x20ac as u32, &mut mut_cp);
    assert_eq!(n, 3);
    assert_eq!(mut_cp, expect_cp);
}

#[test]
fn test_codec_decode() {
    use core::codec::text::u32_to_char;

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    let sequence: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    for b in &sequence {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(state, *b, &mut codep);
        match state {
            UTF8_ACCEPT => {
                break;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence");
                break;
            }
            _ => {
                continue;
            }
        }
    }

    println!("decoded codepoint value {:x}", codep);
    let c = u32_to_char(codep);
    println!("decoded codepoint char {}", c);

    assert_eq!(codep, 0x20ac);
}

#[test]
fn test2_codec_decode() {
    let data: [u8; 27] = [
        0xe2, 0x82, 0xac, 0xe2, 0x82, 0x61, 0x0a, 0x82, 0xac, 0xe2, 0x82, 0x61, 0x0a, 0xac, 0xe2,
        0x82, 0x61, 0x0a, 0xe2, 0x82, 0x61, 0x0a, 0x82, 0x61, 0x0a, 0x61, 0x0a,
    ];

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    for b in &data {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(state, *b, &mut codep);
        println!("state  '{}'", state);
        match state {
            UTF8_ACCEPT => {
                println!("decoded cp = '{:?}'", codep);
                state = 0;
                codep = 0;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence, restart");
                state = 0;
                codep = 0;
                state = decode_byte(state, *b, &mut codep);
                match state {
                    UTF8_ACCEPT => {
                        println!("decoded cp = '{:?}'", codep);
                        state = 0;
                        codep = 0;
                    }
                    UTF8_REJECT => {
                        println!("invalid utf8 sequence, restart");
                        state = 0;
                        codep = 0;
                    }
                    _ => {}
                }
            }

            _ => {
                continue;
            }
        }
    }
}

#[test]
fn test_backward_decode() {
    let data: [u8; 24] = [
        0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac,
        0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac,
    ];

    let mut start_offset: u64 = 6;
    println!(
        "start_offset {} byte is '{:x}'",
        start_offset, data[start_offset as usize] as u32
    );

    let off = get_previous_codepoint_start(&data, start_offset as u64);
    println!(
        "start_offset({}) - off({}) = {}",
        start_offset,
        off,
        start_offset - off
    );
    let delta = start_offset - off;
    start_offset -= delta;

    println!("new start_offset({})", start_offset);
}
<|endoftext|>


<commit_before>pub fn query_operator(qop: &String) -> Result<String, String> {
    match &qop[..] {
        "$eq" => Ok("=".to_string()),
        "$ne" => Ok("!=".to_string()),
        "$gt" => Ok(">".to_string()),
        "$lt" => Ok("<".to_string()),
        "$gte" => Ok(">=".to_string()),
        "$lte" => Ok("<=".to_string()),
        "$in" => Ok("IN".to_string()),
        "$nin" => Ok("NOT IN".to_string()),
        "$notnull" => Ok("IS NOT NULL".to_string()),
        "$null" => Ok("IS NULL".to_string()),
         _ => Err(format!("operator {} not found", qop)),
    }
}

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

    #[test]
    fn it_get_opetators() {
        use std::collections::HashMap;

        let mut test_cases = HashMap::new();
        test_cases.insert("$eq", "=");
        test_cases.insert("$ne", "!=");
        test_cases.insert("$gt", ">");
        test_cases.insert("$gte", ">=");
        test_cases.insert("$lt", "<");
        test_cases.insert("$lte", "<=");
        test_cases.insert("$in", "IN");
        test_cases.insert("$nin", "NOT IN");
        test_cases.insert("$notnull", "IS NOT NULL");
        test_cases.insert("$null", "IS NULL");

        for (op, expected) in &test_cases {
            match query_operator(&op.to_string()) {
                Ok(x) => assert_eq!(expected.to_string(), x),
                Err(e) => assert_eq!("", e)
            }
        }
    }

    #[test]
    fn it_get_opetators_error() {
        let invalid = "!tn".to_string();
        match query_operator(&invalid) {
            Ok(_) => println!("no result"),
            Err(e) => assert_eq!(format!("operator {} not found", invalid), e)
        }
        // assert_eq!(expected, query_operatorv2(&invalid));
    }
}
<commit_msg>Add tests to ext_where<commit_after>extern crate rocket;

use rocket::{Request, Data, Outcome};
use rocket::data::{self, FromData};
use rocket::Outcome::*;
use std::collections::HashMap;

pub struct WhereStructResult {
    sql: String, values: Vec<String>,
}

// My Results
type QueryOpResult = Result<String, String>;
type WhereResult = Result<WhereStructResult, String>;

// implement QueryString
pub struct QueryString {
    query: HashMap<String, String>
}

impl FromData for QueryString {
    type Error = String;

    fn from_data(req: &Request, _: Data) -> data::Outcome<Self, String> {
        let querystring: Vec<&str> = req.uri().query()
            .unwrap().split("&").collect();
        let mut result: QueryString = QueryString{query: HashMap::new()};

        for qs in querystring {
            let kv: Vec<&str> = qs.split("=").collect();
            // [0] is key, [1] is value
            result.query.insert(kv[0].to_string(), kv[1].to_string());
        }
        Success(result)
    }
}

pub fn query_operator(qop: &String) -> QueryOpResult {
    match &qop[..] {
        "$eq" => Ok("=".to_string()),
        "$ne" => Ok("!=".to_string()),
        "$gt" => Ok(">".to_string()),
        "$lt" => Ok("<".to_string()),
        "$gte" => Ok(">=".to_string()),
        "$lte" => Ok("<=".to_string()),
        "$in" => Ok("IN".to_string()),
        "$nin" => Ok("NOT IN".to_string()),
        "$notnull" => Ok("IS NOT NULL".to_string()),
        "$null" => Ok("IS NULL".to_string()),
         _ => Err(format!("operator {} not found", qop)),
    }
}

// Get request and return chuck WHERE statement with values
pub fn ext_where(_: &Request) -> WhereResult {
    Ok(WhereStructResult {
        sql: "WHERE user_id=$1".to_string(),
        values: vec!["5".to_string()],
    })
}

#[cfg(test)]
mod tests {
    use super::{rocket};
    use rocket::local::Client;
    use rocket::http::ContentType;
    use postgres::commands::*;

    #[test]
    fn get_opetators() {
        use std::collections::HashMap;

        let mut test_cases = HashMap::new();
        test_cases.insert("$eq", "=");
        test_cases.insert("$ne", "!=");
        test_cases.insert("$gt", ">");
        test_cases.insert("$gte", ">=");
        test_cases.insert("$lt", "<");
        test_cases.insert("$lte", "<=");
        test_cases.insert("$in", "IN");
        test_cases.insert("$nin", "NOT IN");
        test_cases.insert("$notnull", "IS NOT NULL");
        test_cases.insert("$null", "IS NULL");

        for (op, expected) in &test_cases {
            match query_operator(&op.to_string()) {
                Ok(x) => assert_eq!(expected.to_string(), x),
                Err(e) => assert_eq!("", e)
            }
        }
    }

    #[test]
    fn get_opetators_error() {
        let invalid = "!tn".to_string();
        match query_operator(&invalid) {
            Ok(_) => println!("no result"),
            Err(e) => assert_eq!(format!("operator {} not found", invalid), e)
        }
    }

    #[test]
    fn where_by_request() {
        let client = Client::new(rocket::ignite())
            .expect("valid rocket");
        let req = client.get("/db/sch/tbl?user_id=5&name=cool")
            .header(ContentType::JSON);
        let result = ext_where(req.inner())
            .unwrap();

        assert_eq!(result.sql, "WHERE user_id=$1".to_string());
        assert_eq!(result.values, vec!["5".to_string()])
    }
}
<|endoftext|>


<commit_before>// @has field/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/ops/range/struct.Range.html#structfield.start"]' 'start'
// @has field/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found'
//! [start][std::ops::Range::start]
//! [not_found][std::io::ErrorKind::NotFound]
<commit_msg>use channel-relative urls in rustdoc/intra-doc/field.rs<commit_after>// @has field/index.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start'
// @has field/index.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found'
//! [start][std::ops::Range::start]
//! [not_found][std::io::ErrorKind::NotFound]
<|endoftext|>


<commit_before>use crate::spec::{CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
use crate::spec::{Target, TargetOptions};

pub fn target() -> Target {
    Target {
        data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
        llvm_target: "riscv64".to_string(),
        pointer_width: 64,
        arch: "riscv64".to_string(),

        options: TargetOptions {
            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
            linker: Some("rust-lld".to_string()),
            cpu: "generic-rv64".to_string(),
            max_atomic_width: Some(64),
            atomic_cas: true,
            features: "+m,+a,+f,+d,+c".to_string(),
            executables: true,
            panic_strategy: PanicStrategy::Abort,
            relocation_model: RelocModel::Static,
            code_model: Some(CodeModel::Medium),
            emit_debug_gdb_scripts: false,
            unsupported_abis: super::riscv_base::unsupported_abis(),
            eh_frame_header: false,
            ..Default::default()
        },
    }
}
<commit_msg>Rollup merge of #83231 - DieracDelta:lp64d-abi-for-riscvgc-unknown-none-elf, r=estebank<commit_after>use crate::spec::{CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
use crate::spec::{Target, TargetOptions};

pub fn target() -> Target {
    Target {
        data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
        llvm_target: "riscv64".to_string(),
        pointer_width: 64,
        arch: "riscv64".to_string(),

        options: TargetOptions {
            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
            linker: Some("rust-lld".to_string()),
            llvm_abiname: "lp64d".to_string(),
            cpu: "generic-rv64".to_string(),
            max_atomic_width: Some(64),
            atomic_cas: true,
            features: "+m,+a,+f,+d,+c".to_string(),
            executables: true,
            panic_strategy: PanicStrategy::Abort,
            relocation_model: RelocModel::Static,
            code_model: Some(CodeModel::Medium),
            emit_debug_gdb_scripts: false,
            unsupported_abis: super::riscv_base::unsupported_abis(),
            eh_frame_header: false,
            ..Default::default()
        },
    }
}
<|endoftext|>


<commit_before>use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg};
use rustc_ast::ast::LitKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::{AssocItemKind, BinOpKind, Expr, ExprKind, ImplItemRef, Item, ItemKind, TraitItemRef};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::{Span, Spanned, Symbol};

declare_clippy_lint! {
    /// **What it does:** Checks for getting the length of something via `.len()`
    /// just to compare to zero, and suggests using `.is_empty()` where applicable.
    ///
    /// **Why is this bad?** Some structures can answer `.is_empty()` much faster
    /// than calculating their length. So it is good to get into the habit of using
    /// `.is_empty()`, and having it is cheap.
    /// Besides, it makes the intent clearer than a manual comparison in some contexts.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// if x.len() == 0 {
    ///     ..
    /// }
    /// if y.len() != 0 {
    ///     ..
    /// }
    /// ```
    /// instead use
    /// ```ignore
    /// if x.is_empty() {
    ///     ..
    /// }
    /// if !y.is_empty() {
    ///     ..
    /// }
    /// ```
    pub LEN_ZERO,
    style,
    "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead"
}

declare_clippy_lint! {
    /// **What it does:** Checks for items that implement `.len()` but not
    /// `.is_empty()`.
    ///
    /// **Why is this bad?** It is good custom to have both methods, because for
    /// some data structures, asking about the length will be a costly operation,
    /// whereas `.is_empty()` can usually answer in constant time. Also it used to
    /// lead to false positives on the [`len_zero`](#len_zero) lint – currently that
    /// lint will ignore such entities.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// impl X {
    ///     pub fn len(&self) -> usize {
    ///         ..
    ///     }
    /// }
    /// ```
    pub LEN_WITHOUT_IS_EMPTY,
    style,
    "traits or impls with a public `len` method but no corresponding `is_empty` method"
}

declare_clippy_lint! {
    /// **What it does:** Checks for comparing to an empty slice such as "" or [],`
    /// and suggests using `.is_empty()` where applicable.
    ///
    /// **Why is this bad?** Some structures can answer `.is_empty()` much faster
    /// than checking for equality. So it is good to get into the habit of using
    /// `.is_empty()`, and having it is cheap.
    /// Besides, it makes the intent clearer than a manual comparison in some contexts.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```ignore
    /// if s == "" {
    ///     ..
    /// }

    /// if arr == [] {
    ///     ..
    /// }
    /// ```
    /// Use instead:
    /// ```ignore
    /// if s.is_empty() {
    ///     ..
    /// }

    /// if arr.is_empty() {
    ///     ..
    /// }
    /// ```
    pub COMPARISON_TO_EMPTY,
    style,
    "checking `x == \"\"` or `x == []` (or similar) when `.is_empty()` could be used instead"
}

declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMPTY]);

impl<'tcx> LateLintPass<'tcx> for LenZero {
    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
        if item.span.from_expansion() {
            return;
        }

        match item.kind {
            ItemKind::Trait(_, _, _, _, ref trait_items) => check_trait_items(cx, item, trait_items),
            ItemKind::Impl {
                of_trait: None,
                items: ref impl_items,
                ..
            } => check_impl_items(cx, item, impl_items),
            _ => (),
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if expr.span.from_expansion() {
            return;
        }

        if let ExprKind::Binary(Spanned { node: cmp, .. }, ref left, ref right) = expr.kind {
            match cmp {
                BinOpKind::Eq => {
                    check_cmp(cx, expr.span, left, right, "", 0); // len == 0
                    check_cmp(cx, expr.span, right, left, "", 0); // 0 == len
                },
                BinOpKind::Ne => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len != 0
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 != len
                },
                BinOpKind::Gt => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len > 0
                    check_cmp(cx, expr.span, right, left, "", 1); // 1 > len
                },
                BinOpKind::Lt => {
                    check_cmp(cx, expr.span, left, right, "", 1); // len < 1
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 < len
                },
                BinOpKind::Ge => check_cmp(cx, expr.span, left, right, "!", 1), // len >= 1
                BinOpKind::Le => check_cmp(cx, expr.span, right, left, "!", 1), // 1 <= len
                _ => (),
            }
        }
    }
}

fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items: &[TraitItemRef]) {
    fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: &str) -> bool {
        item.ident.name.as_str() == name
            && if let AssocItemKind::Fn { has_self } = item.kind {
                has_self && {
                    let did = cx.tcx.hir().local_def_id(item.id.hir_id);
                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
                }
            } else {
                false
            }
    }

    // fill the set with current and super traits
    fn fill_trait_set(traitt: DefId, set: &mut FxHashSet<DefId>, cx: &LateContext<'_>) {
        if set.insert(traitt) {
            for supertrait in rustc_trait_selection::traits::supertrait_def_ids(cx.tcx, traitt) {
                fill_trait_set(supertrait, set, cx);
            }
        }
    }

    if cx.access_levels.is_exported(visited_trait.hir_id) && trait_items.iter().any(|i| is_named_self(cx, i, "len")) {
        let mut current_and_super_traits = FxHashSet::default();
        let visited_trait_def_id = cx.tcx.hir().local_def_id(visited_trait.hir_id);
        fill_trait_set(visited_trait_def_id.to_def_id(), &mut current_and_super_traits, cx);

        let is_empty_method_found = current_and_super_traits
            .iter()
            .flat_map(|&i| cx.tcx.associated_items(i).in_definition_order())
            .any(|i| {
                i.kind == ty::AssocKind::Fn
                    && i.fn_has_self_parameter
                    && i.ident.name == sym!(is_empty)
                    && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
            });

        if !is_empty_method_found {
            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                visited_trait.span,
                &format!(
                    "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
                    visited_trait.ident.name
                ),
            );
        }
    }
}

fn check_impl_items(cx: &LateContext<'_>, item: &Item<'_>, impl_items: &[ImplItemRef<'_>]) {
    fn is_named_self(cx: &LateContext<'_>, item: &ImplItemRef<'_>, name: &str) -> bool {
        item.ident.name.as_str() == name
            && if let AssocItemKind::Fn { has_self } = item.kind {
                has_self && {
                    let did = cx.tcx.hir().local_def_id(item.id.hir_id);
                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
                }
            } else {
                false
            }
    }

    let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) {
        if cx.access_levels.is_exported(is_empty.id.hir_id) {
            return;
        } else {
            "a private"
        }
    } else {
        "no corresponding"
    };

    if let Some(i) = impl_items.iter().find(|i| is_named_self(cx, i, "len")) {
        if cx.access_levels.is_exported(i.id.hir_id) {
            let def_id = cx.tcx.hir().local_def_id(item.hir_id);
            let ty = cx.tcx.type_of(def_id);

            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                item.span,
                &format!(
                    "item `{}` has a public `len` method but {} `is_empty` method",
                    ty, is_empty
                ),
            );
        }
    }
}

fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
    if let (&ExprKind::MethodCall(ref method_path, _, ref args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind)
    {
        // check if we are in an is_empty() method
        if let Some(name) = get_item_name(cx, method) {
            if name.as_str() == "is_empty" {
                return;
            }
        }

        check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to)
    } else {
        check_empty_expr(cx, span, method, lit, op)
    }
}

fn check_len(
    cx: &LateContext<'_>,
    span: Span,
    method_name: Symbol,
    args: &[Expr<'_>],
    lit: &LitKind,
    op: &str,
    compare_to: u32,
) {
    if let LitKind::Int(lit, _) = *lit {
        // check if length is compared to the specified number
        if lit != u128::from(compare_to) {
            return;
        }

        if method_name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) {
            let mut applicability = Applicability::MachineApplicable;
            span_lint_and_sugg(
                cx,
                LEN_ZERO,
                span,
                &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
                &format!("using `{}is_empty` is clearer and more explicit", op),
                format!(
                    "{}{}.is_empty()",
                    op,
                    snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
                ),
                applicability,
            );
        }
    }
}

fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Expr<'_>, op: &str) {
    if (is_empty_array(lit2) || is_empty_string(lit2)) && has_is_empty(cx, lit1) {
        let mut applicability = Applicability::MachineApplicable;
        span_lint_and_sugg(
            cx,
            COMPARISON_TO_EMPTY,
            span,
            "comparison to empty slice",
            &format!("using `{}is_empty` is clearer and more explicit", op),
            format!(
                "{}{}.is_empty()",
                op,
                snippet_with_applicability(cx, lit1.span, "_", &mut applicability)
            ),
            applicability,
        );
    }
}

fn is_empty_string(expr: &Expr<'_>) -> bool {
    if let ExprKind::Lit(ref lit) = expr.kind {
        if let LitKind::Str(lit, _) = lit.node {
            let lit = lit.as_str();
            return lit == "";
        }
    }
    false
}

fn is_empty_array(expr: &Expr<'_>) -> bool {
    if let ExprKind::Array(ref arr) = expr.kind {
        return arr.is_empty();
    }
    false
}

/// Checks if this type has an `is_empty` method.
fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
    /// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
    fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
        if let ty::AssocKind::Fn = item.kind {
            if item.ident.name.as_str() == "is_empty" {
                let sig = cx.tcx.fn_sig(item.def_id);
                let ty = sig.skip_binder();
                ty.inputs().len() == 1
            } else {
                false
            }
        } else {
            false
        }
    }

    /// Checks the inherent impl's items for an `is_empty(self)` method.
    fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
        cx.tcx.inherent_impls(id).iter().any(|imp| {
            cx.tcx
                .associated_items(*imp)
                .in_definition_order()
                .any(|item| is_is_empty(cx, &item))
        })
    }

    let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
    match ty.kind() {
        ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| {
            cx.tcx
                .associated_items(principal.def_id())
                .in_definition_order()
                .any(|item| is_is_empty(cx, &item))
        }),
        ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
        ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
        ty::Array(..) | ty::Slice(..) | ty::Str => true,
        _ => false,
    }
}
<commit_msg>Remove empty lines in doc comment<commit_after>use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg};
use rustc_ast::ast::LitKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::{AssocItemKind, BinOpKind, Expr, ExprKind, ImplItemRef, Item, ItemKind, TraitItemRef};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::{Span, Spanned, Symbol};

declare_clippy_lint! {
    /// **What it does:** Checks for getting the length of something via `.len()`
    /// just to compare to zero, and suggests using `.is_empty()` where applicable.
    ///
    /// **Why is this bad?** Some structures can answer `.is_empty()` much faster
    /// than calculating their length. So it is good to get into the habit of using
    /// `.is_empty()`, and having it is cheap.
    /// Besides, it makes the intent clearer than a manual comparison in some contexts.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// if x.len() == 0 {
    ///     ..
    /// }
    /// if y.len() != 0 {
    ///     ..
    /// }
    /// ```
    /// instead use
    /// ```ignore
    /// if x.is_empty() {
    ///     ..
    /// }
    /// if !y.is_empty() {
    ///     ..
    /// }
    /// ```
    pub LEN_ZERO,
    style,
    "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead"
}

declare_clippy_lint! {
    /// **What it does:** Checks for items that implement `.len()` but not
    /// `.is_empty()`.
    ///
    /// **Why is this bad?** It is good custom to have both methods, because for
    /// some data structures, asking about the length will be a costly operation,
    /// whereas `.is_empty()` can usually answer in constant time. Also it used to
    /// lead to false positives on the [`len_zero`](#len_zero) lint – currently that
    /// lint will ignore such entities.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// impl X {
    ///     pub fn len(&self) -> usize {
    ///         ..
    ///     }
    /// }
    /// ```
    pub LEN_WITHOUT_IS_EMPTY,
    style,
    "traits or impls with a public `len` method but no corresponding `is_empty` method"
}

declare_clippy_lint! {
    /// **What it does:** Checks for comparing to an empty slice such as "" or [],`
    /// and suggests using `.is_empty()` where applicable.
    ///
    /// **Why is this bad?** Some structures can answer `.is_empty()` much faster
    /// than checking for equality. So it is good to get into the habit of using
    /// `.is_empty()`, and having it is cheap.
    /// Besides, it makes the intent clearer than a manual comparison in some contexts.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```ignore
    /// if s == "" {
    ///     ..
    /// }
    ///
    /// if arr == [] {
    ///     ..
    /// }
    /// ```
    /// Use instead:
    /// ```ignore
    /// if s.is_empty() {
    ///     ..
    /// }
    ///
    /// if arr.is_empty() {
    ///     ..
    /// }
    /// ```
    pub COMPARISON_TO_EMPTY,
    style,
    "checking `x == \"\"` or `x == []` (or similar) when `.is_empty()` could be used instead"
}

declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMPTY]);

impl<'tcx> LateLintPass<'tcx> for LenZero {
    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
        if item.span.from_expansion() {
            return;
        }

        match item.kind {
            ItemKind::Trait(_, _, _, _, ref trait_items) => check_trait_items(cx, item, trait_items),
            ItemKind::Impl {
                of_trait: None,
                items: ref impl_items,
                ..
            } => check_impl_items(cx, item, impl_items),
            _ => (),
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if expr.span.from_expansion() {
            return;
        }

        if let ExprKind::Binary(Spanned { node: cmp, .. }, ref left, ref right) = expr.kind {
            match cmp {
                BinOpKind::Eq => {
                    check_cmp(cx, expr.span, left, right, "", 0); // len == 0
                    check_cmp(cx, expr.span, right, left, "", 0); // 0 == len
                },
                BinOpKind::Ne => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len != 0
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 != len
                },
                BinOpKind::Gt => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len > 0
                    check_cmp(cx, expr.span, right, left, "", 1); // 1 > len
                },
                BinOpKind::Lt => {
                    check_cmp(cx, expr.span, left, right, "", 1); // len < 1
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 < len
                },
                BinOpKind::Ge => check_cmp(cx, expr.span, left, right, "!", 1), // len >= 1
                BinOpKind::Le => check_cmp(cx, expr.span, right, left, "!", 1), // 1 <= len
                _ => (),
            }
        }
    }
}

fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items: &[TraitItemRef]) {
    fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: &str) -> bool {
        item.ident.name.as_str() == name
            && if let AssocItemKind::Fn { has_self } = item.kind {
                has_self && {
                    let did = cx.tcx.hir().local_def_id(item.id.hir_id);
                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
                }
            } else {
                false
            }
    }

    // fill the set with current and super traits
    fn fill_trait_set(traitt: DefId, set: &mut FxHashSet<DefId>, cx: &LateContext<'_>) {
        if set.insert(traitt) {
            for supertrait in rustc_trait_selection::traits::supertrait_def_ids(cx.tcx, traitt) {
                fill_trait_set(supertrait, set, cx);
            }
        }
    }

    if cx.access_levels.is_exported(visited_trait.hir_id) && trait_items.iter().any(|i| is_named_self(cx, i, "len")) {
        let mut current_and_super_traits = FxHashSet::default();
        let visited_trait_def_id = cx.tcx.hir().local_def_id(visited_trait.hir_id);
        fill_trait_set(visited_trait_def_id.to_def_id(), &mut current_and_super_traits, cx);

        let is_empty_method_found = current_and_super_traits
            .iter()
            .flat_map(|&i| cx.tcx.associated_items(i).in_definition_order())
            .any(|i| {
                i.kind == ty::AssocKind::Fn
                    && i.fn_has_self_parameter
                    && i.ident.name == sym!(is_empty)
                    && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
            });

        if !is_empty_method_found {
            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                visited_trait.span,
                &format!(
                    "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
                    visited_trait.ident.name
                ),
            );
        }
    }
}

fn check_impl_items(cx: &LateContext<'_>, item: &Item<'_>, impl_items: &[ImplItemRef<'_>]) {
    fn is_named_self(cx: &LateContext<'_>, item: &ImplItemRef<'_>, name: &str) -> bool {
        item.ident.name.as_str() == name
            && if let AssocItemKind::Fn { has_self } = item.kind {
                has_self && {
                    let did = cx.tcx.hir().local_def_id(item.id.hir_id);
                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
                }
            } else {
                false
            }
    }

    let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) {
        if cx.access_levels.is_exported(is_empty.id.hir_id) {
            return;
        } else {
            "a private"
        }
    } else {
        "no corresponding"
    };

    if let Some(i) = impl_items.iter().find(|i| is_named_self(cx, i, "len")) {
        if cx.access_levels.is_exported(i.id.hir_id) {
            let def_id = cx.tcx.hir().local_def_id(item.hir_id);
            let ty = cx.tcx.type_of(def_id);

            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                item.span,
                &format!(
                    "item `{}` has a public `len` method but {} `is_empty` method",
                    ty, is_empty
                ),
            );
        }
    }
}

fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
    if let (&ExprKind::MethodCall(ref method_path, _, ref args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind)
    {
        // check if we are in an is_empty() method
        if let Some(name) = get_item_name(cx, method) {
            if name.as_str() == "is_empty" {
                return;
            }
        }

        check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to)
    } else {
        check_empty_expr(cx, span, method, lit, op)
    }
}

fn check_len(
    cx: &LateContext<'_>,
    span: Span,
    method_name: Symbol,
    args: &[Expr<'_>],
    lit: &LitKind,
    op: &str,
    compare_to: u32,
) {
    if let LitKind::Int(lit, _) = *lit {
        // check if length is compared to the specified number
        if lit != u128::from(compare_to) {
            return;
        }

        if method_name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) {
            let mut applicability = Applicability::MachineApplicable;
            span_lint_and_sugg(
                cx,
                LEN_ZERO,
                span,
                &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
                &format!("using `{}is_empty` is clearer and more explicit", op),
                format!(
                    "{}{}.is_empty()",
                    op,
                    snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
                ),
                applicability,
            );
        }
    }
}

fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Expr<'_>, op: &str) {
    if (is_empty_array(lit2) || is_empty_string(lit2)) && has_is_empty(cx, lit1) {
        let mut applicability = Applicability::MachineApplicable;
        span_lint_and_sugg(
            cx,
            COMPARISON_TO_EMPTY,
            span,
            "comparison to empty slice",
            &format!("using `{}is_empty` is clearer and more explicit", op),
            format!(
                "{}{}.is_empty()",
                op,
                snippet_with_applicability(cx, lit1.span, "_", &mut applicability)
            ),
            applicability,
        );
    }
}

fn is_empty_string(expr: &Expr<'_>) -> bool {
    if let ExprKind::Lit(ref lit) = expr.kind {
        if let LitKind::Str(lit, _) = lit.node {
            let lit = lit.as_str();
            return lit == "";
        }
    }
    false
}

fn is_empty_array(expr: &Expr<'_>) -> bool {
    if let ExprKind::Array(ref arr) = expr.kind {
        return arr.is_empty();
    }
    false
}

/// Checks if this type has an `is_empty` method.
fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
    /// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
    fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
        if let ty::AssocKind::Fn = item.kind {
            if item.ident.name.as_str() == "is_empty" {
                let sig = cx.tcx.fn_sig(item.def_id);
                let ty = sig.skip_binder();
                ty.inputs().len() == 1
            } else {
                false
            }
        } else {
            false
        }
    }

    /// Checks the inherent impl's items for an `is_empty(self)` method.
    fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
        cx.tcx.inherent_impls(id).iter().any(|imp| {
            cx.tcx
                .associated_items(*imp)
                .in_definition_order()
                .any(|item| is_is_empty(cx, &item))
        })
    }

    let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
    match ty.kind() {
        ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| {
            cx.tcx
                .associated_items(principal.def_id())
                .in_definition_order()
                .any(|item| is_is_empty(cx, &item))
        }),
        ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
        ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
        ty::Array(..) | ty::Slice(..) | ty::Str => true,
        _ => false,
    }
}
<|endoftext|>


<commit_before>// Hound -- A wav encoding and decoding library in Rust
// Copyright (C) 2017 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

#![no_main]

extern crate libfuzzer_sys;
extern crate hound;

use std::io::Cursor;

#[export_name="rust_fuzzer_test_input"]
pub extern fn go(data: &[u8]) {
    let cursor = Cursor::new(data);
    let mut reader = match hound::WavReader::new(cursor) {
        Ok(r) => r,
        Err(..) => return,
    };

    for sample in reader.samples::<i32>() {
        match sample {
            Ok(..) => { }
            Err(..) => return,
        }
    }
}
<commit_msg>Work around memory error in fuzzer<commit_after>// Hound -- A wav encoding and decoding library in Rust
// Copyright (C) 2017 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

#![no_main]

extern crate libfuzzer_sys;
extern crate hound;

use std::io::Cursor;

#[export_name="rust_fuzzer_test_input"]
pub extern fn go(data: &[u8]) {
    let cursor = Cursor::new(data);
    let mut reader = match hound::WavReader::new(cursor) {
        Ok(r) => r,
        Err(..) => return,
    };

    // TODO: For some reason, the iterator-based approach crashes with an
    // obscure memory error, but the while-let-based method works perfectly
    // fine.
    // for sample in reader.samples::<i32>() {
    //     match sample {
    //         Ok(..) => { }
    //         Err(..) => return,
    //     }
    // }

    let mut iter = reader.samples::<i32>();
    while let Some(sample) = iter.next() {
        match sample {
            Ok(..) => { }
            Err(..) => return,
        }
    }
}
<|endoftext|>


<commit_before>use crossbeam::channel::unbounded;
use rosrust;
use std::process::Command;

mod util;

mod msg {
    rosrust::rosmsg_include!(std_msgs / String);
}

#[test]
fn subscriber_to_multiple_publishers() {
    let _roscore = util::run_roscore_for(util::Language::Multi, util::Feature::Subscriber);
    let _publisher_rostopic = util::ChildProcessTerminator::spawn(
        Command::new("rostopic")
            .arg("pub")
            .arg("-r")
            .arg("5")
            .arg("chatter")
            .arg("std_msgs/String")
            .arg("hello world from rostopic"),
    );
    let _publisher_roscpp = util::ChildProcessTerminator::spawn(
        Command::new("rosrun")
            .arg("roscpp_tutorials")
            .arg("talker")
            .arg("__name:=talker_cpp"),
    );
    let _publisher_rospy = util::ChildProcessTerminator::spawn(
        Command::new("rosrun")
            .arg("rospy_tutorials")
            .arg("talker")
            .arg("__name:=talker_py"),
    );
    let _publisher = util::ChildProcessTerminator::spawn_example(
        "../examples/pubsub",
        Command::new("cargo")
            .arg("run")
            .arg("--bin")
            .arg("publisher")
            .arg("__name:=talker_rust"),
    );

    let (tx, rx) = unbounded();

    rosrust::init("hello_world_listener");
    let _subscriber = rosrust::subscribe::<msg::std_msgs::String, _>("chatter", 100, move |data| {
        println!("{}",data.data);
        tx.send(data.data).unwrap();
    })
    .unwrap();

    println!("Checking roscpp publisher");
    util::test_subscriber_detailed(rx.clone(), r"hello world (\d+)", true, 10, false);
    println!("Checking rospy publisher");
    util::test_subscriber_detailed(rx.clone(), r"hello world (\d+\.\d+)", true, 10, false);
    println!("Checking rosrust publisher");
    util::test_subscriber_detailed(
        rx.clone(),
        r"hello world from rosrust (\d+)",
        true,
        10,
        false,
    );
    println!("Checking rostopic publisher");
    util::test_subscriber_detailed(rx.clone(), r"hello world from rostopic", false, 10, false);
}
<commit_msg>Fix regex matching for multi publisher tests<commit_after>use crossbeam::channel::unbounded;
use rosrust;
use std::process::Command;

mod util;

mod msg {
    rosrust::rosmsg_include!(std_msgs / String);
}

#[test]
fn subscriber_to_multiple_publishers() {
    let _roscore = util::run_roscore_for(util::Language::Multi, util::Feature::Subscriber);
    let _publisher_rostopic = util::ChildProcessTerminator::spawn(
        Command::new("rostopic")
            .arg("pub")
            .arg("-r")
            .arg("5")
            .arg("chatter")
            .arg("std_msgs/String")
            .arg("hello world from rostopic"),
    );
    let _publisher_roscpp = util::ChildProcessTerminator::spawn(
        Command::new("rosrun")
            .arg("roscpp_tutorials")
            .arg("talker")
            .arg("__name:=talker_cpp"),
    );
    let _publisher_rospy = util::ChildProcessTerminator::spawn(
        Command::new("rosrun")
            .arg("rospy_tutorials")
            .arg("talker")
            .arg("__name:=talker_py"),
    );
    let _publisher = util::ChildProcessTerminator::spawn_example(
        "../examples/pubsub",
        Command::new("cargo")
            .arg("run")
            .arg("--bin")
            .arg("publisher")
            .arg("__name:=talker_rust"),
    );

    let (tx, rx) = unbounded();

    rosrust::init("hello_world_listener");
    let _subscriber = rosrust::subscribe::<msg::std_msgs::String, _>("chatter", 100, move |data| {
        println!("{}", data.data);
        tx.send(data.data).unwrap();
    })
    .unwrap();

    println!("Checking roscpp publisher");
    util::test_subscriber_detailed(rx.clone(), r"^hello world (\d+)$", true, 10, false);
    println!("Checking rospy publisher");
    util::test_subscriber_detailed(rx.clone(), r"^hello world (\d+\.\d+)$", true, 10, false);
    println!("Checking rosrust publisher");
    util::test_subscriber_detailed(
        rx.clone(),
        r"^hello world from rosrust (\d+)$",
        true,
        10,
        false,
    );
    println!("Checking rostopic publisher");
    util::test_subscriber_detailed(rx.clone(), r"^hello world from rostopic$", false, 10, false);
}
<|endoftext|>


<commit_before>#![allow(unused_variables,unused_must_use)]
extern crate sozu_lib as sozu;
#[macro_use] extern crate sozu_command_lib as sozu_command;
extern crate time;
extern crate tiny_http;
extern crate ureq;

use std::thread;
use sozu_command::proxy;
use sozu_command::channel::Channel;
use sozu_command::proxy::LoadBalancingParams;
use sozu_command::logging::{Logger,LoggerBackend};
use tiny_http::{Server, Response};
use std::{
    io::{stdout, Read, Write},
    net::{TcpListener,TcpStream,ToSocketAddrs},
    time::Duration,
    sync::{Arc, Barrier},
    str
};

#[test]
fn test() {
    Logger::init("EXAMPLE".to_string(), "debug", LoggerBackend::Stdout(stdout()), None);

    info!("starting up");

    let config = proxy::HttpListener {
        front: "127.0.0.1:8080".parse().expect("could not parse address"),
        ..Default::default()
    };

    let (mut command, channel) = Channel::generate(1000, 10000).expect("should create a channel");

    let jg = thread::spawn(move || {
        Logger::init("SOZU".to_string(), "trace", LoggerBackend::Stdout(stdout()), None);
        let max_buffers = 20;
        let buffer_size = 16384;
        sozu::http::start(config, channel, max_buffers, buffer_size);
    });

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_Status"),
        order: proxy::ProxyRequestData::Status
    });

    // wait for sozu to start and answer
    info!("Status -> {:?}", command.read_message());

    let agent = ureq::AgentBuilder::new()
        .resolver(|addr: &str| match addr {
            "example.com:8080" => Ok(vec![([127,0,0,1], 8080).into()]),
            addr => addr.to_socket_addrs().map(Iterator::collect),
        })
    .build();

    info!("expecting 404");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(404, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_front = proxy::HttpFront {
        app_id:     String::from("test"),
        address:    "127.0.0.1:8080".parse().unwrap(),
        hostname:   String::from("example.com"),
        path_begin: String::from("/"),
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_ABCD"),
        order: proxy::ProxyRequestData::AddHttpFront(http_front)
    });
    println!("HTTP -> {:?}", command.read_message());

    info!("expecting 503");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(503, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    println!("HTTP -> {:?}", command.read_message());

    info!("sending invalid request, expecting 400");
    let mut client = TcpStream::connect(("127.0.0.1", 8080)).expect("could not parse address");
    // 1 seconds of timeout
    client.set_read_timeout(Some(Duration::new(1,0)));

    let w = client.write(&b"HELLO\r\n\r\n"[..]);
    println!("http client write: {:?}", w);

    let expected_answer = "HTTP/1.1 400 Bad Request\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n";
    let mut buffer = [0;4096];
    let mut index = 0;

    let r = client.read(&mut buffer[..]);
    println!("http client read: {:?}", r);
    match r {
        Err(e)      => assert!(false, "client request should not fail. Error: {:?}",e),
        Ok(sz) => {
            index += sz;
            let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
            println!("Response: {}", answer);
        }
    }

    let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
    println!("Response: {}", answer);
    assert_eq!(answer, expected_answer);

    let barrier = Arc::new(Barrier::new(2));
    let barrier2 = barrier.clone();

    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"TEST\r\n\r\n";
        stream.write(&response[..]).unwrap();
    });

    barrier.wait();
    info!("expecting 502");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(502, res) => {
                assert_eq!(res.status_text(), "Bad Gateway");
            },
            e => panic!("invalid response: {:?}", e),
        };

    start_server(2048, barrier.clone());

    barrier.wait();
    info!("expecting 200");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);

    //let _ = jg.join();
    info!("good bye");
}

fn start_server(port: u16, barrier: Arc<Barrier>) {
    thread::spawn(move|| {
        let server = Server::http(&format!("127.0.0.1:{}", port)).expect("could not create server");
        info!("starting web server in port {}", port);

        barrier.wait();
        for request in server.incoming_requests() {
            println!("backend web server got request -> method: {:?}, url: {:?}, headers: {:?}",
                     request.method(),
                     request.url(),
                     request.headers()
                    );

            let response = Response::from_string("hello world");
            request.respond(response).unwrap();
            println!("backend web server sent response");
            println!("server session stopped");
        }

        println!("server on port {} closed", port);
    });
}
<commit_msg>add more integration tests around early shutdown of backend sockets<commit_after>#![allow(unused_variables,unused_must_use)]
extern crate sozu_lib as sozu;
#[macro_use] extern crate sozu_command_lib as sozu_command;
extern crate time;
extern crate tiny_http;
extern crate ureq;

use std::thread;
use sozu_command::proxy;
use sozu_command::channel::Channel;
use sozu_command::proxy::LoadBalancingParams;
use sozu_command::logging::{Logger,LoggerBackend};
use tiny_http::{Server, Response};
use std::{
    io::{stdout, Read, Write},
    net::{TcpListener,TcpStream,ToSocketAddrs},
    time::Duration,
    sync::{Arc, Barrier},
    str
};

#[test]
fn test() {
    Logger::init("EXAMPLE".to_string(), "debug", LoggerBackend::Stdout(stdout()), None);

    info!("starting up");

    let config = proxy::HttpListener {
        front: "127.0.0.1:8080".parse().expect("could not parse address"),
        ..Default::default()
    };

    let (mut command, channel) = Channel::generate(1000, 10000).expect("should create a channel");

    let jg = thread::spawn(move || {
        Logger::init("SOZU".to_string(), "trace", LoggerBackend::Stdout(stdout()), None);
        let max_buffers = 20;
        let buffer_size = 16384;
        sozu::http::start(config, channel, max_buffers, buffer_size);
    });

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_Status"),
        order: proxy::ProxyRequestData::Status
    });

    // wait for sozu to start and answer
    info!("Status -> {:?}", command.read_message());

    let agent = ureq::AgentBuilder::new()
        .resolver(|addr: &str| match addr {
            "example.com:8080" => Ok(vec![([127,0,0,1], 8080).into()]),
            addr => addr.to_socket_addrs().map(Iterator::collect),
        })
    .build();

    info!("expecting 404");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(404, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_front = proxy::HttpFront {
        app_id:     String::from("test"),
        address:    "127.0.0.1:8080".parse().unwrap(),
        hostname:   String::from("example.com"),
        path_begin: String::from("/"),
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_ABCD"),
        order: proxy::ProxyRequestData::AddHttpFront(http_front)
    });
    println!("HTTP -> {:?}", command.read_message());

    info!("expecting 503");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(503, res) => {
                assert_eq!(res.header("connection"), Some("close"));
            },
            e => panic!("invalid response: {:?}", e),
        };

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    println!("HTTP -> {:?}", command.read_message());

    info!("sending invalid request, expecting 400");
    let mut client = TcpStream::connect(("127.0.0.1", 8080)).expect("could not parse address");
    // 1 seconds of timeout
    client.set_read_timeout(Some(Duration::new(1,0)));

    let w = client.write(&b"HELLO\r\n\r\n"[..]);
    println!("http client write: {:?}", w);

    let expected_answer = "HTTP/1.1 400 Bad Request\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n";
    let mut buffer = [0;4096];
    let mut index = 0;

    let r = client.read(&mut buffer[..]);
    println!("http client read: {:?}", r);
    match r {
        Err(e)      => assert!(false, "client request should not fail. Error: {:?}",e),
        Ok(sz) => {
            index += sz;
            let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
            println!("Response: {}", answer);
        }
    }

    let answer = str::from_utf8(&buffer[..index]).expect("could not make string from buffer");
    println!("Response: {}", answer);
    assert_eq!(answer, expected_answer);

    let barrier = Arc::new(Barrier::new(2));
    let barrier2 = barrier.clone();

    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"TEST\r\n\r\n";
        stream.write(&response[..]).unwrap();
    });

    barrier.wait();
    info!("expecting 502");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(502, res) => {
                assert_eq!(res.status_text(), "Bad Gateway");
            },
            e => panic!("invalid response: {:?}", e),
        };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-2"),
        order: proxy::ProxyRequestData::RemoveBackend(proxy::RemoveBackend {
            app_id: String::from("test"),
            backend_id: String::from("test-0"),
            address: "127.0.0.1:2048".parse().unwrap(),
        })
    });

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-3"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    let barrier2 = barrier.clone();
    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let mut stream = listener.incoming().next().unwrap().unwrap();
        let response = b"HTTP/1.1 200 Ok\r\nConnection: close\r\nContent-Length: 5\r\n\r\nHello";
        stream.write(&response[..]).unwrap();
        stream.shutdown(std::net::Shutdown::Both).unwrap();
    });

    barrier.wait();
    info!("expecting 200 then close");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);
    assert_eq!(res.status_text(), "Ok");
    assert_eq!(res.header("Content-Length"), Some("5"));
    assert_eq!(res.into_string().unwrap(), "Hello");

    let barrier2 = barrier.clone();
    let _ = thread::spawn(move || {
        let listener = TcpListener::bind("127.0.0.1:2048").expect("could not parse address");
        barrier2.wait();
        let stream = listener.incoming().next().unwrap().unwrap();
        stream.shutdown(std::net::Shutdown::Both).unwrap();
    });

    barrier.wait();
    info!("server closes, expecting 503");
    match agent
        .get("http://example.com:8080/")
        .call().unwrap_err() {
            ureq::Error::Status(503, res) => {
                println!("res: {:?}", res);
                assert_eq!(res.status_text(), "Service Unavailable");
            },
            e => panic!("invalid response: {:?}", e),
        };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-2"),
        order: proxy::ProxyRequestData::RemoveBackend(proxy::RemoveBackend {
            app_id: String::from("test"),
            backend_id: String::from("test-0"),
            address: "127.0.0.1:2048".parse().unwrap(),
        })
    });

    let http_backend = proxy::Backend {
        app_id:                    String::from("test"),
        backend_id:                String::from("test-0"),
        address:                   "127.0.0.1:2048".parse().unwrap(),
        load_balancing_parameters: Some(LoadBalancingParams::default()),
        sticky_id:                 None,
        backup:                    None,
    };

    command.write_message(&proxy::ProxyRequest {
        id:    String::from("ID_EFGH-3"),
        order: proxy::ProxyRequestData::AddBackend(http_backend)
    });

    start_server(2048, barrier.clone());

    barrier.wait();
    info!("expecting 200");
    let res = agent
        .get("http://example.com:8080/")
        .call().unwrap();
    assert_eq!(res.status(), 200);

    //let _ = jg.join();
    info!("good bye");
}

fn start_server(port: u16, barrier: Arc<Barrier>) {
    thread::spawn(move|| {
        let server = Server::http(&format!("127.0.0.1:{}", port)).expect("could not create server");
        info!("starting web server in port {}", port);

        barrier.wait();
        for request in server.incoming_requests() {
            println!("backend web server got request -> method: {:?}, url: {:?}, headers: {:?}",
                     request.method(),
                     request.url(),
                     request.headers()
                    );

            let response = Response::from_string("hello world");
            request.respond(response).unwrap();
            println!("backend web server sent response");
            println!("server session stopped");
        }

        println!("server on port {} closed", port);
    });
}
<|endoftext|>


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

//! Device extension. Allows creating a renderer or converting into
//! a single-threaded wrapper.

use std::ops;
use device;
use render::{batch, Renderer};
use render::ext::factory::RenderFactory;
use render::shade::ShaderParam;

/// A convenient wrapper suitable for single-threaded operation.
pub struct Graphics<D: device::Device, F> {
    /// Graphics device.
    pub device: D,
    /// Resource factory.
    pub factory: F,
    /// Renderer front-end.
    pub renderer: Renderer<D::Resources, D::CommandBuffer>,
    /// Hidden batch context.
    context: batch::Context<D::Resources>,
}

impl<D: device::Device, F> ops::Deref for Graphics<D, F> {
    type Target = batch::Context<D::Resources>;

    fn deref(&self) -> &batch::Context<D::Resources> {
        &self.context
    }
}

impl<D: device::Device, F> ops::DerefMut for Graphics<D, F> {
    fn deref_mut(&mut self) -> &mut batch::Context<D::Resources> {
        &mut self.context
    }
}

impl<D: device::Device, F: device::Factory<D::Resources>> Graphics<D, F> {
    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: ::ClearData, mask: ::Mask, frame: &::Frame<D::Resources>) {
        self.renderer.clear(data, mask, frame)
    }

    /// Draw a `RefBatch` batch.
    pub fn draw<'a, T: ShaderParam<Resources = D::Resources>>(&'a mut self,
                batch: &'a batch::RefBatch<T>, frame: &::Frame<D::Resources>)
                -> Result<(), ::DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&(batch, &self.context), frame)
    }

    /// Draw a `CoreBatch` batch.
    pub fn draw_core<'a, T: ShaderParam<Resources = D::Resources>>(&'a mut self,
                     core: &'a batch::CoreBatch<T>, slice: &'a ::Slice<D::Resources>,
                     params: &'a T, frame: &::Frame<D::Resources>)
                     -> Result<(), ::DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&self.context.bind(core, slice, params), frame)
    }

    /// Submit the internal command buffer and reset for the next frame.
    pub fn end_frame(&mut self) {
        self.device.submit(self.renderer.as_buffer());
        self.renderer.reset();
    }

    /// Cleanup resources after the frame.
    pub fn cleanup(&mut self) {
        self.device.after_frame();
        self.factory.cleanup();
    }
}

/// Backend extension trait for convenience methods
pub trait DeviceExt<D: device::Device, F> {
    /// Convert to single-threaded wrapper
    fn into_graphics(mut self) -> Graphics<D, F>;
}

impl<
    D: device::Device,
    F: device::Factory<D::Resources>,
> DeviceExt<D, F> for (D, F) {
    fn into_graphics(mut self) -> Graphics<D, F> {
        let rend = self.1.create_renderer();
        Graphics {
            device: self.0,
            factory: self.1,
            renderer: rend,
            context: batch::Context::new(),
        }
    }
}
<commit_msg>Updated Graphics to work with Output<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Device extension. Allows creating a renderer or converting into
//! a single-threaded wrapper.

use std::ops;
use device;
use render::{batch, Renderer};
use render::ext::factory::RenderFactory;
use render::shade::ShaderParam;

/// A convenient wrapper suitable for single-threaded operation.
pub struct Graphics<D: device::Device, F> {
    /// Graphics device.
    pub device: D,
    /// Resource factory.
    pub factory: F,
    /// Renderer front-end.
    pub renderer: Renderer<D::Resources, D::CommandBuffer>,
    /// Hidden batch context.
    context: batch::Context<D::Resources>,
}

impl<D: device::Device, F> ops::Deref for Graphics<D, F> {
    type Target = batch::Context<D::Resources>;

    fn deref(&self) -> &batch::Context<D::Resources> {
        &self.context
    }
}

impl<D: device::Device, F> ops::DerefMut for Graphics<D, F> {
    fn deref_mut(&mut self) -> &mut batch::Context<D::Resources> {
        &mut self.context
    }
}

impl<D: device::Device, F: device::Factory<D::Resources>> Graphics<D, F> {
    /// Clear the output with given `ClearData`.
    pub fn clear<O: ::Output<D::Resources>>(&mut self,
                 data: ::ClearData, mask: ::Mask, out: &O) {
        self.renderer.clear(data, mask, out)
    }

    /// Draw a `RefBatch` batch.
    pub fn draw<'a,
        T: ShaderParam<Resources = D::Resources>,
        O: ::Output<D::Resources>,
    >(
        &'a mut self, batch: &'a batch::RefBatch<T>, out: &O)
        -> Result<(), ::DrawError<batch::OutOfBounds>>
    {
        self.renderer.draw(&(batch, &self.context), out)
    }

    /// Draw a `CoreBatch` batch.
    pub fn draw_core<'a,
        T: ShaderParam<Resources = D::Resources>,
        O: ::Output<D::Resources>,
    >(
        &'a mut self, core: &'a batch::CoreBatch<T>, slice: &'a ::Slice<D::Resources>,
        params: &'a T, out: &O) -> Result<(), ::DrawError<batch::OutOfBounds>>
    {
        self.renderer.draw(&self.context.bind(core, slice, params), out)
    }

    /// Submit the internal command buffer and reset for the next frame.
    pub fn end_frame(&mut self) {
        self.device.submit(self.renderer.as_buffer());
        self.renderer.reset();
    }

    /// Cleanup resources after the frame.
    pub fn cleanup(&mut self) {
        self.device.after_frame();
        self.factory.cleanup();
    }
}

/// Backend extension trait for convenience methods
pub trait DeviceExt<D: device::Device, F> {
    /// Convert to single-threaded wrapper
    fn into_graphics(mut self) -> Graphics<D, F>;
}

impl<
    D: device::Device,
    F: device::Factory<D::Resources>,
> DeviceExt<D, F> for (D, F) {
    fn into_graphics(mut self) -> Graphics<D, F> {
        let rend = self.1.create_renderer();
        Graphics {
            device: self.0,
            factory: self.1,
            renderer: rend,
            context: batch::Context::new(),
        }
    }
}
<|endoftext|>