<commit_before>//! Array type node attribute.

use std::fmt;
use std::marker::PhantomData;
use std::io;
use std::io::Read;
use byteorder::{ReadBytesExt, LittleEndian};
#[cfg(feature = "flate2")]
use flate2::read::ZlibDecoder;
#[cfg(feature = "libflate")]
use libflate::zlib;

use parser::binary::{BinaryParser, CountReader};
use parser::binary::error::{Result, Error, Warning};

/// Read array type attribute from the given parser.
pub fn read_array_attribute<R: Read>(
    parser: &mut BinaryParser<R>,
    type_code: u8
) -> Result<(ArrayAttribute<R>, u64)> {
    let header = try!(ArrayAttributeHeader::read_from_parser(parser));
    let current_pos = parser.source.count();
    let BinaryParser { ref mut source, ref mut warnings, .. } = *parser;
    let reader = try!(ArrayDecoder::new(source, &header));

    let value = match type_code {
        b'b' => ArrayAttribute::Bool(ArrayAttributeReader::new(&header, reader, warnings)),
        b'i' => ArrayAttribute::I32(ArrayAttributeReader::new(&header, reader, warnings)),
        b'l' => ArrayAttribute::I64(ArrayAttributeReader::new(&header, reader, warnings)),
        b'f' => ArrayAttribute::F32(ArrayAttributeReader::new(&header, reader, warnings)),
        b'd' => ArrayAttribute::F64(ArrayAttributeReader::new(&header, reader, warnings)),
        _ => unreachable!(),
    };
    Ok((value, current_pos + header.bytelen_elements as u64))
}

/// Header of an array attribute.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct ArrayAttributeHeader {
    /// Number of elements.
    num_elements: u32,
    /// Array encoding, i.e. compression method.
    encoding: u32,
    /// Length of the array (excluding this header) in bytes.
    bytelen_elements: u32,
}

impl ArrayAttributeHeader {
    fn read_from_parser<R: Read>(parser: &mut BinaryParser<R>) -> io::Result<Self> {
        let num_elements = try!(parser.source.read_u32());
        let encoding = try!(parser.source.read_u32());
        let bytelen_elements = try!(parser.source.read_u32());

        Ok(ArrayAttributeHeader {
            num_elements: num_elements,
            encoding: encoding,
            bytelen_elements: bytelen_elements,
        })
    }
}

/// Array type attribute.
#[derive(Debug)]
pub enum ArrayAttribute<'a, R: 'a> {
    /// Array of `bool`.
    Bool(ArrayAttributeReader<'a, R, bool>),
    /// Array of `i32`.
    I32(ArrayAttributeReader<'a, R, i32>),
    /// Array of `i64`.
    I64(ArrayAttributeReader<'a, R, i64>),
    /// Array of `f32`.
    F32(ArrayAttributeReader<'a, R, f32>),
    /// Array of `f64`.
    F64(ArrayAttributeReader<'a, R, f64>),
}

/// Reader of array attribute elements.
#[derive(Debug)]
pub struct ArrayAttributeReader<'a, R: 'a, T> {
    num_elements: u64,
    rest_elements: u64,
    reader: ArrayDecoder<'a, CountReader<R>>,
    warnings: &'a mut Vec<Warning>,
    _value_type: PhantomData<T>,
}

impl<'a, R: 'a + Read, T> ArrayAttributeReader<'a, R, T> {
    fn new<'b>(
        header: &'b ArrayAttributeHeader,
        reader: ArrayDecoder<'a, CountReader<R>>,
        warnings: &'a mut Vec<Warning>
    ) -> Self {
        ArrayAttributeReader {
            num_elements: header.num_elements as u64,
            rest_elements: header.num_elements as u64,
            reader: reader,
            warnings: warnings,
            _value_type: PhantomData,
        }
    }

    /// Returns number of elements.
    pub fn num_elements(&self) -> u64 {
        self.num_elements
    }

    /// Returns number of rest elements.
    pub fn rest_elements(&self) -> u64 {
        self.num_elements
    }
}

impl<'a, R: 'a + Read> Iterator for ArrayAttributeReader<'a, R, bool> {
    type Item = io::Result<bool>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.rest_elements == 0 {
            return None;
        }
        self.rest_elements -= 1;
        let raw = match self.reader.read_u8() {
            Ok(val) => val,
            Err(err) => return Some(Err(err)),
        };
        let val = (raw & 1) == 1;
        Some(Ok(val))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.rest_elements as usize, Some(self.rest_elements as usize))
    }
}

macro_rules! impl_attr_array_iter {
    ($ty:ty, $f:ident) => {
        impl<'a, R: 'a + Read> Iterator for ArrayAttributeReader<'a, R, $ty> {
            type Item = io::Result<$ty>;

            fn next(&mut self) -> Option<Self::Item> {
                if self.rest_elements == 0 {
                    return None;
                }
                self.rest_elements -= 1;
                Some(self.reader.$f::<LittleEndian>())
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                (self.rest_elements as usize, Some(self.rest_elements as usize))
            }
        }
    }
}

impl_attr_array_iter!(i32, read_i32);
impl_attr_array_iter!(i64, read_i64);
impl_attr_array_iter!(f32, read_f32);
impl_attr_array_iter!(f64, read_f64);

/// Attribute array decoder.
enum ArrayDecoder<'a, R: 'a> {
    /// Non-compressed stream.
    ///
    /// `encoding` == 0.
    Raw(io::Take<&'a mut R>),
    /// Zlib-compressed stream.
    ///
    /// `encoding` == 1.
    #[cfg(feature = "flate2")]
    Zlib(ZlibDecoder<io::Take<&'a mut R>>),
    /// Zlib-compressed stream.
    ///
    /// `encoding` == 1.
    #[cfg(feature = "libflate")]
    Zlib(zlib::Decoder<io::Take<&'a mut R>>),
}

impl<'a, R: 'a + Read> ArrayDecoder<'a, R> {
    fn new(reader: &'a mut R, header: &ArrayAttributeHeader) -> Result<Self> {
        match header.encoding {
            0 => Ok(ArrayDecoder::Raw(reader.take(header.bytelen_elements as u64))),
            #[cfg(feature = "flate2")]
            1 => Ok(ArrayDecoder::Zlib(ZlibDecoder::new(reader.take(header.bytelen_elements as u64)))),
            #[cfg(feature = "libflate")]
            1 => Ok(ArrayDecoder::Zlib(try!(zlib::Decoder::new(reader.take(header.bytelen_elements as u64))))),
            _ => Err(Error::UnknownArrayAttributeEncoding(header.encoding)),
        }
    }
}

impl<'a, R: 'a + Read> Read for ArrayDecoder<'a, R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            ArrayDecoder::Raw(ref mut reader) => reader.read(buf),
            #[cfg(feature = "flate2")]
            ArrayDecoder::Zlib(ref mut reader) => reader.read(buf),
            #[cfg(feature = "libflate")]
            ArrayDecoder::Zlib(ref mut reader) => reader.read(buf),
        }
    }
}

impl<'a, R: 'a> fmt::Debug for ArrayDecoder<'a, R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "ArrayDecoder::{}",
               match *self {
                   ArrayDecoder::Raw(_) => "Raw",
                   #[cfg(feature = "flate2")]
                   ArrayDecoder::Zlib(_) => "Zlib",
                   #[cfg(feature = "libflate")]
                   ArrayDecoder::Zlib(_) => "Zlib",
               })
    }
}
<commit_msg>Implement `Iterator::count` for `ArrayAttributeReader`<commit_after>//! Array type node attribute.

use std::fmt;
use std::marker::PhantomData;
use std::io;
use std::io::Read;
use byteorder::{ReadBytesExt, LittleEndian};
#[cfg(feature = "flate2")]
use flate2::read::ZlibDecoder;
#[cfg(feature = "libflate")]
use libflate::zlib;

use parser::binary::{BinaryParser, CountReader};
use parser::binary::error::{Result, Error, Warning};

/// Read array type attribute from the given parser.
pub fn read_array_attribute<R: Read>(
    parser: &mut BinaryParser<R>,
    type_code: u8
) -> Result<(ArrayAttribute<R>, u64)> {
    let header = try!(ArrayAttributeHeader::read_from_parser(parser));
    let current_pos = parser.source.count();
    let BinaryParser { ref mut source, ref mut warnings, .. } = *parser;
    let reader = try!(ArrayDecoder::new(source, &header));

    let value = match type_code {
        b'b' => ArrayAttribute::Bool(ArrayAttributeReader::new(&header, reader, warnings)),
        b'i' => ArrayAttribute::I32(ArrayAttributeReader::new(&header, reader, warnings)),
        b'l' => ArrayAttribute::I64(ArrayAttributeReader::new(&header, reader, warnings)),
        b'f' => ArrayAttribute::F32(ArrayAttributeReader::new(&header, reader, warnings)),
        b'd' => ArrayAttribute::F64(ArrayAttributeReader::new(&header, reader, warnings)),
        _ => unreachable!(),
    };
    Ok((value, current_pos + header.bytelen_elements as u64))
}

/// Header of an array attribute.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct ArrayAttributeHeader {
    /// Number of elements.
    num_elements: u32,
    /// Array encoding, i.e. compression method.
    encoding: u32,
    /// Length of the array (excluding this header) in bytes.
    bytelen_elements: u32,
}

impl ArrayAttributeHeader {
    fn read_from_parser<R: Read>(parser: &mut BinaryParser<R>) -> io::Result<Self> {
        let num_elements = try!(parser.source.read_u32());
        let encoding = try!(parser.source.read_u32());
        let bytelen_elements = try!(parser.source.read_u32());

        Ok(ArrayAttributeHeader {
            num_elements: num_elements,
            encoding: encoding,
            bytelen_elements: bytelen_elements,
        })
    }
}

/// Array type attribute.
#[derive(Debug)]
pub enum ArrayAttribute<'a, R: 'a> {
    /// Array of `bool`.
    Bool(ArrayAttributeReader<'a, R, bool>),
    /// Array of `i32`.
    I32(ArrayAttributeReader<'a, R, i32>),
    /// Array of `i64`.
    I64(ArrayAttributeReader<'a, R, i64>),
    /// Array of `f32`.
    F32(ArrayAttributeReader<'a, R, f32>),
    /// Array of `f64`.
    F64(ArrayAttributeReader<'a, R, f64>),
}

/// Reader of array attribute elements.
#[derive(Debug)]
pub struct ArrayAttributeReader<'a, R: 'a, T> {
    num_elements: u64,
    rest_elements: u64,
    reader: ArrayDecoder<'a, CountReader<R>>,
    warnings: &'a mut Vec<Warning>,
    _value_type: PhantomData<T>,
}

impl<'a, R: 'a + Read, T> ArrayAttributeReader<'a, R, T> {
    fn new<'b>(
        header: &'b ArrayAttributeHeader,
        reader: ArrayDecoder<'a, CountReader<R>>,
        warnings: &'a mut Vec<Warning>
    ) -> Self {
        ArrayAttributeReader {
            num_elements: header.num_elements as u64,
            rest_elements: header.num_elements as u64,
            reader: reader,
            warnings: warnings,
            _value_type: PhantomData,
        }
    }

    /// Returns number of elements.
    pub fn num_elements(&self) -> u64 {
        self.num_elements
    }

    /// Returns number of rest elements.
    pub fn rest_elements(&self) -> u64 {
        self.num_elements
    }
}

impl<'a, R: 'a + Read> Iterator for ArrayAttributeReader<'a, R, bool> {
    type Item = io::Result<bool>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.rest_elements == 0 {
            return None;
        }
        self.rest_elements -= 1;
        let raw = match self.reader.read_u8() {
            Ok(val) => val,
            Err(err) => return Some(Err(err)),
        };
        let val = (raw & 1) == 1;
        Some(Ok(val))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.rest_elements as usize, Some(self.rest_elements as usize))
    }

    fn count(self) -> usize {
        self.rest_elements as usize
    }
}

macro_rules! impl_attr_array_iter {
    ($ty:ty, $f:ident) => {
        impl<'a, R: 'a + Read> Iterator for ArrayAttributeReader<'a, R, $ty> {
            type Item = io::Result<$ty>;

            fn next(&mut self) -> Option<Self::Item> {
                if self.rest_elements == 0 {
                    return None;
                }
                self.rest_elements -= 1;
                Some(self.reader.$f::<LittleEndian>())
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                (self.rest_elements as usize, Some(self.rest_elements as usize))
            }

            fn count(self) -> usize {
                self.rest_elements as usize
            }
        }
    }
}

impl_attr_array_iter!(i32, read_i32);
impl_attr_array_iter!(i64, read_i64);
impl_attr_array_iter!(f32, read_f32);
impl_attr_array_iter!(f64, read_f64);

/// Attribute array decoder.
enum ArrayDecoder<'a, R: 'a> {
    /// Non-compressed stream.
    ///
    /// `encoding` == 0.
    Raw(io::Take<&'a mut R>),
    /// Zlib-compressed stream.
    ///
    /// `encoding` == 1.
    #[cfg(feature = "flate2")]
    Zlib(ZlibDecoder<io::Take<&'a mut R>>),
    /// Zlib-compressed stream.
    ///
    /// `encoding` == 1.
    #[cfg(feature = "libflate")]
    Zlib(zlib::Decoder<io::Take<&'a mut R>>),
}

impl<'a, R: 'a + Read> ArrayDecoder<'a, R> {
    fn new(reader: &'a mut R, header: &ArrayAttributeHeader) -> Result<Self> {
        match header.encoding {
            0 => Ok(ArrayDecoder::Raw(reader.take(header.bytelen_elements as u64))),
            #[cfg(feature = "flate2")]
            1 => Ok(ArrayDecoder::Zlib(ZlibDecoder::new(reader.take(header.bytelen_elements as u64)))),
            #[cfg(feature = "libflate")]
            1 => Ok(ArrayDecoder::Zlib(try!(zlib::Decoder::new(reader.take(header.bytelen_elements as u64))))),
            _ => Err(Error::UnknownArrayAttributeEncoding(header.encoding)),
        }
    }
}

impl<'a, R: 'a + Read> Read for ArrayDecoder<'a, R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            ArrayDecoder::Raw(ref mut reader) => reader.read(buf),
            #[cfg(feature = "flate2")]
            ArrayDecoder::Zlib(ref mut reader) => reader.read(buf),
            #[cfg(feature = "libflate")]
            ArrayDecoder::Zlib(ref mut reader) => reader.read(buf),
        }
    }
}

impl<'a, R: 'a> fmt::Debug for ArrayDecoder<'a, R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "ArrayDecoder::{}",
               match *self {
                   ArrayDecoder::Raw(_) => "Raw",
                   #[cfg(feature = "flate2")]
                   ArrayDecoder::Zlib(_) => "Zlib",
                   #[cfg(feature = "libflate")]
                   ArrayDecoder::Zlib(_) => "Zlib",
               })
    }
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

//! Implementation of a Micro Transport Protocol library,
//! as well as a small client and server.
//!
//! http://www.bittorrent.org/beps/bep_0029.html

extern crate utp;
use std::io::net::ip::{Ipv4Addr, SocketAddr};

fn usage() {
    println!("Usage: utp [-s|-c] <address> <port>");
}

fn main() {
    use utp::UtpStream;
    use std::from_str::FromStr;
    use std::io::{stdin, EndOfFile};

    // Defaults
    static BUF_SIZE: uint = 4096;
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

	if args.len() != 2 && args.len() != 4 {
		usage();
		return;
	}

    if args.len() == 4 {
        addr = SocketAddr {
            ip:   FromStr::from_str(args[2].as_slice()).unwrap(),
            port: FromStr::from_str(args[3].as_slice()).unwrap(),
        };
    }

    match args[1].as_slice() {
        "-s" => {
            let mut buf = [0, ..BUF_SIZE];
            let mut stream = UtpStream::bind(addr);

            println!("Serving on {}", addr);

            loop {
                match stream.read(buf) {
                    Ok(_read) => {}
                    Err(e) => fail!("{}", e),
                }
            }
        }
        "-c" => {
            let mut stream = UtpStream::connect(addr);
            let mut buf = [0, ..BUF_SIZE];
            let mut reader = stdin();

            loop {
                match reader.read(buf) {
                    Ok(nread) => stream.write(buf.slice(0, nread)),
                    Err(ref e) if e.kind == EndOfFile => break,
                    Err(e) => fail!("{}", e),
                };
            }

            match stream.close() {
                Ok(_) => {},
                Err(e) => fail!("{}", e),
            }
            drop(stream);
        }
        _ => usage(),
    }
}
<commit_msg>Simplify example code.<commit_after>#![feature(macro_rules)]

//! Implementation of a Micro Transport Protocol library,
//! as well as a small client and server.
//!
//! http://www.bittorrent.org/beps/bep_0029.html

extern crate utp;
use std::io::net::ip::{Ipv4Addr, SocketAddr};

fn usage() {
    println!("Usage: utp [-s|-c] <address> <port>");
}

fn main() {
    use utp::UtpStream;
    use std::from_str::FromStr;
    use std::io::{stdin, stdout};

    // Defaults
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

	if args.len() != 2 && args.len() != 4 {
		usage();
		return;
	}

    if args.len() == 4 {
        addr = SocketAddr {
            ip:   FromStr::from_str(args[2].as_slice()).unwrap(),
            port: FromStr::from_str(args[3].as_slice()).unwrap(),
        };
    }

    match args[1].as_slice() {
        "-s" => {
            let mut stream = UtpStream::bind(addr);
            let mut writer = stdout();
            println!("Serving on {}", addr);

            let payload = match stream.read_to_end() {
                Ok(v) => v,
                Err(e) => fail!("{}", e),
            };

            match writer.write(payload.as_slice()) {
                Ok(_) => {},
                Err(e) => fail!("{}", e),
            }
        }
        "-c" => {
            let mut stream = UtpStream::connect(addr);
            let mut reader = stdin();

            let payload = match reader.read_to_end() {
                Ok(v) => v,
                Err(e) => fail!("{}", e),
            };

            match stream.write(payload.as_slice()) {
                Ok(_) => {},
                Err(e) => fail!("{}", e),
            };

            match stream.close() {
                Ok(_) => {},
                Err(e) => fail!("{}", e),
            }
            drop(stream);
        }
        _ => usage(),
    }
}
<|endoftext|>


<commit_before>use unicode_segmentation::UnicodeSegmentation;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;

use textwrap::word_splitters::split_words;
use textwrap::wrap_algorithms::{wrap_first_fit, wrap_optimal_fit, Penalties};
use textwrap::{WordSeparator, WordSplitter};

#[wasm_bindgen]
extern "C" {
    // https://github.com/rustwasm/wasm-bindgen/issues/2069#issuecomment-774038243
    type ExtendedTextMetrics;

    #[wasm_bindgen(method, getter, js_name = actualBoundingBoxLeft)]
    fn actual_bounding_box_left(this: &ExtendedTextMetrics) -> f64;

    #[wasm_bindgen(method, getter, js_name = actualBoundingBoxRight)]
    fn actual_bounding_box_right(this: &ExtendedTextMetrics) -> f64;

    #[wasm_bindgen(method, getter, js_name = actualBoundingBoxAscent)]
    fn actual_bounding_box_ascent(this: &ExtendedTextMetrics) -> f64;

    #[wasm_bindgen(method, getter, js_name = actualBoundingBoxDescent)]
    fn actual_bounding_box_descent(this: &ExtendedTextMetrics) -> f64;

    // TODO: Enable when Firefox and Edge support these methods, see
    // https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics
    //
    // #[wasm_bindgen(method, getter, js_name = fontBoundingBoxAscent)]
    // fn font_bounding_box_ascent(this: &ExtendedTextMetrics) -> f64;
    //
    // #[wasm_bindgen(method, getter, js_name = fontBoundingBoxDescent)]
    // fn font_bounding_box_descent(this: &ExtendedTextMetrics) -> f64;

    #[wasm_bindgen(method, getter)]
    fn width(this: &ExtendedTextMetrics) -> f64;
}

fn canvas_width(ctx: &web_sys::CanvasRenderingContext2d, text: &str) -> f64 {
    ctx.measure_text(text).unwrap().width()
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct CanvasWord<'a> {
    word: &'a str,
    width: f64,
    whitespace: &'a str,
    whitespace_width: f64,
    penalty: &'a str,
    penalty_width: f64,
}

impl<'a> CanvasWord<'a> {
    fn from(ctx: &'_ web_sys::CanvasRenderingContext2d, word: textwrap::core::Word<'a>) -> Self {
        CanvasWord {
            word: word.word,
            width: canvas_width(ctx, word.word),
            whitespace: word.whitespace,
            whitespace_width: canvas_width(ctx, word.whitespace),
            penalty: word.penalty,
            penalty_width: canvas_width(ctx, word.penalty),
        }
    }

    fn break_apart(
        self,
        ctx: &'_ web_sys::CanvasRenderingContext2d,
        max_width: f64,
    ) -> Vec<CanvasWord<'a>> {
        if self.width <= max_width {
            return vec![self];
        }

        let mut start = 0;
        let mut words = Vec::new();
        for (idx, grapheme) in self.word.grapheme_indices(true) {
            let with_grapheme = &self.word[start..idx + grapheme.len()];
            let without_grapheme = &self.word[start..idx];
            if idx > 0 && canvas_width(&ctx, with_grapheme) > max_width {
                // The part without the grapheme fits on the line. We
                // give it a width of max_width instead of its natural
                // width to ensure that it takes up the full line.
                //
                // Otherwise, we can end up with a situation where a
                // text fits in _fewer_ lines when the line width is
                // _smaller_. This happens with proportional fonts,
                // such as the sans-serif or serif fonts. An example
                // text which illustrates the problem is:
                //
                //   i XYZ
                //
                // Line width: 42px. Normal break, XYZ doesn't fit on
                // first line:
                //
                //   i
                //   XYZ
                //
                // Line width: 41px. XYZ takes up 41.1px, so it is
                // broken apart. The first part now fits on the first
                // line:
                //
                //   i XY
                //   Z
                //
                // Line width: 39px. There is no longer room for XY on
                // the first line:
                //
                //   i
                //   XY
                //   Z
                //
                // Line width: 28px. XY takes up 28.9px, so it is
                // broken apart. YZ takes up 26.7px, so everything
                // suddenly fits on two lines again:
                //
                //   i X
                //   YZ
                //
                // We can be a more "natural" or "monotone" behavior
                // by making the parts take up at least the full line
                // width.
                let natural_width = canvas_width(ctx, &without_grapheme);
                words.push(CanvasWord {
                    word: &without_grapheme,
                    width: max_width.max(natural_width),
                    whitespace: "",
                    whitespace_width: 0.0,
                    penalty: "",
                    penalty_width: 0.0,
                });
                start = idx;
            }
        }

        words.push(CanvasWord {
            word: &self.word[start..],
            width: canvas_width(ctx, &self.word[start..]),
            whitespace: self.whitespace,
            whitespace_width: self.whitespace_width,
            penalty: self.penalty,
            penalty_width: self.penalty_width,
        });

        words
    }
}

impl textwrap::core::Fragment for CanvasWord<'_> {
    #[inline]
    fn width(&self) -> f64 {
        self.width
    }

    #[inline]
    fn whitespace_width(&self) -> f64 {
        self.whitespace_width
    }

    #[inline]
    fn penalty_width(&self) -> f64 {
        self.penalty_width
    }
}

fn draw_path(
    ctx: &web_sys::CanvasRenderingContext2d,
    style: &str,
    (mut x, mut y): (f64, f64),
    steps: &[(f64, f64)],
) {
    ctx.save();
    ctx.set_stroke_style(&style.into());
    ctx.begin_path();
    ctx.move_to(x, y);
    for (delta_x, delta_y) in steps {
        x += delta_x;
        y += delta_y;
        ctx.line_to(x, y);
    }
    ctx.stroke();
    ctx.restore();
}

// We offset all text by the width of the round slider. This ensures
// no clipping due to anti-aliasing.
const X_OFFSET: f64 = 8.0;

fn draw_word(
    ctx: &web_sys::CanvasRenderingContext2d,
    x: f64,
    y: f64,
    word: &CanvasWord,
    last_word: bool,
) -> Result<(), JsValue> {
    ctx.fill_text(word.word, x, y)?;

    draw_path(
        ctx,
        "orange",
        (x, y - 10.0),
        &[(0.0, 10.0), (word.width, 0.0)],
    );

    ctx.save();
    ctx.set_font("10px sans-serif");
    ctx.set_text_align("center");
    ctx.set_text_baseline("top");
    ctx.fill_text(
        &format!("{:.1}px", word.width),
        x + word.width / 2.0,
        y + 3.0,
    )?;
    ctx.restore();

    let x = x + word.width;
    if last_word {
        ctx.fill_text(word.penalty, x, y)?;
        draw_path(ctx, "red", (x, y), &[(word.penalty_width, 0.0)]);
    } else {
        ctx.fill_text(word.whitespace, x, y)?;
        draw_path(ctx, "lightblue", (x, y), &[(word.whitespace_width, 0.0)]);
    }

    Ok(())
}

#[wasm_bindgen]
#[derive(Copy, Clone, Debug)]
pub enum WasmWordSeparator {
    AsciiSpace = "AsciiSpace",
    UnicodeBreakProperties = "UnicodeBreakProperties",
}

#[wasm_bindgen]
#[derive(Copy, Clone, Debug)]
pub enum WasmWordSplitter {
    NoHyphenation = "NoHyphenation",
    HyphenSplitter = "HyphenSplitter",
}

#[wasm_bindgen]
#[derive(Copy, Clone, Debug)]
pub enum WasmWrapAlgorithm {
    FirstFit = "FirstFit",
    OptimalFit = "OptimalFit",
}

#[wasm_bindgen]
#[derive(Copy, Clone, Debug, Default)]
pub struct WasmPenalties {
    pub nline_penalty: usize,
    pub overflow_penalty: usize,
    pub short_last_line_fraction: usize,
    pub short_last_line_penalty: usize,
    pub hyphen_penalty: usize,
}

#[wasm_bindgen]
impl WasmPenalties {
    #[wasm_bindgen(constructor)]
    pub fn new(
        nline_penalty: usize,
        overflow_penalty: usize,
        short_last_line_fraction: usize,
        short_last_line_penalty: usize,
        hyphen_penalty: usize,
    ) -> WasmPenalties {
        WasmPenalties {
            nline_penalty,
            overflow_penalty,
            short_last_line_fraction,
            short_last_line_penalty,
            hyphen_penalty,
        }
    }
}

impl Into<Penalties> for WasmPenalties {
    fn into(self) -> Penalties {
        Penalties {
            nline_penalty: self.nline_penalty,
            overflow_penalty: self.overflow_penalty,
            short_last_line_fraction: self.short_last_line_fraction,
            short_last_line_penalty: self.short_last_line_penalty,
            hyphen_penalty: self.hyphen_penalty,
        }
    }
}

#[wasm_bindgen]
#[derive(Copy, Clone, Debug)]
pub struct WasmOptions {
    pub width: f64,
    pub break_words: bool,
    pub word_separator: WasmWordSeparator,
    pub word_splitter: WasmWordSplitter,
    pub wrap_algorithm: WasmWrapAlgorithm,
    pub penalties: WasmPenalties,
}

#[wasm_bindgen]
impl WasmOptions {
    #[wasm_bindgen(constructor)]
    pub fn new(
        width: f64,
        break_words: bool,
        word_separator: WasmWordSeparator,
        word_splitter: WasmWordSplitter,
        wrap_algorithm: WasmWrapAlgorithm,
        penalties: WasmPenalties,
    ) -> WasmOptions {
        WasmOptions {
            width,
            break_words,
            word_separator,
            word_splitter,
            wrap_algorithm,
            penalties,
        }
    }
}

#[wasm_bindgen]
pub fn draw_wrapped_text(
    ctx: &web_sys::CanvasRenderingContext2d,
    options: &WasmOptions,
    text: &str,
) -> Result<(), JsValue> {
    console_error_panic_hook::set_once();

    let metrics: web_sys::TextMetrics = ctx.measure_text("│").unwrap();
    let metrics: ExtendedTextMetrics = metrics.unchecked_into();
    // TODO: use metrics.font_bounding_box_ascent() +
    // metrics.font_bounding_box_descent() and measure "" instead of a
    // tall character when supported by Firefox.
    let line_height = metrics.actual_bounding_box_ascent() + metrics.actual_bounding_box_descent();
    let baseline_distance = 1.5 * line_height;

    let word_separator = match options.word_separator {
        WasmWordSeparator::AsciiSpace => WordSeparator::AsciiSpace,
        WasmWordSeparator::UnicodeBreakProperties => WordSeparator::UnicodeBreakProperties,
        _ => Err("WasmOptions has an invalid word_separator field")?,
    };

    let word_splitter = match options.word_splitter {
        WasmWordSplitter::NoHyphenation => WordSplitter::NoHyphenation,
        WasmWordSplitter::HyphenSplitter => WordSplitter::HyphenSplitter,
        _ => Err("WasmOptions has an invalid word_splitter field")?,
    };

    let mut lineno = 0;
    for line in text.split('\n') {
        let words = word_separator.find_words(line);
        let split_words = split_words(words, &word_splitter);

        let canvas_words = split_words
            .flat_map(|word| {
                let canvas_word = CanvasWord::from(ctx, word);
                if options.break_words {
                    canvas_word.break_apart(ctx, options.width)
                } else {
                    vec![canvas_word]
                }
            })
            .collect::<Vec<_>>();

        let line_lengths = [options.width];
        let wrapped_words = match options.wrap_algorithm {
            WasmWrapAlgorithm::FirstFit => wrap_first_fit(&canvas_words, &line_lengths),
            WasmWrapAlgorithm::OptimalFit => {
                let penalties = options.penalties.into();
                wrap_optimal_fit(&canvas_words, &line_lengths, &penalties).unwrap()
            }
            _ => Err("WasmOptions has an invalid wrap_algorithm field")?,
        };

        for words_in_line in wrapped_words {
            lineno += 1;
            let mut x = X_OFFSET;
            let y = baseline_distance * lineno as f64;

            for (i, word) in words_in_line.iter().enumerate() {
                let last_word = i == words_in_line.len() - 1;
                draw_word(ctx, x, y, word, last_word)?;
                x += word.width;
                x += if last_word {
                    word.penalty_width
                } else {
                    word.whitespace_width
                };
            }

            ctx.save();
            ctx.set_font("10px sans-serif");
            ctx.fill_text(
                &format!("{:.1}px", x - X_OFFSET),
                1.5 * X_OFFSET + options.width as f64,
                y,
            )?;
            ctx.restore();
        }
    }

    draw_path(
        ctx,
        "blue",
        (
            X_OFFSET + options.width as f64,
            metrics.actual_bounding_box_ascent(),
        ),
        &[(0.0, baseline_distance * lineno as f64)],
    );

    Ok(())
}
<commit_msg>Apply Clippy fixes to Wasm example<commit_after>use unicode_segmentation::UnicodeSegmentation;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;

use textwrap::word_splitters::split_words;
use textwrap::wrap_algorithms::{wrap_first_fit, wrap_optimal_fit, Penalties};
use textwrap::{WordSeparator, WordSplitter};

#[wasm_bindgen]
extern "C" {
    // https://github.com/rustwasm/wasm-bindgen/issues/2069#issuecomment-774038243
    type ExtendedTextMetrics;

    #[wasm_bindgen(method, getter, js_name = actualBoundingBoxLeft)]
    fn actual_bounding_box_left(this: &ExtendedTextMetrics) -> f64;

    #[wasm_bindgen(method, getter, js_name = actualBoundingBoxRight)]
    fn actual_bounding_box_right(this: &ExtendedTextMetrics) -> f64;

    #[wasm_bindgen(method, getter, js_name = actualBoundingBoxAscent)]
    fn actual_bounding_box_ascent(this: &ExtendedTextMetrics) -> f64;

    #[wasm_bindgen(method, getter, js_name = actualBoundingBoxDescent)]
    fn actual_bounding_box_descent(this: &ExtendedTextMetrics) -> f64;

    // TODO: Enable when Firefox and Edge support these methods, see
    // https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics
    //
    // #[wasm_bindgen(method, getter, js_name = fontBoundingBoxAscent)]
    // fn font_bounding_box_ascent(this: &ExtendedTextMetrics) -> f64;
    //
    // #[wasm_bindgen(method, getter, js_name = fontBoundingBoxDescent)]
    // fn font_bounding_box_descent(this: &ExtendedTextMetrics) -> f64;

    #[wasm_bindgen(method, getter)]
    fn width(this: &ExtendedTextMetrics) -> f64;
}

fn canvas_width(ctx: &web_sys::CanvasRenderingContext2d, text: &str) -> f64 {
    ctx.measure_text(text).unwrap().width()
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct CanvasWord<'a> {
    word: &'a str,
    width: f64,
    whitespace: &'a str,
    whitespace_width: f64,
    penalty: &'a str,
    penalty_width: f64,
}

impl<'a> CanvasWord<'a> {
    fn from(ctx: &'_ web_sys::CanvasRenderingContext2d, word: textwrap::core::Word<'a>) -> Self {
        CanvasWord {
            word: word.word,
            width: canvas_width(ctx, word.word),
            whitespace: word.whitespace,
            whitespace_width: canvas_width(ctx, word.whitespace),
            penalty: word.penalty,
            penalty_width: canvas_width(ctx, word.penalty),
        }
    }

    fn break_apart(
        self,
        ctx: &'_ web_sys::CanvasRenderingContext2d,
        max_width: f64,
    ) -> Vec<CanvasWord<'a>> {
        if self.width <= max_width {
            return vec![self];
        }

        let mut start = 0;
        let mut words = Vec::new();
        for (idx, grapheme) in self.word.grapheme_indices(true) {
            let with_grapheme = &self.word[start..idx + grapheme.len()];
            let without_grapheme = &self.word[start..idx];
            if idx > 0 && canvas_width(ctx, with_grapheme) > max_width {
                // The part without the grapheme fits on the line. We
                // give it a width of max_width instead of its natural
                // width to ensure that it takes up the full line.
                //
                // Otherwise, we can end up with a situation where a
                // text fits in _fewer_ lines when the line width is
                // _smaller_. This happens with proportional fonts,
                // such as the sans-serif or serif fonts. An example
                // text which illustrates the problem is:
                //
                //   i XYZ
                //
                // Line width: 42px. Normal break, XYZ doesn't fit on
                // first line:
                //
                //   i
                //   XYZ
                //
                // Line width: 41px. XYZ takes up 41.1px, so it is
                // broken apart. The first part now fits on the first
                // line:
                //
                //   i XY
                //   Z
                //
                // Line width: 39px. There is no longer room for XY on
                // the first line:
                //
                //   i
                //   XY
                //   Z
                //
                // Line width: 28px. XY takes up 28.9px, so it is
                // broken apart. YZ takes up 26.7px, so everything
                // suddenly fits on two lines again:
                //
                //   i X
                //   YZ
                //
                // We can be a more "natural" or "monotone" behavior
                // by making the parts take up at least the full line
                // width.
                let natural_width = canvas_width(ctx, without_grapheme);
                words.push(CanvasWord {
                    word: without_grapheme,
                    width: max_width.max(natural_width),
                    whitespace: "",
                    whitespace_width: 0.0,
                    penalty: "",
                    penalty_width: 0.0,
                });
                start = idx;
            }
        }

        words.push(CanvasWord {
            word: &self.word[start..],
            width: canvas_width(ctx, &self.word[start..]),
            whitespace: self.whitespace,
            whitespace_width: self.whitespace_width,
            penalty: self.penalty,
            penalty_width: self.penalty_width,
        });

        words
    }
}

impl textwrap::core::Fragment for CanvasWord<'_> {
    #[inline]
    fn width(&self) -> f64 {
        self.width
    }

    #[inline]
    fn whitespace_width(&self) -> f64 {
        self.whitespace_width
    }

    #[inline]
    fn penalty_width(&self) -> f64 {
        self.penalty_width
    }
}

fn draw_path(
    ctx: &web_sys::CanvasRenderingContext2d,
    style: &str,
    (mut x, mut y): (f64, f64),
    steps: &[(f64, f64)],
) {
    ctx.save();
    ctx.set_stroke_style(&style.into());
    ctx.begin_path();
    ctx.move_to(x, y);
    for (delta_x, delta_y) in steps {
        x += delta_x;
        y += delta_y;
        ctx.line_to(x, y);
    }
    ctx.stroke();
    ctx.restore();
}

// We offset all text by the width of the round slider. This ensures
// no clipping due to anti-aliasing.
const X_OFFSET: f64 = 8.0;

fn draw_word(
    ctx: &web_sys::CanvasRenderingContext2d,
    x: f64,
    y: f64,
    word: &CanvasWord,
    last_word: bool,
) -> Result<(), JsValue> {
    ctx.fill_text(word.word, x, y)?;

    draw_path(
        ctx,
        "orange",
        (x, y - 10.0),
        &[(0.0, 10.0), (word.width, 0.0)],
    );

    ctx.save();
    ctx.set_font("10px sans-serif");
    ctx.set_text_align("center");
    ctx.set_text_baseline("top");
    ctx.fill_text(
        &format!("{:.1}px", word.width),
        x + word.width / 2.0,
        y + 3.0,
    )?;
    ctx.restore();

    let x = x + word.width;
    if last_word {
        ctx.fill_text(word.penalty, x, y)?;
        draw_path(ctx, "red", (x, y), &[(word.penalty_width, 0.0)]);
    } else {
        ctx.fill_text(word.whitespace, x, y)?;
        draw_path(ctx, "lightblue", (x, y), &[(word.whitespace_width, 0.0)]);
    }

    Ok(())
}

#[wasm_bindgen]
#[derive(Copy, Clone, Debug)]
pub enum WasmWordSeparator {
    AsciiSpace = "AsciiSpace",
    UnicodeBreakProperties = "UnicodeBreakProperties",
}

#[wasm_bindgen]
#[derive(Copy, Clone, Debug)]
pub enum WasmWordSplitter {
    NoHyphenation = "NoHyphenation",
    HyphenSplitter = "HyphenSplitter",
}

#[wasm_bindgen]
#[derive(Copy, Clone, Debug)]
pub enum WasmWrapAlgorithm {
    FirstFit = "FirstFit",
    OptimalFit = "OptimalFit",
}

#[wasm_bindgen]
#[derive(Copy, Clone, Debug, Default)]
pub struct WasmPenalties {
    pub nline_penalty: usize,
    pub overflow_penalty: usize,
    pub short_last_line_fraction: usize,
    pub short_last_line_penalty: usize,
    pub hyphen_penalty: usize,
}

#[wasm_bindgen]
impl WasmPenalties {
    #[wasm_bindgen(constructor)]
    pub fn new(
        nline_penalty: usize,
        overflow_penalty: usize,
        short_last_line_fraction: usize,
        short_last_line_penalty: usize,
        hyphen_penalty: usize,
    ) -> WasmPenalties {
        WasmPenalties {
            nline_penalty,
            overflow_penalty,
            short_last_line_fraction,
            short_last_line_penalty,
            hyphen_penalty,
        }
    }
}

impl From<WasmPenalties> for Penalties {
    fn from(val: WasmPenalties) -> Self {
        Penalties {
            nline_penalty: val.nline_penalty,
            overflow_penalty: val.overflow_penalty,
            short_last_line_fraction: val.short_last_line_fraction,
            short_last_line_penalty: val.short_last_line_penalty,
            hyphen_penalty: val.hyphen_penalty,
        }
    }
}

#[wasm_bindgen]
#[derive(Copy, Clone, Debug)]
pub struct WasmOptions {
    pub width: f64,
    pub break_words: bool,
    pub word_separator: WasmWordSeparator,
    pub word_splitter: WasmWordSplitter,
    pub wrap_algorithm: WasmWrapAlgorithm,
    pub penalties: WasmPenalties,
}

#[wasm_bindgen]
impl WasmOptions {
    #[wasm_bindgen(constructor)]
    pub fn new(
        width: f64,
        break_words: bool,
        word_separator: WasmWordSeparator,
        word_splitter: WasmWordSplitter,
        wrap_algorithm: WasmWrapAlgorithm,
        penalties: WasmPenalties,
    ) -> WasmOptions {
        WasmOptions {
            width,
            break_words,
            word_separator,
            word_splitter,
            wrap_algorithm,
            penalties,
        }
    }
}

#[wasm_bindgen]
pub fn draw_wrapped_text(
    ctx: &web_sys::CanvasRenderingContext2d,
    options: &WasmOptions,
    text: &str,
) -> Result<(), JsValue> {
    console_error_panic_hook::set_once();

    let metrics: web_sys::TextMetrics = ctx.measure_text("│").unwrap();
    let metrics: ExtendedTextMetrics = metrics.unchecked_into();
    // TODO: use metrics.font_bounding_box_ascent() +
    // metrics.font_bounding_box_descent() and measure "" instead of a
    // tall character when supported by Firefox.
    let line_height = metrics.actual_bounding_box_ascent() + metrics.actual_bounding_box_descent();
    let baseline_distance = 1.5 * line_height;

    let word_separator = match options.word_separator {
        WasmWordSeparator::AsciiSpace => WordSeparator::AsciiSpace,
        WasmWordSeparator::UnicodeBreakProperties => WordSeparator::UnicodeBreakProperties,
        _ => Err("WasmOptions has an invalid word_separator field")?,
    };

    let word_splitter = match options.word_splitter {
        WasmWordSplitter::NoHyphenation => WordSplitter::NoHyphenation,
        WasmWordSplitter::HyphenSplitter => WordSplitter::HyphenSplitter,
        _ => Err("WasmOptions has an invalid word_splitter field")?,
    };

    let mut lineno = 0;
    for line in text.split('\n') {
        let words = word_separator.find_words(line);
        let split_words = split_words(words, &word_splitter);

        let canvas_words = split_words
            .flat_map(|word| {
                let canvas_word = CanvasWord::from(ctx, word);
                if options.break_words {
                    canvas_word.break_apart(ctx, options.width)
                } else {
                    vec![canvas_word]
                }
            })
            .collect::<Vec<_>>();

        let line_lengths = [options.width];
        let wrapped_words = match options.wrap_algorithm {
            WasmWrapAlgorithm::FirstFit => wrap_first_fit(&canvas_words, &line_lengths),
            WasmWrapAlgorithm::OptimalFit => {
                let penalties = options.penalties.into();
                wrap_optimal_fit(&canvas_words, &line_lengths, &penalties).unwrap()
            }
            _ => Err("WasmOptions has an invalid wrap_algorithm field")?,
        };

        for words_in_line in wrapped_words {
            lineno += 1;
            let mut x = X_OFFSET;
            let y = baseline_distance * lineno as f64;

            for (i, word) in words_in_line.iter().enumerate() {
                let last_word = i == words_in_line.len() - 1;
                draw_word(ctx, x, y, word, last_word)?;
                x += word.width;
                x += if last_word {
                    word.penalty_width
                } else {
                    word.whitespace_width
                };
            }

            ctx.save();
            ctx.set_font("10px sans-serif");
            ctx.fill_text(
                &format!("{:.1}px", x - X_OFFSET),
                1.5 * X_OFFSET + options.width,
                y,
            )?;
            ctx.restore();
        }
    }

    draw_path(
        ctx,
        "blue",
        (
            X_OFFSET + options.width,
            metrics.actual_bounding_box_ascent(),
        ),
        &[(0.0, baseline_distance * lineno as f64)],
    );

    Ok(())
}
<|endoftext|>


<commit_before>use libc;
use std::io;

pub mod public {
    use libc;
    use std::time::Duration;

    pub type CSocket = libc::c_int;
    pub type Buf = *const libc::c_void;
    pub type MutBuf = *mut libc::c_void;
    pub type BufLen = libc::size_t;
    pub type CouldFail = libc::ssize_t;
    pub type SockLen = libc::socklen_t;
    pub type MutSockLen = *mut libc::socklen_t;
    pub type SockAddr = libc::sockaddr;
    pub type SockAddrIn = libc::sockaddr_in;
    pub type SockAddrIn6 = libc::sockaddr_in6;
    pub type SockAddrStorage = libc::sockaddr_storage;
    pub type SockAddrFamily = libc::sa_family_t;
    pub type SockAddrFamily6 = libc::sa_family_t;
    pub type InAddr = libc::in_addr;
    pub type In6Addr = libc::in6_addr;

    pub const AF_INET: libc::c_int = libc::AF_INET;
    pub const AF_INET6: libc::c_int = libc::AF_INET6;
    pub const SOCK_RAW: libc::c_int = libc::SOCK_RAW;

    pub const SOL_SOCKET: libc::c_int = libc::SOL_SOCKET;
    pub const SO_RCVTIMEO: libc::c_int = libc::SO_RCVTIMEO;
    pub const SO_SNDTIMEO: libc::c_int = libc::SO_SNDTIMEO;

    pub const IPPROTO_IP: libc::c_int = libc::IPPROTO_IP;
    pub const IP_HDRINCL: libc::c_int = libc::IP_HDRINCL;
    pub const IP_TTL: libc::c_int = libc::IP_TTL;

    pub use libc::{IFF_UP, IFF_BROADCAST, IFF_LOOPBACK, IFF_POINTOPOINT, IFF_MULTICAST};

    pub const INVALID_SOCKET: CSocket = -1;

    pub unsafe fn close(sock: CSocket) {
        let _ = libc::close(sock);
    }

    pub unsafe fn socket(af: libc::c_int, sock: libc::c_int, proto: libc::c_int) -> CSocket {
        libc::socket(af, sock, proto)
    }

    pub unsafe fn getsockopt(socket: CSocket,
                            level: libc::c_int,
                            name: libc::c_int,
                            value: MutBuf,
                            option_len: MutSockLen)
        -> libc::c_int {
        libc::getsockopt(socket, level, name, value, option_len)
    }

    pub unsafe fn setsockopt(socket: CSocket,
                            level: libc::c_int,
                            name: libc::c_int,
                            value: Buf,
                            option_len: SockLen)
        -> libc::c_int {
        libc::setsockopt(socket, level, name, value, option_len)
    }

    pub fn timeval_to_duration(tv: libc::timeval) -> Duration {
        Duration::new(tv.tv_sec as u64, (tv.tv_usec as u32) * 1000)
    }

    pub fn duration_to_timeval(dur: Duration) -> libc::timeval {
        libc::timeval {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_usec: dur.subsec_micros() as libc::c_long,
        }
    }

    pub fn timespec_to_duration(ts: libc::timespec) -> Duration {
        Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32)
    }

    pub fn duration_to_timespec(dur: Duration) -> libc::timespec {
        libc::timespec {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_nsec: dur.subsec_nanos() as libc::c_long,
        }
    }

}

use self::public::*;

#[inline(always)]
pub fn ipv4_addr(addr: InAddr) -> u32 {
    (addr.s_addr as u32).to_be()
}

#[inline(always)]
pub fn mk_inaddr(addr: u32) -> InAddr {
    InAddr { s_addr: addr }
}

pub unsafe fn sendto(socket: CSocket,
                     buf: Buf,
                     len: BufLen,
                     flags: libc::c_int,
                     addr: *const SockAddr,
                     addrlen: SockLen)
    -> CouldFail {
    libc::sendto(socket, buf, len, flags, addr, addrlen)
}

pub unsafe fn recvfrom(socket: CSocket,
                       buf: MutBuf,
                       len: BufLen,
                       flags: libc::c_int,
                       addr: *mut SockAddr,
                       addrlen: *mut SockLen)
    -> CouldFail {
    libc::recvfrom(socket, buf, len, flags, addr, addrlen)
}

#[inline]
pub fn retry<F>(f: &mut F) -> libc::ssize_t
    where F: FnMut() -> libc::ssize_t
{
    loop {
        let ret = f();
        if ret != -1 || errno() as isize != libc::EINTR as isize {
            return ret;
        }
    }
}

fn errno() -> i32 {
    io::Error::last_os_error().raw_os_error().unwrap()
}

#[cfg(test)]
mod tests {
    use std::time::Duration;
    use duration_to_timespec;
    use timespec_to_duration;

    #[test]
    fn test_duration_to_timespec(){
        let d1 = Duration::new(1, 0);
        let d2 = Duration::from_millis(500);

        let t1 = duration_to_timespec(d1);
        let t2 = duration_to_timespec(d2);

        let r1 = timespec_to_duration(t1);
        let r2 = timespec_to_duration(t2);

        assert_eq!(d1, r1);
        assert_eq!(d2, r2);
    }
}
<commit_msg>Use MacOS specific tv_usec type<commit_after>use libc;
use std::io;

pub mod public {
    use libc;
    use std::time::Duration;

    pub type CSocket = libc::c_int;
    pub type Buf = *const libc::c_void;
    pub type MutBuf = *mut libc::c_void;
    pub type BufLen = libc::size_t;
    pub type CouldFail = libc::ssize_t;
    pub type SockLen = libc::socklen_t;
    pub type MutSockLen = *mut libc::socklen_t;
    pub type SockAddr = libc::sockaddr;
    pub type SockAddrIn = libc::sockaddr_in;
    pub type SockAddrIn6 = libc::sockaddr_in6;
    pub type SockAddrStorage = libc::sockaddr_storage;
    pub type SockAddrFamily = libc::sa_family_t;
    pub type SockAddrFamily6 = libc::sa_family_t;
    pub type InAddr = libc::in_addr;
    pub type In6Addr = libc::in6_addr;

    #[cfg(not(targetos="macos"))]
    pub type TvUsecType = libc::c_long;
    #[cfg(targetos="macos")]
    pub type TvUsecType = libc::__darwin_suseconds_t;

    pub const AF_INET: libc::c_int = libc::AF_INET;
    pub const AF_INET6: libc::c_int = libc::AF_INET6;
    pub const SOCK_RAW: libc::c_int = libc::SOCK_RAW;

    pub const SOL_SOCKET: libc::c_int = libc::SOL_SOCKET;
    pub const SO_RCVTIMEO: libc::c_int = libc::SO_RCVTIMEO;
    pub const SO_SNDTIMEO: libc::c_int = libc::SO_SNDTIMEO;

    pub const IPPROTO_IP: libc::c_int = libc::IPPROTO_IP;
    pub const IP_HDRINCL: libc::c_int = libc::IP_HDRINCL;
    pub const IP_TTL: libc::c_int = libc::IP_TTL;

    pub use libc::{IFF_UP, IFF_BROADCAST, IFF_LOOPBACK, IFF_POINTOPOINT, IFF_MULTICAST};

    pub const INVALID_SOCKET: CSocket = -1;

    pub unsafe fn close(sock: CSocket) {
        let _ = libc::close(sock);
    }

    pub unsafe fn socket(af: libc::c_int, sock: libc::c_int, proto: libc::c_int) -> CSocket {
        libc::socket(af, sock, proto)
    }

    pub unsafe fn getsockopt(socket: CSocket,
                            level: libc::c_int,
                            name: libc::c_int,
                            value: MutBuf,
                            option_len: MutSockLen)
        -> libc::c_int {
        libc::getsockopt(socket, level, name, value, option_len)
    }

    pub unsafe fn setsockopt(socket: CSocket,
                            level: libc::c_int,
                            name: libc::c_int,
                            value: Buf,
                            option_len: SockLen)
        -> libc::c_int {
        libc::setsockopt(socket, level, name, value, option_len)
    }

    /// Convert a platform specific `timeval` into a Duration
    pub fn timeval_to_duration(tv: libc::timeval) -> Duration {
        Duration::new(tv.tv_sec as u64, (tv.tv_usec as u32) * 1000)
    }

    /// Convert a Duration into a platform specific `timeval`
    pub fn duration_to_timeval(dur: Duration) -> libc::timeval {
        libc::timeval {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_usec: dur.subsec_micros() as TvUsecType
        }
    }

    /// Convert a platform specific `timespec` into a Duration
    pub fn timespec_to_duration(ts: libc::timespec) -> Duration {
        Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32)
    }

    /// Convert a Duration into a platform specific `timespec`
    pub fn duration_to_timespec(dur: Duration) -> libc::timespec {
        libc::timespec {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_nsec: dur.subsec_nanos() as TvUsecType
        }
    }

}

use self::public::*;

#[inline(always)]
pub fn ipv4_addr(addr: InAddr) -> u32 {
    (addr.s_addr as u32).to_be()
}

#[inline(always)]
pub fn mk_inaddr(addr: u32) -> InAddr {
    InAddr { s_addr: addr }
}

pub unsafe fn sendto(socket: CSocket,
                     buf: Buf,
                     len: BufLen,
                     flags: libc::c_int,
                     addr: *const SockAddr,
                     addrlen: SockLen)
    -> CouldFail {
    libc::sendto(socket, buf, len, flags, addr, addrlen)
}

pub unsafe fn recvfrom(socket: CSocket,
                       buf: MutBuf,
                       len: BufLen,
                       flags: libc::c_int,
                       addr: *mut SockAddr,
                       addrlen: *mut SockLen)
    -> CouldFail {
    libc::recvfrom(socket, buf, len, flags, addr, addrlen)
}

#[inline]
pub fn retry<F>(f: &mut F) -> libc::ssize_t
    where F: FnMut() -> libc::ssize_t
{
    loop {
        let ret = f();
        if ret != -1 || errno() as isize != libc::EINTR as isize {
            return ret;
        }
    }
}

fn errno() -> i32 {
    io::Error::last_os_error().raw_os_error().unwrap()
}

#[cfg(test)]
mod tests {
    use std::time::Duration;
    use duration_to_timespec;
    use timespec_to_duration;

    #[test]
    fn test_duration_to_timespec(){
        let d1 = Duration::new(1, 0);
        let d2 = Duration::from_millis(500);

        let t1 = duration_to_timespec(d1);
        let t2 = duration_to_timespec(d2);

        let r1 = timespec_to_duration(t1);
        let r2 = timespec_to_duration(t2);

        assert_eq!(d1, r1);
        assert_eq!(d2, r2);
    }
}
<|endoftext|>


<commit_before>//! The module contains an implementation of a simple HTTP/2 client.

use super::super::http::connection::ClientConnection;
use super::super::http::connection::HttpConnection;
use super::super::http::connection::HttpConnect;
use super::super::http::transport::TransportStream;
use super::super::http::session::{DefaultSession, Stream};
use super::super::http::{StreamId, HttpResult, HttpError, Response, Header, Request};

/// A struct implementing a simple HTTP/2 client.
///
/// This client works as an HTTP/1.1 client with a Keep-Alive connection and
/// pipelining might work.
///
/// Multiple requests can be queued up (and sent to the server) by calling
/// `request` multiple times, before any `get_response`.
///
/// Once a `get_response` is issued, the client blocks until it receives the
/// response for the particular request that was referenced in the `get_response`
/// call.
///
/// Therefore, by doing `request` -> `get_response` we can use the HTTP/2
/// connection as a `Keep-Alive` HTTP/1.1 connection and a pipelined flow by
/// queuing up a sequence of requests and then "joining" over them by calling
/// `get_response` for each of them.
///
/// The responses that are returned by the client are very raw representations
/// of the response.
///
/// # Notes
///
/// - For now (temporarily) no requests with bodies are supported.
/// - For now, only HTTP/2 over a cleartext TCP connection is supported.
/// - A direct HTTP/2 connection is used (not an upgrade of an HTTP/1.1
///   connection)
///
/// # Examples
///
/// Issue a simple GET request using the helper `get` method. Premade connection
/// passed to the client.
///
/// ```no_run
/// use std::net::TcpStream;
/// use solicit::http::HttpScheme;
/// use solicit::http::connection::{HttpConnection, write_preface};
/// use solicit::client::SimpleClient;
/// use std::str;
///
/// // Prepare a stream manually... We must write the preface ourselves in this case.
/// // This is a more advanced way to use the client and the `HttpConnect` implementations
/// // should usually be preferred for their convenience.
/// let mut stream = TcpStream::connect(&("http2bin.org", 80)).unwrap();
/// write_preface(&mut stream);
/// // Connect to an HTTP/2 aware server
/// let conn = HttpConnection::<TcpStream, TcpStream>::with_stream(
///                                stream,
///                                HttpScheme::Http,
///                                "http2bin.org".into());
/// let mut client = SimpleClient::with_connection(conn).unwrap();
/// let response = client.get(b"/", &[]).unwrap();
/// assert_eq!(response.stream_id, 1);
/// assert_eq!(response.status_code().unwrap(), 200);
/// // Dump the headers and the response body to stdout.
/// // They are returned as raw bytes for the user to do as they please.
/// // (Note: in general directly decoding assuming a utf8 encoding might not
/// // always work -- this is meant as a simple example that shows that the
/// // response is well formed.)
/// for header in response.headers.iter() {
///     println!("{}: {}",
///         str::from_utf8(&header.0).unwrap(),
///         str::from_utf8(&header.1).unwrap());
/// }
/// println!("{}", str::from_utf8(&response.body).unwrap());
/// ```
///
/// Issue a simple GET request using the helper `get` method. Pass a connector
/// to establish a new connection.
///
/// ```no_run
/// use solicit::http::connection::CleartextConnector;
/// use solicit::client::SimpleClient;
/// use std::str;
///
/// // Connect to an HTTP/2 aware server
/// let connector = CleartextConnector { host: "http2bin.org" };
/// let mut client = SimpleClient::with_connector(connector).unwrap();
/// let response = client.get(b"/", &[]).unwrap();
/// assert_eq!(response.stream_id, 1);
/// assert_eq!(response.status_code().unwrap(), 200);
/// // Dump the headers and the response body to stdout.
/// // They are returned as raw bytes for the user to do as they please.
/// // (Note: in general directly decoding assuming a utf8 encoding might not
/// // always work -- this is meant as a simple example that shows that the
/// // response is well formed.)
/// for header in response.headers.iter() {
///     println!("{}: {}",
///         str::from_utf8(&header.0).unwrap(),
///         str::from_utf8(&header.1).unwrap());
/// }
/// println!("{}", str::from_utf8(&response.body).unwrap());
/// ```
///
/// Issue a GET request over `https` using the `TlsConnector`
///
/// ```no_run
/// use solicit::http::connection::TlsConnector;
/// use solicit::client::SimpleClient;
/// use std::str;
///
/// // Connect to an HTTP/2 aware server
/// let path = "/path/to/certs.pem";
/// let connector = TlsConnector::new("http2bin.org", &path);
/// let mut client = SimpleClient::with_connector(connector).unwrap();
/// let response = client.get(b"/get", &[]).unwrap();
/// assert_eq!(response.stream_id, 1);
/// assert_eq!(response.status_code().unwrap(), 200);
/// // Dump the headers and the response body to stdout.
/// // They are returned as raw bytes for the user to do as they please.
/// // (Note: in general directly decoding assuming a utf8 encoding might not
/// // always work -- this is meant as a simple example that shows that the
/// // response is well formed.)
/// for header in response.headers.iter() {
///     println!("{}: {}",
///         str::from_utf8(&header.0).unwrap(),
///         str::from_utf8(&header.1).unwrap());
/// }
/// println!("{}", str::from_utf8(&response.body).unwrap());
/// ```
pub struct SimpleClient<S> where S: TransportStream {
    /// The underlying `ClientConnection` that the client uses
    conn: ClientConnection<S, S, DefaultSession>,
    /// Holds the ID that can be assigned to the next stream to be opened by the
    /// client.
    next_stream_id: u32,
}

impl<S> SimpleClient<S> where S: TransportStream {
    /// Create a new `SimpleClient` instance that will use the given `HttpConnection`
    /// to communicate to the server.
    ///
    /// It assumes that the connection is in an uninitialized state and will try
    /// to send the client preface and make sure it receives the server preface
    /// before returning.
    pub fn with_connection(conn: HttpConnection<S, S>) -> HttpResult<SimpleClient<S>> {
        let mut client = SimpleClient {
            conn: ClientConnection::with_connection(conn, DefaultSession::new()),
            next_stream_id: 1,
        };

        try!(client.init());

        Ok(client)
    }

    /// A convenience constructor that first tries to establish an HTTP/2
    /// connection by using the given connector instance (an implementation of
    /// the `HttpConnect` trait).
    ///
    /// # Panics
    ///
    /// Currently, it panics if the connector returns an error.
    pub fn with_connector<C>(connector: C) -> HttpResult<SimpleClient<S>>
            where C: HttpConnect<Stream=S> {
        let stream = connector.connect().ok().unwrap();
        let conn = HttpConnection::<S, S>::with_stream(stream.0, stream.1, stream.2.into());
        SimpleClient::with_connection(conn)
    }

    /// Internal helper method that performs the initialization of the client's
    /// connection.
    #[inline]
    fn init(&mut self) -> HttpResult<()> {
        self.conn.init()
    }

    /// Send a request to the server. Blocks until the entire request has been
    /// sent.
    ///
    /// The request is described by the method, the path on which it should be
    /// invoked and the "real" headers that should be included. Clients should
    /// never put pseudo-headers in the `headers` parameter, as those are
    /// automatically included based on metadata.
    ///
    /// # Returns
    ///
    /// If the full request is successfully sent, returns the ID of the stream
    /// on which the request was sent. Clients can use this ID to refer to the
    /// response.
    ///
    /// Any IO errors are propagated.
    pub fn request(&mut self, method: &[u8], path: &[u8], extras: &[Header])
            -> HttpResult<StreamId> {
        let stream_id = self.new_stream();
        let mut headers: Vec<Header> = vec![
            (b":method".to_vec(), method.to_vec()),
            (b":path".to_vec(), path.to_vec()),
            (b":authority".to_vec(), self.conn.host().as_bytes().to_vec()),
            (b":scheme".to_vec(), self.conn.scheme().as_bytes().to_vec()),
        ];
        headers.extend(extras.to_vec().into_iter());

        try!(self.conn.send_request(Request {
            stream_id: stream_id,
            headers: headers,
            body: Vec::new(),
        }));

        Ok(stream_id)
    }

    /// Gets the response for the stream with the given ID. If a valid stream ID
    /// is given, it blocks until a response is received.
    ///
    /// # Returns
    ///
    /// A `Response` if the response can be successfully read.
    ///
    /// Any underlying IO errors are propagated. Errors in the HTTP/2 protocol
    /// also stop processing and are returned to the client.
    pub fn get_response(&mut self, stream_id: StreamId) -> HttpResult<Response> {
        match self.conn.session.get_stream(stream_id) {
            None => return Err(HttpError::UnknownStreamId),
            Some(_) => {},
        };
        loop {
            if let Some(stream) = self.conn.session.get_stream(stream_id) {
                if stream.is_closed() {
                    return Ok(Response {
                        stream_id: stream.id(),
                        headers: stream.headers.clone().unwrap(),
                        body: stream.body.clone(),
                    });
                }
            }
            try!(self.handle_next_frame());
        }
    }

    /// Performs a GET request on the given path. This is a shortcut method for
    /// calling `request` followed by `get_response` for the returned stream ID.
    pub fn get(&mut self, path: &[u8], extra_headers: &[Header])
            -> HttpResult<Response> {
        let stream_id = try!(self.request(b"GET", path, extra_headers));
        self.get_response(stream_id)
    }

    /// Internal helper method that initializes a new stream and returns its
    /// ID once done.
    fn new_stream(&mut self) -> StreamId {
        let stream_id = self.get_next_stream_id();
        self.conn.session.new_stream(stream_id);

        stream_id
    }

    /// Internal helper method that gets the next valid stream ID number.
    fn get_next_stream_id(&mut self) -> StreamId {
        let ret = self.next_stream_id;
        self.next_stream_id += 2;

        ret
    }

    /// Internal helper method that triggers the client to handle the next
    /// frame off the HTTP/2 connection.
    #[inline]
    fn handle_next_frame(&mut self) -> HttpResult<()> {
        self.conn.handle_next_frame()
    }
}
<commit_msg>Remove some obsolete documentation<commit_after>//! The module contains an implementation of a simple HTTP/2 client.

use super::super::http::connection::ClientConnection;
use super::super::http::connection::HttpConnection;
use super::super::http::connection::HttpConnect;
use super::super::http::transport::TransportStream;
use super::super::http::session::{DefaultSession, Stream};
use super::super::http::{StreamId, HttpResult, HttpError, Response, Header, Request};

/// A struct implementing a simple HTTP/2 client.
///
/// This client works as an HTTP/1.1 client with a Keep-Alive connection and
/// pipelining might work.
///
/// Multiple requests can be queued up (and sent to the server) by calling
/// `request` multiple times, before any `get_response`.
///
/// Once a `get_response` is issued, the client blocks until it receives the
/// response for the particular request that was referenced in the `get_response`
/// call.
///
/// Therefore, by doing `request` -> `get_response` we can use the HTTP/2
/// connection as a `Keep-Alive` HTTP/1.1 connection and a pipelined flow by
/// queuing up a sequence of requests and then "joining" over them by calling
/// `get_response` for each of them.
///
/// The responses that are returned by the client are very raw representations
/// of the response.
///
/// # Notes
///
/// - For now (temporarily) no requests with bodies are supported.
/// - A direct HTTP/2 connection is used (not an upgrade of an HTTP/1.1
///   connection)
///
/// # Examples
///
/// Issue a simple GET request using the helper `get` method. Premade connection
/// passed to the client.
///
/// ```no_run
/// use std::net::TcpStream;
/// use solicit::http::HttpScheme;
/// use solicit::http::connection::{HttpConnection, write_preface};
/// use solicit::client::SimpleClient;
/// use std::str;
///
/// // Prepare a stream manually... We must write the preface ourselves in this case.
/// // This is a more advanced way to use the client and the `HttpConnect` implementations
/// // should usually be preferred for their convenience.
/// let mut stream = TcpStream::connect(&("http2bin.org", 80)).unwrap();
/// write_preface(&mut stream);
/// // Connect to an HTTP/2 aware server
/// let conn = HttpConnection::<TcpStream, TcpStream>::with_stream(
///                                stream,
///                                HttpScheme::Http,
///                                "http2bin.org".into());
/// let mut client = SimpleClient::with_connection(conn).unwrap();
/// let response = client.get(b"/", &[]).unwrap();
/// assert_eq!(response.stream_id, 1);
/// assert_eq!(response.status_code().unwrap(), 200);
/// // Dump the headers and the response body to stdout.
/// // They are returned as raw bytes for the user to do as they please.
/// // (Note: in general directly decoding assuming a utf8 encoding might not
/// // always work -- this is meant as a simple example that shows that the
/// // response is well formed.)
/// for header in response.headers.iter() {
///     println!("{}: {}",
///         str::from_utf8(&header.0).unwrap(),
///         str::from_utf8(&header.1).unwrap());
/// }
/// println!("{}", str::from_utf8(&response.body).unwrap());
/// ```
///
/// Issue a simple GET request using the helper `get` method. Pass a connector
/// to establish a new connection.
///
/// ```no_run
/// use solicit::http::connection::CleartextConnector;
/// use solicit::client::SimpleClient;
/// use std::str;
///
/// // Connect to an HTTP/2 aware server
/// let connector = CleartextConnector { host: "http2bin.org" };
/// let mut client = SimpleClient::with_connector(connector).unwrap();
/// let response = client.get(b"/", &[]).unwrap();
/// assert_eq!(response.stream_id, 1);
/// assert_eq!(response.status_code().unwrap(), 200);
/// // Dump the headers and the response body to stdout.
/// // They are returned as raw bytes for the user to do as they please.
/// // (Note: in general directly decoding assuming a utf8 encoding might not
/// // always work -- this is meant as a simple example that shows that the
/// // response is well formed.)
/// for header in response.headers.iter() {
///     println!("{}: {}",
///         str::from_utf8(&header.0).unwrap(),
///         str::from_utf8(&header.1).unwrap());
/// }
/// println!("{}", str::from_utf8(&response.body).unwrap());
/// ```
///
/// Issue a GET request over `https` using the `TlsConnector`
///
/// ```no_run
/// use solicit::http::connection::TlsConnector;
/// use solicit::client::SimpleClient;
/// use std::str;
///
/// // Connect to an HTTP/2 aware server
/// let path = "/path/to/certs.pem";
/// let connector = TlsConnector::new("http2bin.org", &path);
/// let mut client = SimpleClient::with_connector(connector).unwrap();
/// let response = client.get(b"/get", &[]).unwrap();
/// assert_eq!(response.stream_id, 1);
/// assert_eq!(response.status_code().unwrap(), 200);
/// // Dump the headers and the response body to stdout.
/// // They are returned as raw bytes for the user to do as they please.
/// // (Note: in general directly decoding assuming a utf8 encoding might not
/// // always work -- this is meant as a simple example that shows that the
/// // response is well formed.)
/// for header in response.headers.iter() {
///     println!("{}: {}",
///         str::from_utf8(&header.0).unwrap(),
///         str::from_utf8(&header.1).unwrap());
/// }
/// println!("{}", str::from_utf8(&response.body).unwrap());
/// ```
pub struct SimpleClient<S> where S: TransportStream {
    /// The underlying `ClientConnection` that the client uses
    conn: ClientConnection<S, S, DefaultSession>,
    /// Holds the ID that can be assigned to the next stream to be opened by the
    /// client.
    next_stream_id: u32,
}

impl<S> SimpleClient<S> where S: TransportStream {
    /// Create a new `SimpleClient` instance that will use the given `HttpConnection`
    /// to communicate to the server.
    ///
    /// It assumes that the connection is in an uninitialized state and will try
    /// to send the client preface and make sure it receives the server preface
    /// before returning.
    pub fn with_connection(conn: HttpConnection<S, S>) -> HttpResult<SimpleClient<S>> {
        let mut client = SimpleClient {
            conn: ClientConnection::with_connection(conn, DefaultSession::new()),
            next_stream_id: 1,
        };

        try!(client.init());

        Ok(client)
    }

    /// A convenience constructor that first tries to establish an HTTP/2
    /// connection by using the given connector instance (an implementation of
    /// the `HttpConnect` trait).
    ///
    /// # Panics
    ///
    /// Currently, it panics if the connector returns an error.
    pub fn with_connector<C>(connector: C) -> HttpResult<SimpleClient<S>>
            where C: HttpConnect<Stream=S> {
        let stream = connector.connect().ok().unwrap();
        let conn = HttpConnection::<S, S>::with_stream(stream.0, stream.1, stream.2.into());
        SimpleClient::with_connection(conn)
    }

    /// Internal helper method that performs the initialization of the client's
    /// connection.
    #[inline]
    fn init(&mut self) -> HttpResult<()> {
        self.conn.init()
    }

    /// Send a request to the server. Blocks until the entire request has been
    /// sent.
    ///
    /// The request is described by the method, the path on which it should be
    /// invoked and the "real" headers that should be included. Clients should
    /// never put pseudo-headers in the `headers` parameter, as those are
    /// automatically included based on metadata.
    ///
    /// # Returns
    ///
    /// If the full request is successfully sent, returns the ID of the stream
    /// on which the request was sent. Clients can use this ID to refer to the
    /// response.
    ///
    /// Any IO errors are propagated.
    pub fn request(&mut self, method: &[u8], path: &[u8], extras: &[Header])
            -> HttpResult<StreamId> {
        let stream_id = self.new_stream();
        let mut headers: Vec<Header> = vec![
            (b":method".to_vec(), method.to_vec()),
            (b":path".to_vec(), path.to_vec()),
            (b":authority".to_vec(), self.conn.host().as_bytes().to_vec()),
            (b":scheme".to_vec(), self.conn.scheme().as_bytes().to_vec()),
        ];
        headers.extend(extras.to_vec().into_iter());

        try!(self.conn.send_request(Request {
            stream_id: stream_id,
            headers: headers,
            body: Vec::new(),
        }));

        Ok(stream_id)
    }

    /// Gets the response for the stream with the given ID. If a valid stream ID
    /// is given, it blocks until a response is received.
    ///
    /// # Returns
    ///
    /// A `Response` if the response can be successfully read.
    ///
    /// Any underlying IO errors are propagated. Errors in the HTTP/2 protocol
    /// also stop processing and are returned to the client.
    pub fn get_response(&mut self, stream_id: StreamId) -> HttpResult<Response> {
        match self.conn.session.get_stream(stream_id) {
            None => return Err(HttpError::UnknownStreamId),
            Some(_) => {},
        };
        loop {
            if let Some(stream) = self.conn.session.get_stream(stream_id) {
                if stream.is_closed() {
                    return Ok(Response {
                        stream_id: stream.id(),
                        headers: stream.headers.clone().unwrap(),
                        body: stream.body.clone(),
                    });
                }
            }
            try!(self.handle_next_frame());
        }
    }

    /// Performs a GET request on the given path. This is a shortcut method for
    /// calling `request` followed by `get_response` for the returned stream ID.
    pub fn get(&mut self, path: &[u8], extra_headers: &[Header])
            -> HttpResult<Response> {
        let stream_id = try!(self.request(b"GET", path, extra_headers));
        self.get_response(stream_id)
    }

    /// Internal helper method that initializes a new stream and returns its
    /// ID once done.
    fn new_stream(&mut self) -> StreamId {
        let stream_id = self.get_next_stream_id();
        self.conn.session.new_stream(stream_id);

        stream_id
    }

    /// Internal helper method that gets the next valid stream ID number.
    fn get_next_stream_id(&mut self) -> StreamId {
        let ret = self.next_stream_id;
        self.next_stream_id += 2;

        ret
    }

    /// Internal helper method that triggers the client to handle the next
    /// frame off the HTTP/2 connection.
    #[inline]
    fn handle_next_frame(&mut self) -> HttpResult<()> {
        self.conn.handle_next_frame()
    }
}
<|endoftext|>


<commit_before>use control_updates as cu;
use controls;
use broadcaster;
use failure::Error as FError;
use json;
use websocket::message::Message;
use std::sync::{Arc, Mutex};

// Implement a ControlUpdateProcessor if you want the controls to actually do something
// on the server.
pub trait ControlUpdateProcessor: Send {
  fn on_update_received(&mut self, &cu::UpdateMsg, ci: &ControlInfo) -> ();
}

// A basic ControlUpdateProcessor that just prints out the update messages.
pub struct PrintUpdateMsg {
}

impl ControlUpdateProcessor for PrintUpdateMsg {
  fn on_update_received(&mut self, update: &cu::UpdateMsg, _ci: &ControlInfo) -> ()
  {
    println!("update callback called! {:?}", update);
  }
}

// Info about all the controls.
pub struct ControlInfo {
  pub cm: controls::ControlMap,
  pub cnm: controls::ControlNameMap,
  pub guijson: String,
}

impl ControlInfo {
  pub fn get_name(&self, id: &Vec<i32>) -> Option<String> {
    match self.cm.get(id) {
      Some(ctrl) => Some(String::from(ctrl.name())),
      _ => None,
    }
  }
}

// The control nexus contains all the controls and the broadcaster.
pub struct ControlNexus {
  pub ci: Arc<Mutex<ControlInfo>>,
  pub bc: broadcaster::Broadcaster,
}

impl ControlNexus {
  fn get_cid_by_name(&self, name: &str) -> Option<Vec<i32>> {
    let guard = match self.ci.lock() {
      Ok(guard) => guard,
      Err(poisoned) => poisoned.into_inner(),
    };

    match guard.cnm.get(name) {
      Some(cid) => Some(cid.clone()),
      _ => None,
    }
  }

  pub fn get_name(&self, id: &Vec<i32>) -> Option<String> {
    let ci = match self.ci.lock() {
      Ok(guard) => guard,
      Err(poisoned) => poisoned.into_inner(),
    };

    match ci.cm.get(id) {
      Some(ctrl) => Some(String::from(ctrl.name())),
      _ => None,
    }
  }

  pub fn make_update_msg(&self, name: &str) -> Option<cu::UpdateMsg> {
    let guard = match self.ci.lock() {
      Ok(guard) => guard,
      Err(poisoned) => poisoned.into_inner(),
    };

    match guard.cnm.get(name) {
      Some(cid) => match guard.cm.get(cid) {
        Some(ctrl) => ctrl.empty_update(),
        None => None,
      },
      _ => None,
    }
  }
  pub fn update(&self, updmsg: &cu::UpdateMsg) {
    let mut ci = match self.ci.lock() {
      Ok(guard) => guard,
      Err(poisoned) => poisoned.into_inner(),
    };

    match ci.cm.get_mut(controls::get_um_id(&updmsg)) {
      Some(ctl) => {
        (*ctl).update(&updmsg);
        let val = json::encode_update_message(&updmsg);
        match serde_json::ser::to_string(&val) {
          Ok(s) => self.bc.broadcast(Message::text(s)),
          Err(_) => (),
        }
      }
      None => (),
    }
  }

  pub fn update_label(&self, name: &str, label: &str) {
    match self.get_cid_by_name(name) {
      Some(cid) => self.update(&cu::UpdateMsg::Label {
        control_id: cid,
        label: String::from(label),
      }),
      None => (),
    }
  }
  pub fn update_button(&self, name: &str, state: Option<cu::PressState>, label: Option<String>) {
    match self.get_cid_by_name(name) {
      Some(cid) => self.update(&cu::UpdateMsg::Button {
        control_id: cid,
        state: state,
        label: label,
      }),
      None => (),
    }
  }
  pub fn update_slider(
    &self,
    name: &str,
    state: Option<cu::PressState>,
    location: Option<f64>,
    label: Option<String>,
  ) {
    match self.get_cid_by_name(name) {
      Some(cid) => self.update(&cu::UpdateMsg::Slider {
        control_id: cid,
        state: state,
        location: location,
        label: label,
      }),
      None => (),
    }
  }
  pub fn load_gui_string(&self, guistring: &str) -> Result<(), FError> {
    let guival = serde_json::from_str(guistring)?;

    let controltree = json::deserialize_root(&guival)?;
    println!("new control layout recieved!");

    println!(
      "title: {} count: {} ",
      controltree.title,
      controltree.root_control.control_type()
    );
    println!("controls: {:?}", controltree.root_control);

    let mut guard = match self.ci.lock() {
      Ok(guard) => guard,
      Err(poisoned) => poisoned.into_inner(),
    };

    (*guard).cm = controls::make_control_map(&*controltree.root_control);
    (*guard).cnm = controls::control_map_to_name_map(&(*guard).cm);
    (*guard).guijson = guistring.to_string();

    // send the updated gui string to all clients.
    self.bc.broadcast(Message::text(guistring.to_string()));

    Ok(())
  }
}
<commit_msg>format and println revisions<commit_after>use broadcaster;
use control_updates as cu;
use controls;
use failure::Error as FError;
use json;
use std::sync::{Arc, Mutex};
use websocket::message::Message;

// Implement a ControlUpdateProcessor if you want the controls to actually do something
// on the server.
pub trait ControlUpdateProcessor: Send {
  fn on_update_received(&mut self, &cu::UpdateMsg, ci: &ControlInfo) -> ();
}

// A basic ControlUpdateProcessor that just prints out the update messages.
pub struct PrintUpdateMsg {}

impl ControlUpdateProcessor for PrintUpdateMsg {
  fn on_update_received(&mut self, update: &cu::UpdateMsg, _ci: &ControlInfo) -> () {
    println!("control update: {:?}", update);
  }
}

// Info about all the controls.
pub struct ControlInfo {
  pub cm: controls::ControlMap,
  pub cnm: controls::ControlNameMap,
  pub guijson: String,
}

impl ControlInfo {
  pub fn get_name(&self, id: &Vec<i32>) -> Option<String> {
    match self.cm.get(id) {
      Some(ctrl) => Some(String::from(ctrl.name())),
      _ => None,
    }
  }
}

// The control nexus contains all the controls and the broadcaster.
pub struct ControlNexus {
  pub ci: Arc<Mutex<ControlInfo>>,
  pub bc: broadcaster::Broadcaster,
}

impl ControlNexus {
  fn get_cid_by_name(&self, name: &str) -> Option<Vec<i32>> {
    let guard = match self.ci.lock() {
      Ok(guard) => guard,
      Err(poisoned) => poisoned.into_inner(),
    };

    match guard.cnm.get(name) {
      Some(cid) => Some(cid.clone()),
      _ => None,
    }
  }
  pub fn get_name(&self, id: &Vec<i32>) -> Option<String> {
    let ci = match self.ci.lock() {
      Ok(guard) => guard,
      Err(poisoned) => poisoned.into_inner(),
    };

    match ci.cm.get(id) {
      Some(ctrl) => Some(String::from(ctrl.name())),
      _ => None,
    }
  }
  pub fn make_update_msg(&self, name: &str) -> Option<cu::UpdateMsg> {
    let guard = match self.ci.lock() {
      Ok(guard) => guard,
      Err(poisoned) => poisoned.into_inner(),
    };

    match guard.cnm.get(name) {
      Some(cid) => match guard.cm.get(cid) {
        Some(ctrl) => ctrl.empty_update(),
        None => None,
      },
      _ => None,
    }
  }
  pub fn update(&self, updmsg: &cu::UpdateMsg) {
    let mut ci = match self.ci.lock() {
      Ok(guard) => guard,
      Err(poisoned) => poisoned.into_inner(),
    };

    match ci.cm.get_mut(controls::get_um_id(&updmsg)) {
      Some(ctl) => {
        (*ctl).update(&updmsg);
        let val = json::encode_update_message(&updmsg);
        match serde_json::ser::to_string(&val) {
          Ok(s) => self.bc.broadcast(Message::text(s)),
          Err(_) => (),
        }
      }
      None => (),
    }
  }
  pub fn update_label(&self, name: &str, label: &str) {
    match self.get_cid_by_name(name) {
      Some(cid) => self.update(&cu::UpdateMsg::Label {
        control_id: cid,
        label: String::from(label),
      }),
      None => (),
    }
  }
  pub fn update_button(&self, name: &str, state: Option<cu::PressState>, label: Option<String>) {
    match self.get_cid_by_name(name) {
      Some(cid) => self.update(&cu::UpdateMsg::Button {
        control_id: cid,
        state: state,
        label: label,
      }),
      None => (),
    }
  }
  pub fn update_slider(
    &self,
    name: &str,
    state: Option<cu::PressState>,
    location: Option<f64>,
    label: Option<String>,
  ) {
    match self.get_cid_by_name(name) {
      Some(cid) => self.update(&cu::UpdateMsg::Slider {
        control_id: cid,
        state: state,
        location: location,
        label: label,
      }),
      None => (),
    }
  }
  pub fn load_gui_string(&self, guistring: &str) -> Result<(), FError> {
    let guival = serde_json::from_str(guistring)?;

    let controltree = json::deserialize_root(&guival)?;
    println!("new control layout recieved! title: {} ",
      controltree.title
    );
    println!("controls: {:?}", controltree.root_control);

    let mut guard = match self.ci.lock() {
      Ok(guard) => guard,
      Err(poisoned) => poisoned.into_inner(),
    };

    (*guard).cm = controls::make_control_map(&*controltree.root_control);
    (*guard).cnm = controls::control_map_to_name_map(&(*guard).cm);
    (*guard).guijson = guistring.to_string();

    // send the updated gui string to all clients.
    self.bc.broadcast(Message::text(guistring.to_string()));

    Ok(())
  }
}
<|endoftext|>