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

//! Shader parameter handling.

use std::cell::Cell;
use std::fmt;
use device::shade;
use device::{RawBufferHandle, ProgramHandle, TextureHandle, SamplerHandle};

/// Helper trait to transform base types into their corresponding uniforms
pub trait ToUniform {
    /// Create a `UniformValue` representing this value.
    fn to_uniform(&self) -> shade::UniformValue;
}

macro_rules! impl_ToUniform(
    ($srcty:ty, $dstty:expr) => (
        impl ToUniform for $srcty {
            fn to_uniform(&self) -> shade::UniformValue {
                $dstty(*self)
            }
        }
    );
)

impl_ToUniform!(i32, shade::ValueI32)
impl_ToUniform!(f32, shade::ValueF32)

impl_ToUniform!([i32, ..2], shade::ValueI32Vector2)
impl_ToUniform!([i32, ..3], shade::ValueI32Vector3)
impl_ToUniform!([i32, ..4], shade::ValueI32Vector4)

impl_ToUniform!([f32, ..2], shade::ValueF32Vector2)
impl_ToUniform!([f32, ..3], shade::ValueF32Vector3)
impl_ToUniform!([f32, ..4], shade::ValueF32Vector4)

impl_ToUniform!([[f32, ..2], ..2], shade::ValueF32Matrix2)
impl_ToUniform!([[f32, ..3], ..3], shade::ValueF32Matrix3)
impl_ToUniform!([[f32, ..4], ..4], shade::ValueF32Matrix4)

/// Variable index of a uniform.
pub type VarUniform = u16;

/// Variable index of a uniform block.
pub type VarBlock = u8;

/// Variable index of a texture.
pub type VarTexture = u8;

/// A texture parameter: consists of a texture handle with an optional sampler.
pub type TextureParam = (TextureHandle, Option<SamplerHandle>);

/// A borrowed mutable storage for shader parameter values.
// Not sure if it's the best data structure to represent it.
pub struct ParamValues<'a> {
    /// uniform values to be provided
    pub uniforms: &'a mut [Option<shade::UniformValue>],
    /// uniform buffers to be provided
    pub blocks  : &'a mut [Option<RawBufferHandle>],
    /// textures to be provided
    pub textures: &'a mut [Option<TextureParam>],
}

/// An error type on either the parameter storage or the program side
#[deriving(Clone, PartialEq)]
pub enum ParameterError {
    /// Internal error
    ErrorInternal,
    /// Error with the named uniform
    ErrorUniform(String),
    /// Error with the named uniform block
    ErrorBlock(String),
    /// Error with the named texture.
    ErrorTexture(String),
}

impl fmt::Show for ParameterError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ErrorInternal          => write!(f, "Internal error"),
            &ErrorUniform(ref name) => write!(
                f,
                "Uniform error: Please make sure the uniform \"{0}\" is used \
                by the shader. Note: Specifying the uniform in the shader like \
                \"uniform <type> {0};\"  is not enough. It must actively be \
                used by the shader code.",
                name),
            &ErrorBlock(ref name)   => write!(f, "Block error: {}", name),
            &ErrorTexture(ref name) => write!(
                f,
                "Texture error: Please make sure the texture \"{0}\" is used \
                by the shader. Note: Specifying the texture in the shader like \
                \"uniform sampler2D {0};\"  is not enough. It must actively be \
                used by the shader code.",
                name),
        }
    }
}

/// Abstracts the shader parameter structure, generated by the `shader_param` attribute
pub trait ShaderParam<L> {
    /// Creates a new link, self is passed as a workaround for Rust to not be lost in generics
    fn create_link(Option<Self>, &shade::ProgramInfo) -> Result<L, ParameterError>;
    /// Get all the contained parameter values, using a given link.
    fn fill_params(&self, &L, ParamValues);
}

impl ShaderParam<()> for () {
    fn create_link(_: Option<()>, info: &shade::ProgramInfo) -> Result<(), ParameterError> {
        match info.uniforms.as_slice().head() {
            Some(u) => return Err(ErrorUniform(u.name.clone())),
            None => (),
        }
        match info.blocks.as_slice().head() {
            Some(b) => return Err(ErrorBlock(b.name.clone())),
            None => (),
        }
        match info.textures.as_slice().head() {
            Some(t) => return Err(ErrorTexture(t.name.clone())),
            None => (),
        }
        Ok(())
    }

    fn fill_params(&self, _: &(), _: ParamValues) {
        //empty
    }
}

/// A named cell containing arbitrary value
pub struct NamedCell<T> {
    /// Name
    pub name: String,
    /// Value
    pub value: Cell<T>,
}

/// A dictionary of parameters, meant to be shared between different programs
pub struct ParamDictionary {
    /// Uniform dictionary
    pub uniforms: Vec<NamedCell<shade::UniformValue>>,
    /// Block dictionary
    pub blocks: Vec<NamedCell<RawBufferHandle>>,
    /// Texture dictionary
    pub textures: Vec<NamedCell<TextureParam>>,
}

/// An associated link structure for `ParamDictionary` that redirects program
/// input to the relevant dictionary cell.
pub struct ParamDictionaryLink {
    uniforms: Vec<uint>,
    blocks: Vec<uint>,
    textures: Vec<uint>,
}

impl ParamDictionary {
    /// Connect a shader program with a parameter structure
    pub fn connect(&self, prog: &ProgramHandle)
               -> Result<ParamDictionaryLink, ParameterError> {
        //TODO: proper error checks
        Ok(ParamDictionaryLink {
            uniforms: prog.get_info().uniforms.iter().map(|var|
                self.uniforms.iter().position(|c| c.name == var.name).unwrap()
            ).collect(),
            blocks: prog.get_info().blocks.iter().map(|var|
                self.blocks  .iter().position(|c| c.name == var.name).unwrap()
            ).collect(),
            textures: prog.get_info().textures.iter().map(|var|
                self.textures.iter().position(|c| c.name == var.name).unwrap()
            ).collect(),
        })
    }

    /// Set the parameter values
    pub fn fill_params(&self, link: &ParamDictionaryLink, params: ParamValues) {
        for (&id, var) in link.uniforms.iter().zip(params.uniforms.mut_iter()) {
            *var = Some(self.uniforms[id].value.get());
        }
        for (&id, var) in link.blocks.iter().zip(params.blocks.mut_iter()) {
            *var = Some(self.blocks[id].value.get());
        }
        for (&id, var) in link.textures.iter().zip(params.textures.mut_iter()) {
            *var = Some(self.textures[id].value.get());
        }
    }
}
<commit_msg>Exporting shader stages<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.

//! Shader parameter handling.

use std::cell::Cell;
use std::fmt;
use device::shade;
use device::{RawBufferHandle, ProgramHandle, TextureHandle, SamplerHandle};

pub use device::shade::{Stage, CreateShaderError, Vertex, Geometry, Fragment};

/// Helper trait to transform base types into their corresponding uniforms
pub trait ToUniform {
    /// Create a `UniformValue` representing this value.
    fn to_uniform(&self) -> shade::UniformValue;
}

macro_rules! impl_ToUniform(
    ($srcty:ty, $dstty:expr) => (
        impl ToUniform for $srcty {
            fn to_uniform(&self) -> shade::UniformValue {
                $dstty(*self)
            }
        }
    );
)

impl_ToUniform!(i32, shade::ValueI32)
impl_ToUniform!(f32, shade::ValueF32)

impl_ToUniform!([i32, ..2], shade::ValueI32Vector2)
impl_ToUniform!([i32, ..3], shade::ValueI32Vector3)
impl_ToUniform!([i32, ..4], shade::ValueI32Vector4)

impl_ToUniform!([f32, ..2], shade::ValueF32Vector2)
impl_ToUniform!([f32, ..3], shade::ValueF32Vector3)
impl_ToUniform!([f32, ..4], shade::ValueF32Vector4)

impl_ToUniform!([[f32, ..2], ..2], shade::ValueF32Matrix2)
impl_ToUniform!([[f32, ..3], ..3], shade::ValueF32Matrix3)
impl_ToUniform!([[f32, ..4], ..4], shade::ValueF32Matrix4)

/// Variable index of a uniform.
pub type VarUniform = u16;

/// Variable index of a uniform block.
pub type VarBlock = u8;

/// Variable index of a texture.
pub type VarTexture = u8;

/// A texture parameter: consists of a texture handle with an optional sampler.
pub type TextureParam = (TextureHandle, Option<SamplerHandle>);

/// A borrowed mutable storage for shader parameter values.
// Not sure if it's the best data structure to represent it.
pub struct ParamValues<'a> {
    /// uniform values to be provided
    pub uniforms: &'a mut [Option<shade::UniformValue>],
    /// uniform buffers to be provided
    pub blocks  : &'a mut [Option<RawBufferHandle>],
    /// textures to be provided
    pub textures: &'a mut [Option<TextureParam>],
}

/// An error type on either the parameter storage or the program side
#[deriving(Clone, PartialEq)]
pub enum ParameterError {
    /// Internal error
    ErrorInternal,
    /// Error with the named uniform
    ErrorUniform(String),
    /// Error with the named uniform block
    ErrorBlock(String),
    /// Error with the named texture.
    ErrorTexture(String),
}

impl fmt::Show for ParameterError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ErrorInternal          => write!(f, "Internal error"),
            &ErrorUniform(ref name) => write!(
                f,
                "Uniform error: Please make sure the uniform \"{0}\" is used \
                by the shader. Note: Specifying the uniform in the shader like \
                \"uniform <type> {0};\"  is not enough. It must actively be \
                used by the shader code.",
                name),
            &ErrorBlock(ref name)   => write!(f, "Block error: {}", name),
            &ErrorTexture(ref name) => write!(
                f,
                "Texture error: Please make sure the texture \"{0}\" is used \
                by the shader. Note: Specifying the texture in the shader like \
                \"uniform sampler2D {0};\"  is not enough. It must actively be \
                used by the shader code.",
                name),
        }
    }
}

/// Abstracts the shader parameter structure, generated by the `shader_param` attribute
pub trait ShaderParam<L> {
    /// Creates a new link, self is passed as a workaround for Rust to not be lost in generics
    fn create_link(Option<Self>, &shade::ProgramInfo) -> Result<L, ParameterError>;
    /// Get all the contained parameter values, using a given link.
    fn fill_params(&self, &L, ParamValues);
}

impl ShaderParam<()> for () {
    fn create_link(_: Option<()>, info: &shade::ProgramInfo) -> Result<(), ParameterError> {
        match info.uniforms.as_slice().head() {
            Some(u) => return Err(ErrorUniform(u.name.clone())),
            None => (),
        }
        match info.blocks.as_slice().head() {
            Some(b) => return Err(ErrorBlock(b.name.clone())),
            None => (),
        }
        match info.textures.as_slice().head() {
            Some(t) => return Err(ErrorTexture(t.name.clone())),
            None => (),
        }
        Ok(())
    }

    fn fill_params(&self, _: &(), _: ParamValues) {
        //empty
    }
}

/// A named cell containing arbitrary value
pub struct NamedCell<T> {
    /// Name
    pub name: String,
    /// Value
    pub value: Cell<T>,
}

/// A dictionary of parameters, meant to be shared between different programs
pub struct ParamDictionary {
    /// Uniform dictionary
    pub uniforms: Vec<NamedCell<shade::UniformValue>>,
    /// Block dictionary
    pub blocks: Vec<NamedCell<RawBufferHandle>>,
    /// Texture dictionary
    pub textures: Vec<NamedCell<TextureParam>>,
}

/// An associated link structure for `ParamDictionary` that redirects program
/// input to the relevant dictionary cell.
pub struct ParamDictionaryLink {
    uniforms: Vec<uint>,
    blocks: Vec<uint>,
    textures: Vec<uint>,
}

impl ParamDictionary {
    /// Connect a shader program with a parameter structure
    pub fn connect(&self, prog: &ProgramHandle)
               -> Result<ParamDictionaryLink, ParameterError> {
        //TODO: proper error checks
        Ok(ParamDictionaryLink {
            uniforms: prog.get_info().uniforms.iter().map(|var|
                self.uniforms.iter().position(|c| c.name == var.name).unwrap()
            ).collect(),
            blocks: prog.get_info().blocks.iter().map(|var|
                self.blocks  .iter().position(|c| c.name == var.name).unwrap()
            ).collect(),
            textures: prog.get_info().textures.iter().map(|var|
                self.textures.iter().position(|c| c.name == var.name).unwrap()
            ).collect(),
        })
    }

    /// Set the parameter values
    pub fn fill_params(&self, link: &ParamDictionaryLink, params: ParamValues) {
        for (&id, var) in link.uniforms.iter().zip(params.uniforms.mut_iter()) {
            *var = Some(self.uniforms[id].value.get());
        }
        for (&id, var) in link.blocks.iter().zip(params.blocks.mut_iter()) {
            *var = Some(self.blocks[id].value.get());
        }
        for (&id, var) in link.textures.iter().zip(params.textures.mut_iter()) {
            *var = Some(self.textures[id].value.get());
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2013 Jorge Aparicio

fn main() {
  println("Hello World!")
}
<commit_msg>000.rs: use println macro<commit_after>// Copyright (C) 2013 Jorge Aparicio

fn main() {
  println!("Hello World!")
}
<|endoftext|>


<commit_before>#![feature(generators, generator_trait, never_type)]

use std::ops::{GeneratorState::{self, *}, Generator};
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::fmt::Debug;

fn basic() {
    fn finish<T>(mut amt: usize, mut t: T) -> T::Return
        where T: Generator<Yield = usize>
    {
        // We are not moving the `t` around until it gets dropped, so this is okay.
        let mut t = unsafe { Pin::new_unchecked(&mut t) };
        loop {
            match t.as_mut().resume(()) {
                GeneratorState::Yielded(y) => amt -= y,
                GeneratorState::Complete(ret) => {
                    assert_eq!(amt, 0);
                    return ret
                }
            }
        }
    }

    enum Never {}
    fn never() -> Never {
        panic!()
    }

    finish(1, || yield 1);

    finish(3, || {
        let mut x = 0;
        yield 1;
        x += 1;
        yield 1;
        x += 1;
        yield 1;
        assert_eq!(x, 2);
    });

    finish(7*8/2, || {
        for i in 0..8 {
            yield i;
        }
    });

    finish(1, || {
        if true {
            yield 1;
        } else {
        }
    });

    finish(1, || {
        if false {
        } else {
            yield 1;
        }
    });

    finish(2, || {
        if { yield 1; false } {
            yield 1;
            panic!()
        }
        yield 1;
    });

    // also test a self-referential generator
    assert_eq!(
        finish(5, || {
            let mut x = Box::new(5);
            let y = &mut *x;
            *y = 5;
            yield *y;
            *y = 10;
            *x
        }),
        10
    );

    let b = true;
    finish(1, || {
        yield 1;
        if b { return; }
        #[allow(unused)]
        let x = never();
        yield 2;
        drop(x);
    });

    finish(3, || {
        yield 1;
        #[allow(unreachable_code)]
        let _x: (String, !) = (String::new(), { yield 2; return });
    });
}

fn smoke_resume_arg() {
    fn drain<G: Generator<R, Yield = Y> + Unpin, R, Y>(
        gen: &mut G,
        inout: Vec<(R, GeneratorState<Y, G::Return>)>,
    ) where
        Y: Debug + PartialEq,
        G::Return: Debug + PartialEq,
    {
        let mut gen = Pin::new(gen);

        for (input, out) in inout {
            assert_eq!(gen.as_mut().resume(input), out);
        }
    }

    static DROPS: AtomicUsize = AtomicUsize::new(0);

    #[derive(Debug, PartialEq)]
    struct DropMe;

    impl Drop for DropMe {
        fn drop(&mut self) {
            DROPS.fetch_add(1, Ordering::SeqCst);
        }
    }

    fn expect_drops<T>(expected_drops: usize, f: impl FnOnce() -> T) -> T {
        DROPS.store(0, Ordering::SeqCst);

        let res = f();

        let actual_drops = DROPS.load(Ordering::SeqCst);
        assert_eq!(actual_drops, expected_drops);
        res
    }

    drain(
        &mut |mut b| {
            while b != 0 {
                b = yield (b + 1);
            }
            -1
        },
        vec![(1, Yielded(2)), (-45, Yielded(-44)), (500, Yielded(501)), (0, Complete(-1))],
    );

    expect_drops(2, || drain(&mut |a| yield a, vec![(DropMe, Yielded(DropMe))]));

    expect_drops(6, || {
        drain(
            &mut |a| yield yield a,
            vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))],
        )
    });

    #[allow(unreachable_code)]
    expect_drops(2, || drain(&mut |a| yield return a, vec![(DropMe, Complete(DropMe))]));

    expect_drops(2, || {
        drain(
            &mut |a: DropMe| {
                if false { yield () } else { a }
            },
            vec![(DropMe, Complete(DropMe))],
        )
    });

    expect_drops(4, || {
        drain(
            #[allow(unused_assignments, unused_variables)]
            &mut |mut a: DropMe| {
                a = yield;
                a = yield;
                a = yield;
            },
            vec![
                (DropMe, Yielded(())),
                (DropMe, Yielded(())),
                (DropMe, Yielded(())),
                (DropMe, Complete(())),
            ],
        )
    });
}

fn main() {
    basic();
    smoke_resume_arg();
}
<commit_msg>try even harder to catch invalid generator fields<commit_after>#![feature(generators, generator_trait, never_type)]

use std::ops::{GeneratorState::{self, *}, Generator};
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::fmt::Debug;
use std::mem::ManuallyDrop;
use std::ptr;

fn basic() {
    fn finish<T>(mut amt: usize, mut t: T) -> T::Return
        where T: Generator<Yield = usize>
    {
        // We are not moving the `t` around until it gets dropped, so this is okay.
        let mut t = unsafe { Pin::new_unchecked(&mut t) };
        loop {
            let state = t.as_mut().resume(());
            // Test if the generator is valid (according to type invariants).
            let _ = unsafe { ManuallyDrop::new(ptr::read(t.as_mut().get_unchecked_mut())) };
            match state {
                GeneratorState::Yielded(y) => {
                    amt -= y;
                }
                GeneratorState::Complete(ret) => {
                    assert_eq!(amt, 0);
                    return ret
                }
            }
        }
    }

    enum Never {}
    fn never() -> Never {
        panic!()
    }

    finish(1, || yield 1);

    finish(3, || {
        let mut x = 0;
        yield 1;
        x += 1;
        yield 1;
        x += 1;
        yield 1;
        assert_eq!(x, 2);
    });

    finish(7*8/2, || {
        for i in 0..8 {
            yield i;
        }
    });

    finish(1, || {
        if true {
            yield 1;
        } else {
        }
    });

    finish(1, || {
        if false {
        } else {
            yield 1;
        }
    });

    finish(2, || {
        if { yield 1; false } {
            yield 1;
            panic!()
        }
        yield 1;
    });

    // also test a self-referential generator
    assert_eq!(
        finish(5, || {
            let mut x = Box::new(5);
            let y = &mut *x;
            *y = 5;
            yield *y;
            *y = 10;
            *x
        }),
        10
    );

    let b = true;
    finish(1, || {
        yield 1;
        if b { return; }
        #[allow(unused)]
        let x = never();
        yield 2;
        drop(x);
    });

    finish(3, || {
        yield 1;
        #[allow(unreachable_code)]
        let _x: (String, !) = (String::new(), { yield 2; return });
    });
}

fn smoke_resume_arg() {
    fn drain<G: Generator<R, Yield = Y> + Unpin, R, Y>(
        gen: &mut G,
        inout: Vec<(R, GeneratorState<Y, G::Return>)>,
    ) where
        Y: Debug + PartialEq,
        G::Return: Debug + PartialEq,
    {
        let mut gen = Pin::new(gen);

        for (input, out) in inout {
            assert_eq!(gen.as_mut().resume(input), out);
            // Test if the generator is valid (according to type invariants).
            let _ = unsafe { ManuallyDrop::new(ptr::read(gen.as_mut().get_unchecked_mut())) };
        }
    }

    static DROPS: AtomicUsize = AtomicUsize::new(0);

    #[derive(Debug, PartialEq)]
    struct DropMe;

    impl Drop for DropMe {
        fn drop(&mut self) {
            DROPS.fetch_add(1, Ordering::SeqCst);
        }
    }

    fn expect_drops<T>(expected_drops: usize, f: impl FnOnce() -> T) -> T {
        DROPS.store(0, Ordering::SeqCst);

        let res = f();

        let actual_drops = DROPS.load(Ordering::SeqCst);
        assert_eq!(actual_drops, expected_drops);
        res
    }

    drain(
        &mut |mut b| {
            while b != 0 {
                b = yield (b + 1);
            }
            -1
        },
        vec![(1, Yielded(2)), (-45, Yielded(-44)), (500, Yielded(501)), (0, Complete(-1))],
    );

    expect_drops(2, || drain(&mut |a| yield a, vec![(DropMe, Yielded(DropMe))]));

    expect_drops(6, || {
        drain(
            &mut |a| yield yield a,
            vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))],
        )
    });

    #[allow(unreachable_code)]
    expect_drops(2, || drain(&mut |a| yield return a, vec![(DropMe, Complete(DropMe))]));

    expect_drops(2, || {
        drain(
            &mut |a: DropMe| {
                if false { yield () } else { a }
            },
            vec![(DropMe, Complete(DropMe))],
        )
    });

    expect_drops(4, || {
        drain(
            #[allow(unused_assignments, unused_variables)]
            &mut |mut a: DropMe| {
                a = yield;
                a = yield;
                a = yield;
            },
            vec![
                (DropMe, Yielded(())),
                (DropMe, Yielded(())),
                (DropMe, Yielded(())),
                (DropMe, Complete(())),
            ],
        )
    });
}

fn main() {
    basic();
    smoke_resume_arg();
}
<|endoftext|>


<commit_before>use quick_xml::encoding::Decoder;
use quick_xml::escape::unescape;
use quick_xml::events::{BytesStart, Event};
use quick_xml::name::{QName, ResolveResult};
use quick_xml::reader::NsReader;
use std::str::from_utf8;

#[test]
fn sample_1_short() {
    test(
        include_str!("documents/sample_1.xml"),
        include_str!("documents/sample_1_short.txt"),
        true,
    );
}

#[test]
fn sample_1_full() {
    test(
        include_str!("documents/sample_1.xml"),
        include_str!("documents/sample_1_full.txt"),
        false,
    );
}

#[test]
fn sample_2_short() {
    test(
        include_str!("documents/sample_2.xml"),
        include_str!("documents/sample_2_short.txt"),
        true,
    );
}

#[test]
fn sample_2_full() {
    test(
        include_str!("documents/sample_2.xml"),
        include_str!("documents/sample_2_full.txt"),
        false,
    );
}

#[cfg(feature = "escape-html")]
#[test]
fn html5() {
    test(
        include_str!("documents/html5.html"),
        include_str!("documents/html5.txt"),
        false,
    );
}

#[test]
fn bom_removed_from_initial_text() {
    let expected = r#"
        |Characters(asdf)
        |StartElement(paired [attr1="value1", attr2="value2"])
        |Characters(text)
        |EndElement(paired)
        |EndDocument
    "#;

    // BOM right up against the text
    test(
        "\u{FEFF}asdf<paired attr1=\"value1\" attr2=\"value2\">text</paired>",
        expected,
        true,
    );
}

#[test]
fn escaped_characters() {
    test(
        r#"<e attr=""Hello"">'a' < '&'</e>"#,
        r#"
            |StartElement(e [attr=""Hello""])
            |Characters('a' < '&')
            |EndElement(e)
            |EndDocument
        "#,
        true,
    )
}

#[cfg(feature = "escape-html")]
#[test]
fn escaped_characters_html() {
    test(
        r#"<e attr="ℏÈℓ𝕝⨀">╔╗╔╗╔╗</e>"#,
        r#"
            |StartElement(e [attr="ℏÈℓ𝕝⨀"])
            |Characters(╔╗╔╗╔╗)
            |EndElement(e)
            |EndDocument
        "#,
        true,
    )
}

#[cfg(feature = "encoding")]
#[test]
fn encoded_characters() {
    test_bytes(
        b"\
            <?xml version = \"1.0\" encoding = \"Shift_JIS\" ?>\n\
            \x82\xA0\x82\xA2\x82\xA4\
        ",
        "
            |StartDocument(1.0, Shift_JIS)
            |StartElement(a)
            |Characters(あいう)
            |EndElement(a)
            |EndDocument
        "
        .as_bytes(),
        true,
    )
}

// #[test]
// fn sample_3_short() {
//     test(
//         include_str!("documents/sample_3.xml"),
//         include_str!("documents/sample_3_short.txt"),
//         true
//     );
// }

// #[test]
// fn sample_3_full() {
//     test(
//         include_str!("documents/sample_3.xml"),
//         include_str!("documents/sample_3_full.txt"),
//         false
//     );
// }

// #[test]
// fn sample_4_short() {
//     test(
//         include_str!("documents/sample_4.xml"),
//         include_str!("documents/sample_4_short.txt"),
//         true
//     );
// }

// #[test]
// fn sample_4_full() {
//     test(
//         include_str!("documents/sample_4.xml"),
//         include_str!("documents/sample_4_full.txt"),
//         false
//     );
//
// }

#[test]
// FIXME: Trips on the first byte-order-mark byte
// Expected: StartDocument(1.0, utf-16)
// Found: InvalidUtf8([255, 254]; invalid utf-8 sequence of 1 bytes from index 0)
#[ignore]
fn sample_5_short() {
    test_bytes(
        include_bytes!("documents/sample_5_utf16bom.xml"),
        include_bytes!("documents/sample_5_short.txt"),
        true,
    );
}

#[test]
fn sample_ns_short() {
    test(
        include_str!("documents/sample_ns.xml"),
        include_str!("documents/sample_ns_short.txt"),
        true,
    );
}

#[test]
fn eof_1() {
    test(
        r#"<?xml"#,
        r#"Error: Unexpected EOF during reading XmlDecl"#,
        true,
    );
}

#[test]
fn bad_1() {
    test(
        r#"<?xml&.,"#,
        r#"1:6 Error: Unexpected EOF during reading XmlDecl"#,
        true,
    );
}

#[test]
fn dashes_in_comments() {
    test(
        r#"<hello/>"#,
        r#"
        |Error: Unexpected token '--'
        "#,
        true,
    );

    test(
        r#"<hello/>"#,
        r#"
        |Error: Unexpected token '--'
        "#,
        true,
    );

    // Canary test for correct comments
    test(
        r#"<hello/>"#,
        r#"
        |Comment( comment )
        |EmptyElement(hello)
        |EndDocument
        "#,
        true,
    );
}

#[test]
fn tabs_1() {
    test(
        "\t\t",
        r#"
            StartElement(a)
            EmptyElement(b)
            EndElement(a)
            EndDocument
        "#,
        true,
    );
}

#[test]
fn issue_83_duplicate_attributes() {
    // Error when parsing attributes won't stop main event reader
    // as it is a lazy operation => add ending events
    test(
        r#"<hello><some-tag a='10' a="20"/></hello>"#,
        "
            |StartElement(hello)
            |1:30 EmptyElement(some-tag, attr-error: \
                  position 16: duplicated attribute, previous declaration at position 9)
            |EndElement(hello)
            |EndDocument
        ",
        true,
    );
}

#[test]
fn issue_93_large_characters_in_entity_references() {
    test(
        r#"<hello>&𤶼;</hello>"#,
        r#"
            |StartElement(hello)
            |1:10 FailedUnescape([38, 240, 164, 182, 188, 59]; Error while escaping character at range 1..5: Unrecognized escape symbol: "𤶼")
            |EndElement(hello)
            |EndDocument
        "#,
        true,
    )
}

#[test]
fn issue_98_cdata_ending_with_right_bracket() {
    test(
        r#"<hello><![CDATA[Foo [Bar]]]></hello>"#,
        r#"
            |StartElement(hello)
            |CData(Foo [Bar])
            |EndElement(hello)
            |EndDocument
        "#,
        false,
    )
}

#[test]
fn issue_105_unexpected_double_dash() {
    test(
        r#"<hello>-- </hello>"#,
        r#"
            |StartElement(hello)
            |Characters(-- )
            |EndElement(hello)
            |EndDocument
        "#,
        false,
    );

    test(
        r#"<hello>--</hello>"#,
        r#"
            |StartElement(hello)
            |Characters(--)
            |EndElement(hello)
            |EndDocument
        "#,
        false,
    );

    test(
        r#"<hello>--></hello>"#,
        r#"
            |StartElement(hello)
            |Characters(-->)
            |EndElement(hello)
            |EndDocument
        "#,
        false,
    );

    test(
        r#"<hello><![CDATA[--]]></hello>"#,
        r#"
            |StartElement(hello)
            |CData(--)
            |EndElement(hello)
            |EndDocument
        "#,
        false,
    );
}

#[test]
fn issue_attributes_have_no_default_namespace() {
    // At the moment, the 'test' method doesn't render namespaces for attribute names.
    // This test only checks whether the default namespace got applied to the EmptyElement.
    test(
        r#"<hello xmlns="urn:foo" x="y"/>"#,
        r#"
             |EmptyElement({urn:foo}hello [x="y"])
             |EndDocument
         "#,
        true,
    );
}

#[test]
fn issue_default_namespace_on_outermost_element() {
    // Regression test
    test(
        r#"<hello xmlns="urn:foo"/>"#,
        r#"
                |EmptyElement({urn:foo}hello)
                |EndDocument
            "#,
        true,
    );
}

#[test]
fn default_namespace_applies_to_end_elem() {
    test(
        r#"<hello xmlns="urn:foo" x="y">
              <inner/>
            </hello>"#,
        r#"
            |StartElement({urn:foo}hello [x="y"])
            |EmptyElement({urn:foo}inner)
            |EndElement({urn:foo}hello)
            |EndDocument
        "#,
        true,
    );
}

#[track_caller]
fn test(input: &str, output: &str, trim: bool) {
    test_bytes(input.as_bytes(), output.as_bytes(), trim);
}

#[track_caller]
fn test_bytes(input: &[u8], output: &[u8], trim: bool) {
    let mut reader = NsReader::from_reader(input);
    reader
        .trim_text(trim)
        .check_comments(true)
        .expand_empty_elements(false);

    let mut spec_lines = SpecIter(output).enumerate();

    let mut decoder = reader.decoder();
    loop {
        let line = match reader.read_resolved_event() {
            Ok((_, Event::Decl(e))) => {
                // Declaration could change decoder
                decoder = reader.decoder();

                let version_cow = e.version().unwrap();
                let version = decoder.decode(version_cow.as_ref()).unwrap();
                let encoding_cow = e.encoding().unwrap().unwrap();
                let encoding = decoder.decode(encoding_cow.as_ref()).unwrap();
                format!("StartDocument({}, {})", version, encoding)
            }
            Ok((_, Event::PI(e))) => {
                format!("ProcessingInstruction(PI={})", decoder.decode(&e).unwrap())
            }
            Ok((_, Event::DocType(e))) => format!("DocType({})", decoder.decode(&e).unwrap()),
            Ok((n, Event::Start(e))) => {
                let name = namespace_name(n, e.name(), decoder);
                match make_attrs(&e, decoder) {
                    Ok(attrs) if attrs.is_empty() => format!("StartElement({})", &name),
                    Ok(attrs) => format!("StartElement({} [{}])", &name, &attrs),
                    Err(e) => format!("StartElement({}, attr-error: {})", &name, &e),
                }
            }
            Ok((n, Event::Empty(e))) => {
                let name = namespace_name(n, e.name(), decoder);
                match make_attrs(&e, decoder) {
                    Ok(attrs) if attrs.is_empty() => format!("EmptyElement({})", &name),
                    Ok(attrs) => format!("EmptyElement({} [{}])", &name, &attrs),
                    Err(e) => format!("EmptyElement({}, attr-error: {})", &name, &e),
                }
            }
            Ok((n, Event::End(e))) => {
                let name = namespace_name(n, e.name(), decoder);
                format!("EndElement({})", name)
            }
            Ok((_, Event::Comment(e))) => format!("Comment({})", decoder.decode(&e).unwrap()),
            Ok((_, Event::CData(e))) => format!("CData({})", decoder.decode(&e).unwrap()),
            Ok((_, Event::Text(e))) => match unescape(&decoder.decode(&e).unwrap()) {
                Ok(c) => format!("Characters({})", &c),
                Err(err) => format!("FailedUnescape({:?}; {})", e.as_ref(), err),
            },
            Ok((_, Event::Eof)) => format!("EndDocument"),
            Err(e) => format!("Error: {}", e),
        };
        if let Some((n, spec)) = spec_lines.next() {
            if spec.trim() == "EndDocument" {
                break;
            }
            if line.trim() != spec.trim() {
                panic!(
                    "\n-------------------\n\
                     Unexpected event at line {}:\n\
                     Expected: {}\nFound: {}\n\
                     -------------------\n",
                    n + 1,
                    spec,
                    line
                );
            }
        } else {
            if line == "EndDocument" {
                break;
            }
            panic!("Unexpected event: {}", line);
        }
    }
}

fn namespace_name(n: ResolveResult, name: QName, decoder: Decoder) -> String {
    let name = decoder.decode(name.as_ref()).unwrap();
    match n {
        // Produces string '{namespace}prefixed_name'
        ResolveResult::Bound(n) => format!("{{{}}}{}", decoder.decode(n.as_ref()).unwrap(), name),
        _ => name.to_string(),
    }
}

fn make_attrs(e: &BytesStart, decoder: Decoder) -> ::std::result::Result<String, String> {
    let mut atts = Vec::new();
    for a in e.attributes() {
        match a {
            Ok(a) => {
                if a.key.as_namespace_binding().is_none() {
                    let key = decoder.decode(a.key.as_ref()).unwrap();
                    let value = decoder.decode(a.value.as_ref()).unwrap();
                    let unescaped_value = unescape(&value).unwrap();
                    atts.push(format!(
                        "{}=\"{}\"",
                        key,
                        // unescape does not change validity of an UTF-8 string
                        &unescaped_value
                    ));
                }
            }
            Err(e) => return Err(e.to_string()),
        }
    }
    Ok(atts.join(", "))
}

struct SpecIter<'a>(&'a [u8]);

impl<'a> Iterator for SpecIter<'a> {
    type Item = &'a str;
    fn next(&mut self) -> Option<&'a str> {
        let start = self
            .0
            .iter()
            .position(|b| !matches!(*b, b' ' | b'\r' | b'\n' | b'\t' | b'|' | b':' | b'0'..=b'9'))
            .unwrap_or(0);

        if let Some(p) = self.0.windows(3).position(|w| w == b")\r\n") {
            let (prev, next) = self.0.split_at(p + 1);
            self.0 = &next[1..];
            Some(from_utf8(&prev[start..]).expect("Error decoding to uft8"))
        } else if let Some(p) = self.0.windows(2).position(|w| w == b")\n") {
            let (prev, next) = self.0.split_at(p + 1);
            self.0 = next;
            Some(from_utf8(&prev[start..]).expect("Error decoding to uft8"))
        } else if self.0.is_empty() {
            None
        } else {
            let p = self.0;
            self.0 = &[];
            Some(from_utf8(&p[start..]).unwrap())
        }
    }
}
<commit_msg>Use pretty_assertions when compare events in reader tests<commit_after>use pretty_assertions::assert_eq;
use quick_xml::encoding::Decoder;
use quick_xml::escape::unescape;
use quick_xml::events::{BytesStart, Event};
use quick_xml::name::{QName, ResolveResult};
use quick_xml::reader::NsReader;
use std::str::from_utf8;

#[test]
fn sample_1_short() {
    test(
        include_str!("documents/sample_1.xml"),
        include_str!("documents/sample_1_short.txt"),
        true,
    );
}

#[test]
fn sample_1_full() {
    test(
        include_str!("documents/sample_1.xml"),
        include_str!("documents/sample_1_full.txt"),
        false,
    );
}

#[test]
fn sample_2_short() {
    test(
        include_str!("documents/sample_2.xml"),
        include_str!("documents/sample_2_short.txt"),
        true,
    );
}

#[test]
fn sample_2_full() {
    test(
        include_str!("documents/sample_2.xml"),
        include_str!("documents/sample_2_full.txt"),
        false,
    );
}

#[cfg(feature = "escape-html")]
#[test]
fn html5() {
    test(
        include_str!("documents/html5.html"),
        include_str!("documents/html5.txt"),
        false,
    );
}

#[test]
fn bom_removed_from_initial_text() {
    let expected = r#"
        |Characters(asdf)
        |StartElement(paired [attr1="value1", attr2="value2"])
        |Characters(text)
        |EndElement(paired)
        |EndDocument
    "#;

    // BOM right up against the text
    test(
        "\u{FEFF}asdf<paired attr1=\"value1\" attr2=\"value2\">text</paired>",
        expected,
        true,
    );
}

#[test]
fn escaped_characters() {
    test(
        r#"<e attr=""Hello"">'a' < '&'</e>"#,
        r#"
            |StartElement(e [attr=""Hello""])
            |Characters('a' < '&')
            |EndElement(e)
            |EndDocument
        "#,
        true,
    )
}

#[cfg(feature = "escape-html")]
#[test]
fn escaped_characters_html() {
    test(
        r#"<e attr="ℏÈℓ𝕝⨀">╔╗╔╗╔╗</e>"#,
        r#"
            |StartElement(e [attr="ℏÈℓ𝕝⨀"])
            |Characters(╔╗╔╗╔╗)
            |EndElement(e)
            |EndDocument
        "#,
        true,
    )
}

#[cfg(feature = "encoding")]
#[test]
fn encoded_characters() {
    test_bytes(
        b"\
            <?xml version = \"1.0\" encoding = \"Shift_JIS\" ?>\n\
            \x82\xA0\x82\xA2\x82\xA4\
        ",
        "
            |StartDocument(1.0, Shift_JIS)
            |StartElement(a)
            |Characters(あいう)
            |EndElement(a)
            |EndDocument
        "
        .as_bytes(),
        true,
    )
}

// #[test]
// fn sample_3_short() {
//     test(
//         include_str!("documents/sample_3.xml"),
//         include_str!("documents/sample_3_short.txt"),
//         true
//     );
// }

// #[test]
// fn sample_3_full() {
//     test(
//         include_str!("documents/sample_3.xml"),
//         include_str!("documents/sample_3_full.txt"),
//         false
//     );
// }

// #[test]
// fn sample_4_short() {
//     test(
//         include_str!("documents/sample_4.xml"),
//         include_str!("documents/sample_4_short.txt"),
//         true
//     );
// }

// #[test]
// fn sample_4_full() {
//     test(
//         include_str!("documents/sample_4.xml"),
//         include_str!("documents/sample_4_full.txt"),
//         false
//     );
//
// }

#[test]
// FIXME: Trips on the first byte-order-mark byte
// Expected: StartDocument(1.0, utf-16)
// Found: InvalidUtf8([255, 254]; invalid utf-8 sequence of 1 bytes from index 0)
#[ignore]
fn sample_5_short() {
    test_bytes(
        include_bytes!("documents/sample_5_utf16bom.xml"),
        include_bytes!("documents/sample_5_short.txt"),
        true,
    );
}

#[test]
fn sample_ns_short() {
    test(
        include_str!("documents/sample_ns.xml"),
        include_str!("documents/sample_ns_short.txt"),
        true,
    );
}

#[test]
fn eof_1() {
    test(
        r#"<?xml"#,
        r#"Error: Unexpected EOF during reading XmlDecl"#,
        true,
    );
}

#[test]
fn bad_1() {
    test(
        r#"<?xml&.,"#,
        r#"1:6 Error: Unexpected EOF during reading XmlDecl"#,
        true,
    );
}

#[test]
fn dashes_in_comments() {
    test(
        r#"<hello/>"#,
        r#"
        |Error: Unexpected token '--'
        "#,
        true,
    );

    test(
        r#"<hello/>"#,
        r#"
        |Error: Unexpected token '--'
        "#,
        true,
    );

    // Canary test for correct comments
    test(
        r#"<hello/>"#,
        r#"
        |Comment( comment )
        |EmptyElement(hello)
        |EndDocument
        "#,
        true,
    );
}

#[test]
fn tabs_1() {
    test(
        "\t\t",
        r#"
            StartElement(a)
            EmptyElement(b)
            EndElement(a)
            EndDocument
        "#,
        true,
    );
}

#[test]
fn issue_83_duplicate_attributes() {
    // Error when parsing attributes won't stop main event reader
    // as it is a lazy operation => add ending events
    test(
        r#"<hello><some-tag a='10' a="20"/></hello>"#,
        "
            |StartElement(hello)
            |1:30 EmptyElement(some-tag, attr-error: \
                  position 16: duplicated attribute, previous declaration at position 9)
            |EndElement(hello)
            |EndDocument
        ",
        true,
    );
}

#[test]
fn issue_93_large_characters_in_entity_references() {
    test(
        r#"<hello>&𤶼;</hello>"#,
        r#"
            |StartElement(hello)
            |1:10 FailedUnescape([38, 240, 164, 182, 188, 59]; Error while escaping character at range 1..5: Unrecognized escape symbol: "𤶼")
            |EndElement(hello)
            |EndDocument
        "#,
        true,
    )
}

#[test]
fn issue_98_cdata_ending_with_right_bracket() {
    test(
        r#"<hello><![CDATA[Foo [Bar]]]></hello>"#,
        r#"
            |StartElement(hello)
            |CData(Foo [Bar])
            |EndElement(hello)
            |EndDocument
        "#,
        false,
    )
}

#[test]
fn issue_105_unexpected_double_dash() {
    test(
        r#"<hello>-- </hello>"#,
        r#"
            |StartElement(hello)
            |Characters(-- )
            |EndElement(hello)
            |EndDocument
        "#,
        false,
    );

    test(
        r#"<hello>--</hello>"#,
        r#"
            |StartElement(hello)
            |Characters(--)
            |EndElement(hello)
            |EndDocument
        "#,
        false,
    );

    test(
        r#"<hello>--></hello>"#,
        r#"
            |StartElement(hello)
            |Characters(-->)
            |EndElement(hello)
            |EndDocument
        "#,
        false,
    );

    test(
        r#"<hello><![CDATA[--]]></hello>"#,
        r#"
            |StartElement(hello)
            |CData(--)
            |EndElement(hello)
            |EndDocument
        "#,
        false,
    );
}

#[test]
fn issue_attributes_have_no_default_namespace() {
    // At the moment, the 'test' method doesn't render namespaces for attribute names.
    // This test only checks whether the default namespace got applied to the EmptyElement.
    test(
        r#"<hello xmlns="urn:foo" x="y"/>"#,
        r#"
             |EmptyElement({urn:foo}hello [x="y"])
             |EndDocument
         "#,
        true,
    );
}

#[test]
fn issue_default_namespace_on_outermost_element() {
    // Regression test
    test(
        r#"<hello xmlns="urn:foo"/>"#,
        r#"
                |EmptyElement({urn:foo}hello)
                |EndDocument
            "#,
        true,
    );
}

#[test]
fn default_namespace_applies_to_end_elem() {
    test(
        r#"<hello xmlns="urn:foo" x="y">
              <inner/>
            </hello>"#,
        r#"
            |StartElement({urn:foo}hello [x="y"])
            |EmptyElement({urn:foo}inner)
            |EndElement({urn:foo}hello)
            |EndDocument
        "#,
        true,
    );
}

#[track_caller]
fn test(input: &str, output: &str, trim: bool) {
    test_bytes(input.as_bytes(), output.as_bytes(), trim);
}

#[track_caller]
fn test_bytes(input: &[u8], output: &[u8], trim: bool) {
    let mut reader = NsReader::from_reader(input);
    reader
        .trim_text(trim)
        .check_comments(true)
        .expand_empty_elements(false);

    let mut spec_lines = SpecIter(output).enumerate();

    let mut decoder = reader.decoder();
    loop {
        let line = match reader.read_resolved_event() {
            Ok((_, Event::Decl(e))) => {
                // Declaration could change decoder
                decoder = reader.decoder();

                let version_cow = e.version().unwrap();
                let version = decoder.decode(version_cow.as_ref()).unwrap();
                let encoding_cow = e.encoding().unwrap().unwrap();
                let encoding = decoder.decode(encoding_cow.as_ref()).unwrap();
                format!("StartDocument({}, {})", version, encoding)
            }
            Ok((_, Event::PI(e))) => {
                format!("ProcessingInstruction(PI={})", decoder.decode(&e).unwrap())
            }
            Ok((_, Event::DocType(e))) => format!("DocType({})", decoder.decode(&e).unwrap()),
            Ok((n, Event::Start(e))) => {
                let name = namespace_name(n, e.name(), decoder);
                match make_attrs(&e, decoder) {
                    Ok(attrs) if attrs.is_empty() => format!("StartElement({})", &name),
                    Ok(attrs) => format!("StartElement({} [{}])", &name, &attrs),
                    Err(e) => format!("StartElement({}, attr-error: {})", &name, &e),
                }
            }
            Ok((n, Event::Empty(e))) => {
                let name = namespace_name(n, e.name(), decoder);
                match make_attrs(&e, decoder) {
                    Ok(attrs) if attrs.is_empty() => format!("EmptyElement({})", &name),
                    Ok(attrs) => format!("EmptyElement({} [{}])", &name, &attrs),
                    Err(e) => format!("EmptyElement({}, attr-error: {})", &name, &e),
                }
            }
            Ok((n, Event::End(e))) => {
                let name = namespace_name(n, e.name(), decoder);
                format!("EndElement({})", name)
            }
            Ok((_, Event::Comment(e))) => format!("Comment({})", decoder.decode(&e).unwrap()),
            Ok((_, Event::CData(e))) => format!("CData({})", decoder.decode(&e).unwrap()),
            Ok((_, Event::Text(e))) => match unescape(&decoder.decode(&e).unwrap()) {
                Ok(c) => format!("Characters({})", &c),
                Err(err) => format!("FailedUnescape({:?}; {})", e.as_ref(), err),
            },
            Ok((_, Event::Eof)) => format!("EndDocument"),
            Err(e) => format!("Error: {}", e),
        };
        if let Some((n, spec)) = spec_lines.next() {
            if spec.trim() == "EndDocument" {
                break;
            }
            assert_eq!(
                line.trim(),
                spec.trim(),
                "Unexpected event at line {}",
                n + 1
            );
        } else {
            if line == "EndDocument" {
                break;
            }
            panic!("Unexpected event: {}", line);
        }
    }
}

fn namespace_name(n: ResolveResult, name: QName, decoder: Decoder) -> String {
    let name = decoder.decode(name.as_ref()).unwrap();
    match n {
        // Produces string '{namespace}prefixed_name'
        ResolveResult::Bound(n) => format!("{{{}}}{}", decoder.decode(n.as_ref()).unwrap(), name),
        _ => name.to_string(),
    }
}

fn make_attrs(e: &BytesStart, decoder: Decoder) -> ::std::result::Result<String, String> {
    let mut atts = Vec::new();
    for a in e.attributes() {
        match a {
            Ok(a) => {
                if a.key.as_namespace_binding().is_none() {
                    let key = decoder.decode(a.key.as_ref()).unwrap();
                    let value = decoder.decode(a.value.as_ref()).unwrap();
                    let unescaped_value = unescape(&value).unwrap();
                    atts.push(format!(
                        "{}=\"{}\"",
                        key,
                        // unescape does not change validity of an UTF-8 string
                        &unescaped_value
                    ));
                }
            }
            Err(e) => return Err(e.to_string()),
        }
    }
    Ok(atts.join(", "))
}

struct SpecIter<'a>(&'a [u8]);

impl<'a> Iterator for SpecIter<'a> {
    type Item = &'a str;
    fn next(&mut self) -> Option<&'a str> {
        let start = self
            .0
            .iter()
            .position(|b| !matches!(*b, b' ' | b'\r' | b'\n' | b'\t' | b'|' | b':' | b'0'..=b'9'))
            .unwrap_or(0);

        if let Some(p) = self.0.windows(3).position(|w| w == b")\r\n") {
            let (prev, next) = self.0.split_at(p + 1);
            self.0 = &next[1..];
            Some(from_utf8(&prev[start..]).expect("Error decoding to uft8"))
        } else if let Some(p) = self.0.windows(2).position(|w| w == b")\n") {
            let (prev, next) = self.0.split_at(p + 1);
            self.0 = next;
            Some(from_utf8(&prev[start..]).expect("Error decoding to uft8"))
        } else if self.0.is_empty() {
            None
        } else {
            let p = self.0;
            self.0 = &[];
            Some(from_utf8(&p[start..]).unwrap())
        }
    }
}
<|endoftext|>


<commit_before>use std::{cmp, io::{self, Write, Read}, iter::repeat, ptr};

#[derive(Debug,PartialEq,Clone)]
pub struct Buffer {
  memory:   Vec<u8>,
  capacity: usize,
  position: usize,
  end:      usize
}

impl Buffer {
  pub fn with_capacity(capacity: usize) -> Buffer {
    let mut v = Vec::with_capacity(capacity);
    v.extend(repeat(0).take(capacity));
    Buffer {
      memory:   v,
      capacity: capacity,
      position: 0,
      end:      0
    }
  }

  pub fn grow(&mut self, new_size: usize) -> bool {
    if self.capacity >= new_size {
      return false;
    }

    self.memory.resize(new_size, 0);
    self.capacity = new_size;
    true
  }

  pub fn available_data(&self) -> usize {
    self.end - self.position
  }

  pub fn available_space(&self) -> usize {
    self.capacity - self.end
  }

  pub fn consume(&mut self, count: usize) -> usize {
    let cnt        = cmp::min(count, self.available_data());
    self.position += cnt;
    if self.position > self.capacity / 2 {
      //trace!("consume shift: pos {}, end {}", self.position, self.end);
      self.shift();
    }
    cnt
  }

  pub fn fill(&mut self, count: usize) -> usize {
    let cnt   = cmp::min(count, self.available_space());
    self.end += cnt;
    if self.available_space() < self.available_data() + cnt {
      //trace!("fill shift: pos {}, end {}", self.position, self.end);
      self.shift();
    }

    cnt
  }

  pub fn data(&self) -> &[u8] {
    &self.memory[self.position..self.end]
  }

  pub fn space(&mut self) -> &mut[u8] {
    &mut self.memory[self.end..self.capacity]
  }

  fn shift(&mut self) {
    if self.position > 0 {
      unsafe {
        let length = self.end - self.position;
        ptr::copy( (&self.memory[self.position..self.end]).as_ptr(), (&mut self.memory[..length]).as_mut_ptr(), length);
        self.position = 0;
        self.end      = length;
      }
    }
  }
}

impl Write for Buffer {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    match self.space().write(buf) {
      Ok(size) => { self.fill(size); Ok(size) },
      err      => err
    }
  }

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

impl Read for Buffer {
  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
    let len = cmp::min(self.available_data(), buf.len());
    unsafe {
      ptr::copy((&self.memory[self.position..len]).as_ptr(), buf.as_mut_ptr(), len);
      self.position += len;
    }
    Ok(len)
  }
}

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

  #[test]
  fn fill_and_consume() {
    let mut b = Buffer::with_capacity(10);
    assert_eq!(b.available_data(), 0);
    assert_eq!(b.available_space(), 10);
    let res = b.write(&b"abcd"[..]);
    assert_eq!(res.ok(), Some(4));
    assert_eq!(b.available_data(), 4);
    assert_eq!(b.available_space(), 6);

    assert_eq!(b.data(), &b"abcd"[..]);

    b.consume(2);
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 6);
    assert_eq!(b.data(), &b"cd"[..]);

    b.shift();
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 8);
    assert_eq!(b.data(), &b"cd"[..]);

    assert_eq!(b.write(&b"efghijklmnop"[..]).ok(), Some(8));
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
    b.shift();
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
  }
}
<commit_msg>async: buffer cleanups<commit_after>use std::{cmp, io::{self, Write, Read}, iter::repeat, ptr};

#[derive(Debug,PartialEq,Clone)]
pub struct Buffer {
  memory:   Vec<u8>,
  capacity: usize,
  position: usize,
  end:      usize
}

impl Buffer {
  pub fn with_capacity(capacity: usize) -> Buffer {
    let mut v = Vec::with_capacity(capacity);
    v.extend(repeat(0).take(capacity));
    Buffer {
      memory:   v,
      capacity,
      position: 0,
      end:      0
    }
  }

  pub fn grow(&mut self, new_size: usize) -> bool {
    if self.capacity >= new_size {
      return false;
    }

    self.memory.resize(new_size, 0);
    self.capacity = new_size;
    true
  }

  pub fn available_data(&self) -> usize {
    self.end - self.position
  }

  pub fn available_space(&self) -> usize {
    self.capacity - self.end
  }

  pub fn consume(&mut self, count: usize) -> usize {
    let cnt        = cmp::min(count, self.available_data());
    self.position += cnt;
    if self.position > self.capacity / 2 {
      self.shift();
    }
    cnt
  }

  pub fn fill(&mut self, count: usize) -> usize {
    if self.available_space() < self.position {
      self.shift();
    }
    let cnt   = cmp::min(count, self.available_space());
    self.end += cnt;
    cnt
  }

  pub fn data(&self) -> &[u8] {
    &self.memory[self.position..self.end]
  }

  pub fn space(&mut self) -> &mut [u8] {
    &mut self.memory[self.end..self.capacity]
  }

  fn shift(&mut self) {
    let length = self.end - self.position;
    unsafe {
      ptr::copy((&self.memory[self.position..self.end]).as_ptr(), (&mut self.memory[..length]).as_mut_ptr(), length);
    }
    self.position = 0;
    self.end      = length;
  }
}

impl Write for Buffer {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    self.space().write(buf).map(|size| {
      self.fill(size);
      size
    })
  }

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

impl Read for Buffer {
  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
    let len = cmp::min(self.available_data(), buf.len());
    buf.copy_from_slice(&self.memory[self.position..len]);
    self.position += len;
    Ok(len)
  }
}

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

  #[test]
  fn fill_and_consume() {
    let mut b = Buffer::with_capacity(10);
    assert_eq!(b.available_data(), 0);
    assert_eq!(b.available_space(), 10);
    let res = b.write(&b"abcd"[..]);
    assert_eq!(res.ok(), Some(4));
    assert_eq!(b.available_data(), 4);
    assert_eq!(b.available_space(), 6);

    assert_eq!(b.data(), &b"abcd"[..]);

    b.consume(2);
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 6);
    assert_eq!(b.data(), &b"cd"[..]);

    b.shift();
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 8);
    assert_eq!(b.data(), &b"cd"[..]);

    assert_eq!(b.write(&b"efghijklmnop"[..]).ok(), Some(8));
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
    b.shift();
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
  }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate regex;

include!("../clap-test.rs");

use clap::{App, SubCommand, ErrorKind};

static HELP: &'static str = "clap-test v1.4.8
Kevin K. <kbknapp@gmail.com>
tests clap library

USAGE:
    clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]

FLAGS:
    -f, --flag       tests flags
    -F               tests flags with exclusions
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -O, --Option <option3>           specific vals [values: fast, slow]
        --long-option-2 <option2>    tests long options with exclusions
        --maxvals3 <maxvals>...      Tests 3 max vals
        --minvals2 <minvals>...      Tests 2 min vals
        --multvals <one> <two>       Tests mutliple values, not mult occs
        --multvalsmo <one> <two>     Tests mutliple values, and mult occs
    -o, --option <opt>...            tests options

ARGS:
    <positional>        tests positionals
    <positional2>       tests positionals with exclusions
    <positional3>...    tests specific values [values: vi, emacs]

SUBCOMMANDS:
    help      Prints this message or the help of the given subcommand(s)
    subcmd    tests subcommands";

static SC_HELP: &'static str = "subcmd 0.1
Kevin K. <kbknapp@gmail.com>
tests subcommands

USAGE:
    subcmd [FLAGS] [OPTIONS] [--] [ARGS]

FLAGS:
    -f, --flag    tests flags

OPTIONS:
    -o, --option <scoption>...    tests options

ARGS:
    <scpositional>    tests positionals";

#[test]
fn help_short() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "-h"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn help_long() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "--help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn help_no_subcommand() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::UnknownArgument);
}

#[test]
fn help_subcommand() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .subcommand(SubCommand::with_name("test")
            .about("tests things")
            .arg_from_usage("-v --verbose 'with verbosity'"))
        .get_matches_from_safe(vec!["myprog", "help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_short_help() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "subcmd", "-h"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_long_help() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "subcmd", "--help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_help_rev() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "help", "subcmd"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn complex_help_output() {
    test::check_help(test::complex_app(), HELP);
}

#[test]
fn complex_subcommand_help_output() {
    let mut a = test::complex_app();
    let _ = a.get_matches_from_safe_borrow(vec![""]);
    let sc = a.p.subcommands.iter().filter(|s| s.p.meta.name == "subcmd").next().unwrap();
    // Now we check the output of print_help()
    let mut help = vec![];
    sc.write_help(&mut help).ok().expect("failed to print help");
    assert_eq!(&*String::from_utf8(help).unwrap(), SC_HELP);
}
<commit_msg>tests: adds test to check for before_help<commit_after>extern crate clap;
extern crate regex;

include!("../clap-test.rs");

use clap::{App, SubCommand, ErrorKind};

static HELP: &'static str = "clap-test v1.4.8
Kevin K. <kbknapp@gmail.com>
tests clap library

USAGE:
    clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]

FLAGS:
    -f, --flag       tests flags
    -F               tests flags with exclusions
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -O, --Option <option3>           specific vals [values: fast, slow]
        --long-option-2 <option2>    tests long options with exclusions
        --maxvals3 <maxvals>...      Tests 3 max vals
        --minvals2 <minvals>...      Tests 2 min vals
        --multvals <one> <two>       Tests mutliple values, not mult occs
        --multvalsmo <one> <two>     Tests mutliple values, and mult occs
    -o, --option <opt>...            tests options

ARGS:
    <positional>        tests positionals
    <positional2>       tests positionals with exclusions
    <positional3>...    tests specific values [values: vi, emacs]

SUBCOMMANDS:
    help      Prints this message or the help of the given subcommand(s)
    subcmd    tests subcommands";

static AFTER_HELP: &'static str = "some text that comes before the help

clap-test v1.4.8
tests clap library

USAGE:
    clap-test [FLAGS]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

some text that comes after the help";

static SC_HELP: &'static str = "subcmd 0.1
Kevin K. <kbknapp@gmail.com>
tests subcommands

USAGE:
    subcmd [FLAGS] [OPTIONS] [--] [ARGS]

FLAGS:
    -f, --flag    tests flags

OPTIONS:
    -o, --option <scoption>...    tests options

ARGS:
    <scpositional>    tests positionals";

#[test]
fn help_short() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "-h"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn help_long() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "--help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn help_no_subcommand() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .get_matches_from_safe(vec!["myprog", "help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::UnknownArgument);
}

#[test]
fn help_subcommand() {
    let m = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .subcommand(SubCommand::with_name("test")
            .about("tests things")
            .arg_from_usage("-v --verbose 'with verbosity'"))
        .get_matches_from_safe(vec!["myprog", "help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_short_help() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "subcmd", "-h"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_long_help() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "subcmd", "--help"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn subcommand_help_rev() {
    let m = test::complex_app()
        .get_matches_from_safe(vec!["clap-test", "help", "subcmd"]);

    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn complex_help_output() {
    test::check_help(test::complex_app(), HELP);
}

#[test]
fn after_and_before_help_output() {
    let app = App::new("clap-test")
        .version("v1.4.8")
        .about("tests clap library")
        .before_help("some text that comes before the help")
        .after_help("some text that comes after the help");
    test::check_help(app, AFTER_HELP);
}

#[test]
fn complex_subcommand_help_output() {
    let mut a = test::complex_app();
    let _ = a.get_matches_from_safe_borrow(vec![""]);
    let sc = a.p.subcommands.iter().filter(|s| s.p.meta.name == "subcmd").next().unwrap();
    // Now we check the output of print_help()
    let mut help = vec![];
    sc.write_help(&mut help).ok().expect("failed to print help");
    assert_eq!(&*String::from_utf8(help).unwrap(), SC_HELP);
}
<|endoftext|>


<commit_before>extern crate diesel;
extern crate r2d2;
extern crate r2d2_diesel;

use std::sync::Arc;
use std::sync::mpsc;
use std::thread;

use diesel::pg::PgConnection;
use r2d2_diesel::ConnectionManager;

#[test]
fn basic_connection() {
    let manager = ConnectionManager::<PgConnection>::new("postgres://localhost/");
    let config = r2d2::Config::builder().pool_size(2).build();
    let pool = Arc::new(r2d2::Pool::new(config, manager).unwrap());

    let (s1, r1) = mpsc::channel();
    let (s2, r2) = mpsc::channel();

    let pool1 = pool.clone();
    let t1 = thread::spawn(move || {
        let conn = pool1.get().unwrap();
        s1.send(()).unwrap();
        r2.recv().unwrap();
        drop(conn);
    });

    let pool2 = pool.clone();
    let t2 = thread::spawn(move || {
        let conn = pool2.get().unwrap();
        s2.send(()).unwrap();
        r1.recv().unwrap();
        drop(conn);
    });

    t1.join().unwrap();
    t2.join().unwrap();

    pool.get().unwrap();
}

#[test]
fn is_valid() {
    let manager = ConnectionManager::<PgConnection>::new("postgres://localhost/");
    let config = r2d2::Config::builder().pool_size(1).test_on_check_out(true).build();
    let pool = r2d2::Pool::new(config, manager).unwrap();

    pool.get().unwrap();
}
<commit_msg>add sqlite tests<commit_after>extern crate diesel;
extern crate r2d2;
extern crate r2d2_diesel;

use std::sync::Arc;
use std::sync::mpsc;
use std::thread;

use diesel::pg::PgConnection;
use r2d2_diesel::ConnectionManager;

#[cfg(feature = "sqlite")]
use diesel::sqlite::SqliteConnection;

#[test]
fn pg_basic_connection() {
    let manager = ConnectionManager::<PgConnection>::new("postgres://localhost/");
    let config = r2d2::Config::builder().pool_size(2).build();
    let pool = Arc::new(r2d2::Pool::new(config, manager).unwrap());

    let (s1, r1) = mpsc::channel();
    let (s2, r2) = mpsc::channel();

    let pool1 = pool.clone();
    let t1 = thread::spawn(move || {
        let conn = pool1.get().unwrap();
        s1.send(()).unwrap();
        r2.recv().unwrap();
        drop(conn);
    });

    let pool2 = pool.clone();
    let t2 = thread::spawn(move || {
        let conn = pool2.get().unwrap();
        s2.send(()).unwrap();
        r1.recv().unwrap();
        drop(conn);
    });

    t1.join().unwrap();
    t2.join().unwrap();

    pool.get().unwrap();
}

#[test]
fn pg_is_valid() {
    let manager = ConnectionManager::<PgConnection>::new("postgres://localhost/");
    let config = r2d2::Config::builder().pool_size(1).test_on_check_out(true).build();
    let pool = r2d2::Pool::new(config, manager).unwrap();

    pool.get().unwrap();
}

#[cfg(feature = "sqlite")]
#[test]
fn sqlite_basic_connection() {
    let manager = ConnectionManager::<SqliteConnection>::new("test.db");
    let config = r2d2::Config::builder().pool_size(2).build();
    let pool = Arc::new(r2d2::Pool::new(config, manager).unwrap());

    let (s1, r1) = mpsc::channel();
    let (s2, r2) = mpsc::channel();

    let pool1 = pool.clone();
    let t1 = thread::spawn(move || {
        let conn = pool1.get().unwrap();
        s1.send(()).unwrap();
        r2.recv().unwrap();
        drop(conn);
    });

    let pool2 = pool.clone();
    let t2 = thread::spawn(move || {
        let conn = pool2.get().unwrap();
        s2.send(()).unwrap();
        r1.recv().unwrap();
        drop(conn);
    });

    t1.join().unwrap();
    t2.join().unwrap();

    pool.get().unwrap();
}

#[cfg(feature = "sqlite")]
#[test]
fn sqlite_is_valid() {
    let manager = ConnectionManager::<SqliteConnection>::new("test.db");
    let config = r2d2::Config::builder().pool_size(1).test_on_check_out(true).build();
    let pool = r2d2::Pool::new(config, manager).unwrap();

    pool.get().unwrap();
}
<|endoftext|>


<commit_before>use bytes::Buf;
use std::io;
use std::ops::DerefMut;
use std::pin::Pin;
use std::task::{Context, Poll};

/// Writes bytes asynchronously.
///
/// The trait inherits from [`std::io::Write`] and indicates that an I/O object is
/// **nonblocking**. All non-blocking I/O objects must return an error when
/// bytes cannot be written instead of blocking the current thread.
///
/// Specifically, this means that the [`poll_write`] function will return one of
/// the following:
///
/// * `Poll::Ready(Ok(n))` means that `n` bytes of data was immediately
///   written.
///
/// * `Poll::Pending` means that no data was written from the buffer
///   provided. The I/O object is not currently writable but may become writable
///   in the future. Most importantly, **the current future's task is scheduled
///   to get unparked when the object is writable**. This means that like
///   `Future::poll` you'll receive a notification when the I/O object is
///   writable again.
///
/// * `Poll::Ready(Err(e))` for other errors are standard I/O errors coming from the
///   underlying object.
///
/// This trait importantly means that the [`write`][stdwrite] method only works in
/// the context of a future's task. The object may panic if used outside of a task.
///
/// Note that this trait also represents that the  [`Write::flush`][stdflush] method
/// works very similarly to the `write` method, notably that `Ok(())` means that the
/// writer has successfully been flushed, a "would block" error means that the
/// current task is ready to receive a notification when flushing can make more
/// progress, and otherwise normal errors can happen as well.
///
/// Utilities for working with `AsyncWrite` values are provided by
/// [`AsyncWriteExt`].
///
/// [`std::io::Write`]: std::io::Write
/// [`poll_write`]: AsyncWrite::poll_write()
/// [stdwrite]: std::io::Write::write()
/// [stdflush]: std::io::Write::flush()
/// [`AsyncWriteExt`]: crate::io::AsyncWriteExt
pub trait AsyncWrite {
    /// Attempt to write bytes from `buf` into the object.
    ///
    /// On success, returns `Poll::Ready(Ok(num_bytes_written))`.
    ///
    /// If the object is not ready for writing, the method returns
    /// `Poll::Pending` and arranges for the current task (via
    /// `cx.waker()`) to receive a notification when the object becomes
    /// readable or is closed.
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<Result<usize, io::Error>>;

    /// Attempts to flush the object, ensuring that any buffered data reach
    /// their destination.
    ///
    /// On success, returns `Poll::Ready(Ok(()))`.
    ///
    /// If flushing cannot immediately complete, this method returns
    /// `Poll::Pending` and arranges for the current task (via
    /// `cx.waker()`) to receive a notification when the object can make
    /// progress towards flushing.
    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>;

    /// Initiates or attempts to shut down this writer, returning success when
    /// the I/O connection has completely shut down.
    ///
    /// This method is intended to be used for asynchronous shutdown of I/O
    /// connections. For example this is suitable for implementing shutdown of a
    /// TLS connection or calling `TcpStream::shutdown` on a proxied connection.
    /// Protocols sometimes need to flush out final pieces of data or otherwise
    /// perform a graceful shutdown handshake, reading/writing more data as
    /// appropriate. This method is the hook for such protocols to implement the
    /// graceful shutdown logic.
    ///
    /// This `shutdown` method is required by implementers of the
    /// `AsyncWrite` trait. Wrappers typically just want to proxy this call
    /// through to the wrapped type, and base types will typically implement
    /// shutdown logic here or just return `Ok(().into())`. Note that if you're
    /// wrapping an underlying `AsyncWrite` a call to `shutdown` implies that
    /// transitively the entire stream has been shut down. After your wrapper's
    /// shutdown logic has been executed you should shut down the underlying
    /// stream.
    ///
    /// Invocation of a `shutdown` implies an invocation of `flush`. Once this
    /// method returns `Ready` it implies that a flush successfully happened
    /// before the shutdown happened. That is, callers don't need to call
    /// `flush` before calling `shutdown`. They can rely that by calling
    /// `shutdown` any pending buffered data will be written out.
    ///
    /// # Return value
    ///
    /// This function returns a `Poll<io::Result<()>>` classified as such:
    ///
    /// * `Poll::Ready(Ok(()))` - indicates that the connection was
    ///   successfully shut down and is now safe to deallocate/drop/close
    ///   resources associated with it. This method means that the current task
    ///   will no longer receive any notifications due to this method and the
    ///   I/O object itself is likely no longer usable.
    ///
    /// * `Poll::Pending` - indicates that shutdown is initiated but could
    ///   not complete just yet. This may mean that more I/O needs to happen to
    ///   continue this shutdown operation. The current task is scheduled to
    ///   receive a notification when it's otherwise ready to continue the
    ///   shutdown operation. When woken up this method should be called again.
    ///
    /// * `Poll::Ready(Err(e))` - indicates a fatal error has happened with shutdown,
    ///   indicating that the shutdown operation did not complete successfully.
    ///   This typically means that the I/O object is no longer usable.
    ///
    /// # Errors
    ///
    /// This function can return normal I/O errors through `Err`, described
    /// above. Additionally this method may also render the underlying
    /// `Write::write` method no longer usable (e.g. will return errors in the
    /// future). It's recommended that once `shutdown` is called the
    /// `write` method is no longer called.
    ///
    /// # Panics
    ///
    /// This function will panic if not called within the context of a future's
    /// task.
    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>;

    /// Writes a `Buf` into this value, returning how many bytes were written.
    ///
    /// Note that this method will advance the `buf` provided automatically by
    /// the number of bytes written.
    fn poll_write_buf(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut B,
    ) -> Poll<Result<usize, io::Error>>
    where
        Self: Sized,
    {
        if !buf.has_remaining() {
            return Poll::Ready(Ok(0));
        }

        let n = ready!(self.poll_write(cx, buf.bytes()))?;
        buf.advance(n);
        Poll::Ready(Ok(n))
    }
}

macro_rules! deref_async_write {
    () => {
        fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8])
            -> Poll<io::Result<usize>>
        {
            Pin::new(&mut **self).poll_write(cx, buf)
        }

        fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
            Pin::new(&mut **self).poll_flush(cx)
        }

        fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
            Pin::new(&mut **self).poll_shutdown(cx)
        }
    }
}

impl<T: ?Sized + AsyncWrite + Unpin> AsyncWrite for Box<T> {
    deref_async_write!();
}

impl<T: ?Sized + AsyncWrite + Unpin> AsyncWrite for &mut T {
    deref_async_write!();
}

impl
 AsyncWrite for Pin

where
    P: DerefMut + Unpin,
    P::Target: AsyncWrite,
{
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        self.get_mut().as_mut().poll_write(cx, buf)
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.get_mut().as_mut().poll_flush(cx)
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.get_mut().as_mut().poll_shutdown(cx)
    }
}

impl AsyncWrite for Vec<u8> {
    fn poll_write(
        self: Pin<&mut Self>,
        _cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        self.get_mut().extend_from_slice(buf);
        Poll::Ready(Ok(buf.len()))
    }

    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }

    fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }
}

impl AsyncWrite for io::Cursor<&mut [u8]> {
    fn poll_write(
        mut self: Pin<&mut Self>,
        _: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        Poll::Ready(io::Write::write(&mut *self, buf))
    }

    fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(io::Write::flush(&mut *self))
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.poll_flush(cx)
    }
}

impl AsyncWrite for io::Cursor<&mut Vec<u8>> {
    fn poll_write(
        mut self: Pin<&mut Self>,
        _: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        Poll::Ready(io::Write::write(&mut *self, buf))
    }

    fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(io::Write::flush(&mut *self))
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.poll_flush(cx)
    }
}

impl AsyncWrite for io::Cursor<Vec<u8>> {
    fn poll_write(
        mut self: Pin<&mut Self>,
        _: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        Poll::Ready(io::Write::write(&mut *self, buf))
    }

    fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(io::Write::flush(&mut *self))
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.poll_flush(cx)
    }
}

impl AsyncWrite for io::Cursor<Box<[u8]>> {
    fn poll_write(
        mut self: Pin<&mut Self>,
        _: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        Poll::Ready(io::Write::write(&mut *self, buf))
    }

    fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(io::Write::flush(&mut *self))
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.poll_flush(cx)
    }
}
<commit_msg>io: fix typo on AsyncWrite doc (#2427)<commit_after>use bytes::Buf;
use std::io;
use std::ops::DerefMut;
use std::pin::Pin;
use std::task::{Context, Poll};

/// Writes bytes asynchronously.
///
/// The trait inherits from [`std::io::Write`] and indicates that an I/O object is
/// **nonblocking**. All non-blocking I/O objects must return an error when
/// bytes cannot be written instead of blocking the current thread.
///
/// Specifically, this means that the [`poll_write`] function will return one of
/// the following:
///
/// * `Poll::Ready(Ok(n))` means that `n` bytes of data was immediately
///   written.
///
/// * `Poll::Pending` means that no data was written from the buffer
///   provided. The I/O object is not currently writable but may become writable
///   in the future. Most importantly, **the current future's task is scheduled
///   to get unparked when the object is writable**. This means that like
///   `Future::poll` you'll receive a notification when the I/O object is
///   writable again.
///
/// * `Poll::Ready(Err(e))` for other errors are standard I/O errors coming from the
///   underlying object.
///
/// This trait importantly means that the [`write`][stdwrite] method only works in
/// the context of a future's task. The object may panic if used outside of a task.
///
/// Note that this trait also represents that the  [`Write::flush`][stdflush] method
/// works very similarly to the `write` method, notably that `Ok(())` means that the
/// writer has successfully been flushed, a "would block" error means that the
/// current task is ready to receive a notification when flushing can make more
/// progress, and otherwise normal errors can happen as well.
///
/// Utilities for working with `AsyncWrite` values are provided by
/// [`AsyncWriteExt`].
///
/// [`std::io::Write`]: std::io::Write
/// [`poll_write`]: AsyncWrite::poll_write()
/// [stdwrite]: std::io::Write::write()
/// [stdflush]: std::io::Write::flush()
/// [`AsyncWriteExt`]: crate::io::AsyncWriteExt
pub trait AsyncWrite {
    /// Attempt to write bytes from `buf` into the object.
    ///
    /// On success, returns `Poll::Ready(Ok(num_bytes_written))`.
    ///
    /// If the object is not ready for writing, the method returns
    /// `Poll::Pending` and arranges for the current task (via
    /// `cx.waker()`) to receive a notification when the object becomes
    /// writable or is closed.
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<Result<usize, io::Error>>;

    /// Attempts to flush the object, ensuring that any buffered data reach
    /// their destination.
    ///
    /// On success, returns `Poll::Ready(Ok(()))`.
    ///
    /// If flushing cannot immediately complete, this method returns
    /// `Poll::Pending` and arranges for the current task (via
    /// `cx.waker()`) to receive a notification when the object can make
    /// progress towards flushing.
    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>;

    /// Initiates or attempts to shut down this writer, returning success when
    /// the I/O connection has completely shut down.
    ///
    /// This method is intended to be used for asynchronous shutdown of I/O
    /// connections. For example this is suitable for implementing shutdown of a
    /// TLS connection or calling `TcpStream::shutdown` on a proxied connection.
    /// Protocols sometimes need to flush out final pieces of data or otherwise
    /// perform a graceful shutdown handshake, reading/writing more data as
    /// appropriate. This method is the hook for such protocols to implement the
    /// graceful shutdown logic.
    ///
    /// This `shutdown` method is required by implementers of the
    /// `AsyncWrite` trait. Wrappers typically just want to proxy this call
    /// through to the wrapped type, and base types will typically implement
    /// shutdown logic here or just return `Ok(().into())`. Note that if you're
    /// wrapping an underlying `AsyncWrite` a call to `shutdown` implies that
    /// transitively the entire stream has been shut down. After your wrapper's
    /// shutdown logic has been executed you should shut down the underlying
    /// stream.
    ///
    /// Invocation of a `shutdown` implies an invocation of `flush`. Once this
    /// method returns `Ready` it implies that a flush successfully happened
    /// before the shutdown happened. That is, callers don't need to call
    /// `flush` before calling `shutdown`. They can rely that by calling
    /// `shutdown` any pending buffered data will be written out.
    ///
    /// # Return value
    ///
    /// This function returns a `Poll<io::Result<()>>` classified as such:
    ///
    /// * `Poll::Ready(Ok(()))` - indicates that the connection was
    ///   successfully shut down and is now safe to deallocate/drop/close
    ///   resources associated with it. This method means that the current task
    ///   will no longer receive any notifications due to this method and the
    ///   I/O object itself is likely no longer usable.
    ///
    /// * `Poll::Pending` - indicates that shutdown is initiated but could
    ///   not complete just yet. This may mean that more I/O needs to happen to
    ///   continue this shutdown operation. The current task is scheduled to
    ///   receive a notification when it's otherwise ready to continue the
    ///   shutdown operation. When woken up this method should be called again.
    ///
    /// * `Poll::Ready(Err(e))` - indicates a fatal error has happened with shutdown,
    ///   indicating that the shutdown operation did not complete successfully.
    ///   This typically means that the I/O object is no longer usable.
    ///
    /// # Errors
    ///
    /// This function can return normal I/O errors through `Err`, described
    /// above. Additionally this method may also render the underlying
    /// `Write::write` method no longer usable (e.g. will return errors in the
    /// future). It's recommended that once `shutdown` is called the
    /// `write` method is no longer called.
    ///
    /// # Panics
    ///
    /// This function will panic if not called within the context of a future's
    /// task.
    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>;

    /// Writes a `Buf` into this value, returning how many bytes were written.
    ///
    /// Note that this method will advance the `buf` provided automatically by
    /// the number of bytes written.
    fn poll_write_buf(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut B,
    ) -> Poll<Result<usize, io::Error>>
    where
        Self: Sized,
    {
        if !buf.has_remaining() {
            return Poll::Ready(Ok(0));
        }

        let n = ready!(self.poll_write(cx, buf.bytes()))?;
        buf.advance(n);
        Poll::Ready(Ok(n))
    }
}

macro_rules! deref_async_write {
    () => {
        fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8])
            -> Poll<io::Result<usize>>
        {
            Pin::new(&mut **self).poll_write(cx, buf)
        }

        fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
            Pin::new(&mut **self).poll_flush(cx)
        }

        fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
            Pin::new(&mut **self).poll_shutdown(cx)
        }
    }
}

impl<T: ?Sized + AsyncWrite + Unpin> AsyncWrite for Box<T> {
    deref_async_write!();
}

impl<T: ?Sized + AsyncWrite + Unpin> AsyncWrite for &mut T {
    deref_async_write!();
}

impl
 AsyncWrite for Pin

where
    P: DerefMut + Unpin,
    P::Target: AsyncWrite,
{
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        self.get_mut().as_mut().poll_write(cx, buf)
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.get_mut().as_mut().poll_flush(cx)
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.get_mut().as_mut().poll_shutdown(cx)
    }
}

impl AsyncWrite for Vec<u8> {
    fn poll_write(
        self: Pin<&mut Self>,
        _cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        self.get_mut().extend_from_slice(buf);
        Poll::Ready(Ok(buf.len()))
    }

    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }

    fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }
}

impl AsyncWrite for io::Cursor<&mut [u8]> {
    fn poll_write(
        mut self: Pin<&mut Self>,
        _: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        Poll::Ready(io::Write::write(&mut *self, buf))
    }

    fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(io::Write::flush(&mut *self))
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.poll_flush(cx)
    }
}

impl AsyncWrite for io::Cursor<&mut Vec<u8>> {
    fn poll_write(
        mut self: Pin<&mut Self>,
        _: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        Poll::Ready(io::Write::write(&mut *self, buf))
    }

    fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(io::Write::flush(&mut *self))
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.poll_flush(cx)
    }
}

impl AsyncWrite for io::Cursor<Vec<u8>> {
    fn poll_write(
        mut self: Pin<&mut Self>,
        _: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        Poll::Ready(io::Write::write(&mut *self, buf))
    }

    fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(io::Write::flush(&mut *self))
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.poll_flush(cx)
    }
}

impl AsyncWrite for io::Cursor<Box<[u8]>> {
    fn poll_write(
        mut self: Pin<&mut Self>,
        _: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        Poll::Ready(io::Write::write(&mut *self, buf))
    }

    fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(io::Write::flush(&mut *self))
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.poll_flush(cx)
    }
}
<|endoftext|>