<commit_before>// Copyright (C) 2019 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use gst::prelude::*;
use gstreamer as gst;

use std::sync::mpsc;

fn init() {
    use std::sync::Once;
    static INIT: Once = Once::new();

    INIT.call_once(|| {
        gst::init().unwrap();
        gstreqwest::plugin_register_static().expect("reqwesthttpsrc tests");
    });
}

/// Our custom test harness around the HTTP source
#[derive(Debug)]
struct Harness {
    src: gst::Element,
    pad: gst::Pad,
    receiver: Option<mpsc::Receiver<Message>>,
    rt: Option<tokio::runtime::Runtime>,
}

/// Messages sent from our test harness
#[derive(Debug, Clone)]
enum Message {
    Buffer(gst::Buffer),
    Event(gst::Event),
    Message(gst::Message),
    ServerError(String),
}

impl Harness {
    /// Creates a new HTTP source and test harness around it
    ///
    /// `http_func`: Function to generate HTTP responses based on a request
    /// `setup_func`: Setup function for the HTTP source, should only set properties and similar
    fn new<
        F: FnMut(hyper::Request<hyper::Body>) -> hyper::Response<hyper::Body> + Send + 'static,
        G: FnOnce(&gst::Element),
    >(
        http_func: F,
        setup_func: G,
    ) -> Harness {
        use hyper::service::{make_service_fn, service_fn_ok};
        use hyper::Server;
        use std::sync::{Arc, Mutex};
        use tokio::prelude::*;

        // Create the HTTP source
        let src = gst::ElementFactory::make("reqwesthttpsrc", None).unwrap();

        // Sender/receiver for the messages we generate from various places for the tests
        //
        // Sending to this sender will block until the corresponding item was received from the
        // receiver, which allows us to handle everything as if it is running in a single thread
        let (sender, receiver) = mpsc::sync_channel(0);

        // Sink pad that receives everything the source is generating
        let pad = gst::Pad::new(Some("sink"), gst::PadDirection::Sink);
        let srcpad = src.get_static_pad("src").unwrap();
        srcpad.link(&pad).unwrap();

        // Collect all buffers, events and messages sent from the source
        let sender_clone = sender.clone();
        pad.set_chain_function(move |_pad, _parent, buffer| {
            let _ = sender_clone.send(Message::Buffer(buffer));
            Ok(gst::FlowSuccess::Ok)
        });
        let sender_clone = sender.clone();
        pad.set_event_function(move |_pad, _parent, event| {
            let _ = sender_clone.send(Message::Event(event));
            true
        });
        let bus = gst::Bus::new();
        bus.set_flushing(false);
        src.set_bus(Some(&bus));
        let sender_clone = sender.clone();
        bus.set_sync_handler(move |_bus, msg| {
            let _ = sender_clone.send(Message::Message(msg.clone()));
            gst::BusSyncReply::Drop
        });

        // Activate the pad so that it can be used now
        pad.set_active(true).unwrap();

        // Create the tokio runtime used for the HTTP server in this test
        let mut rt = tokio::runtime::Builder::new()
            .core_threads(1)
            .build()
            .unwrap();

        // Create an HTTP sever that listens on localhost on some random, free port
        let addr = ([127, 0, 0, 1], 0).into();

        // Whenever a new client is connecting, a new service function is requested. For each
        // client we use the same service function, which simply calls the function used by the
        // test
        let http_func = Arc::new(Mutex::new(http_func));
        let make_service = make_service_fn(move |_ctx| {
            let http_func = http_func.clone();
            service_fn_ok(move |req| (&mut *http_func.lock().unwrap())(req))
        });

        // Bind the server, retrieve the local port that was selected in the end and set this as
        // the location property on the source
        let server = Server::bind(&addr).serve(make_service);
        let local_addr = server.local_addr();
        src.set_property("location", &format!("http://{}/", local_addr))
            .unwrap();

        // Spawn the server in the background so that it can handle requests
        rt.spawn(server.map_err(move |e| {
            let _ = sender.send(Message::ServerError(format!("{:?}", e)));
        }));

        // Let the test setup anything needed on the HTTP source now
        setup_func(&src);

        Harness {
            src,
            pad,
            receiver: Some(receiver),
            rt: Some(rt),
        }
    }

    fn wait_for_error(&mut self) -> glib::Error {
        loop {
            match self.receiver.as_mut().unwrap().recv().unwrap() {
                Message::ServerError(err) => {
                    panic!("Got server error: {}", err);
                }
                Message::Event(ev) => {
                    use gst::EventView;

                    match ev.view() {
                        EventView::Eos(_) => {
                            panic!("Got EOS but expected error");
                        }
                        _ => (),
                    }
                }
                Message::Message(msg) => {
                    use gst::MessageView;

                    match msg.view() {
                        MessageView::Error(err) => {
                            return err.get_error();
                        }
                        _ => (),
                    }
                }
                Message::Buffer(_buffer) => {
                    panic!("Got buffer but expected error");
                }
            }
        }
    }

    /// Wait until a buffer is available or EOS was reached
    ///
    /// This function will panic on errors.
    fn wait_buffer_or_eos(&mut self) -> Option<gst::Buffer> {
        loop {
            match self.receiver.as_mut().unwrap().recv().unwrap() {
                Message::ServerError(err) => {
                    panic!("Got server error: {}", err);
                }
                Message::Event(ev) => {
                    use gst::EventView;

                    match ev.view() {
                        EventView::Eos(_) => return None,
                        _ => (),
                    }
                }
                Message::Message(msg) => {
                    use gst::MessageView;

                    match msg.view() {
                        MessageView::Error(err) => {
                            use std::error::Error;

                            panic!(
                                "Got error: {} ({})",
                                err.get_error().description(),
                                err.get_debug().unwrap_or_else(|| String::from("None"))
                            );
                        }
                        _ => (),
                    }
                }
                Message::Buffer(buffer) => return Some(buffer),
            }
        }
    }

    /// Run some code asynchronously on another thread with the HTTP source
    fn run<F: FnOnce(&gst::Element) + Send + 'static>(&self, func: F) {
        self.src.call_async(move |src| func(src));
    }
}

impl Drop for Harness {
    fn drop(&mut self) {
        use tokio::prelude::*;

        // Shut down everything that was set up for this test harness
        // and wait until the tokio runtime exited
        let bus = self.src.get_bus().unwrap();
        bus.set_flushing(true);

        // Drop the receiver first before setting the state so that
        // any threads that might still be blocked on the sender
        // are immediately unblocked
        self.receiver.take().unwrap();

        self.pad.set_active(false).unwrap();
        self.src.set_state(gst::State::Null).unwrap();

        self.rt.take().unwrap().shutdown_now().wait().unwrap();
    }
}

#[test]
fn test_basic_request() {
    use std::io::{Cursor, Read};
    init();

    // Set up a simple harness that returns "Hello World" for any HTTP request
    let mut h = Harness::new(
        |_req| {
            use hyper::{Body, Response};

            Response::new(Body::from("Hello World"))
        },
        |_src| {
            // No additional setup needed here
        },
    );

    // Set the HTTP source to Playing so that everything can start
    h.run(|src| {
        src.set_state(gst::State::Playing).unwrap();
    });

    // And now check if the data we receive is exactly what we expect it to be
    let expected_output = "Hello World";
    let mut cursor = Cursor::new(expected_output);

    while let Some(buffer) = h.wait_buffer_or_eos() {
        // On the first buffer also check if the duration reported by the HTTP source is what we
        // would expect it to be
        if cursor.position() == 0 {
            assert_eq!(
                h.src.query_duration::<gst::format::Bytes>(),
                Some(gst::format::Bytes::from(expected_output.len() as u64))
            );
        }

        // Map the buffer readable and check if it contains exactly the data we would expect at
        // this point after reading everything else we read in previous runs
        let map = buffer.map_readable().unwrap();
        let mut read_buf = vec![0; map.get_size()];
        assert_eq!(cursor.read(&mut read_buf).unwrap(), map.get_size());
        assert_eq!(&*map, &*read_buf);
    }

    // Check if everything was read
    assert_eq!(cursor.position(), 11);
}

#[test]
fn test_404_error() {
    use reqwest::StatusCode;
    init();

    let mut h = Harness::new(
        |_req| {
            use hyper::{Body, Response};

            Response::builder()
                .status(StatusCode::NOT_FOUND.as_u16())
                .body(Body::empty())
                .unwrap()
        },
        |_src| {},
    );

    h.run(|src| {
        let _ = src.set_state(gst::State::Playing);
    });

    let err_code = h.wait_for_error();
    if let Some(err) = err_code.kind::<gst::ResourceError>() {
        assert_eq!(err, gst::ResourceError::NotFound);
    }
}
<commit_msg>reqwesthttpsrc: Add a seeking test<commit_after>// Copyright (C) 2019 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use gst::prelude::*;
use gstreamer as gst;

use std::sync::mpsc;

fn init() {
    use std::sync::Once;
    static INIT: Once = Once::new();

    INIT.call_once(|| {
        gst::init().unwrap();
        gstreqwest::plugin_register_static().expect("reqwesthttpsrc tests");
    });
}

/// Our custom test harness around the HTTP source
#[derive(Debug)]
struct Harness {
    src: gst::Element,
    pad: gst::Pad,
    receiver: Option<mpsc::Receiver<Message>>,
    rt: Option<tokio::runtime::Runtime>,
}

/// Messages sent from our test harness
#[derive(Debug, Clone)]
enum Message {
    Buffer(gst::Buffer),
    Event(gst::Event),
    Message(gst::Message),
    ServerError(String),
}

impl Harness {
    /// Creates a new HTTP source and test harness around it
    ///
    /// `http_func`: Function to generate HTTP responses based on a request
    /// `setup_func`: Setup function for the HTTP source, should only set properties and similar
    fn new<
        F: FnMut(hyper::Request<hyper::Body>) -> hyper::Response<hyper::Body> + Send + 'static,
        G: FnOnce(&gst::Element),
    >(
        http_func: F,
        setup_func: G,
    ) -> Harness {
        use hyper::service::{make_service_fn, service_fn_ok};
        use hyper::Server;
        use std::sync::{Arc, Mutex};
        use tokio::prelude::*;

        // Create the HTTP source
        let src = gst::ElementFactory::make("reqwesthttpsrc", None).unwrap();

        // Sender/receiver for the messages we generate from various places for the tests
        //
        // Sending to this sender will block until the corresponding item was received from the
        // receiver, which allows us to handle everything as if it is running in a single thread
        let (sender, receiver) = mpsc::sync_channel(0);

        // Sink pad that receives everything the source is generating
        let pad = gst::Pad::new(Some("sink"), gst::PadDirection::Sink);
        let srcpad = src.get_static_pad("src").unwrap();
        srcpad.link(&pad).unwrap();

        // Collect all buffers, events and messages sent from the source
        let sender_clone = sender.clone();
        pad.set_chain_function(move |_pad, _parent, buffer| {
            let _ = sender_clone.send(Message::Buffer(buffer));
            Ok(gst::FlowSuccess::Ok)
        });
        let sender_clone = sender.clone();
        pad.set_event_function(move |_pad, _parent, event| {
            let _ = sender_clone.send(Message::Event(event));
            true
        });
        let bus = gst::Bus::new();
        bus.set_flushing(false);
        src.set_bus(Some(&bus));
        let sender_clone = sender.clone();
        bus.set_sync_handler(move |_bus, msg| {
            let _ = sender_clone.send(Message::Message(msg.clone()));
            gst::BusSyncReply::Drop
        });

        // Activate the pad so that it can be used now
        pad.set_active(true).unwrap();

        // Create the tokio runtime used for the HTTP server in this test
        let mut rt = tokio::runtime::Builder::new()
            .core_threads(1)
            .build()
            .unwrap();

        // Create an HTTP sever that listens on localhost on some random, free port
        let addr = ([127, 0, 0, 1], 0).into();

        // Whenever a new client is connecting, a new service function is requested. For each
        // client we use the same service function, which simply calls the function used by the
        // test
        let http_func = Arc::new(Mutex::new(http_func));
        let make_service = make_service_fn(move |_ctx| {
            let http_func = http_func.clone();
            service_fn_ok(move |req| (&mut *http_func.lock().unwrap())(req))
        });

        // Bind the server, retrieve the local port that was selected in the end and set this as
        // the location property on the source
        let server = Server::bind(&addr).serve(make_service);
        let local_addr = server.local_addr();
        src.set_property("location", &format!("http://{}/", local_addr))
            .unwrap();

        // Spawn the server in the background so that it can handle requests
        rt.spawn(server.map_err(move |e| {
            let _ = sender.send(Message::ServerError(format!("{:?}", e)));
        }));

        // Let the test setup anything needed on the HTTP source now
        setup_func(&src);

        Harness {
            src,
            pad,
            receiver: Some(receiver),
            rt: Some(rt),
        }
    }

    fn wait_for_error(&mut self) -> glib::Error {
        loop {
            match self.receiver.as_mut().unwrap().recv().unwrap() {
                Message::ServerError(err) => {
                    panic!("Got server error: {}", err);
                }
                Message::Event(ev) => {
                    use gst::EventView;

                    match ev.view() {
                        EventView::Eos(_) => {
                            panic!("Got EOS but expected error");
                        }
                        _ => (),
                    }
                }
                Message::Message(msg) => {
                    use gst::MessageView;

                    match msg.view() {
                        MessageView::Error(err) => {
                            return err.get_error();
                        }
                        _ => (),
                    }
                }
                Message::Buffer(_buffer) => {
                    panic!("Got buffer but expected error");
                }
            }
        }
    }

    fn wait_for_state_change(&mut self) -> gst::State {
        loop {
            match self.receiver.as_mut().unwrap().recv().unwrap() {
                Message::ServerError(err) => {
                    panic!("Got server error: {}", err);
                }
                Message::Event(ev) => {
                    use gst::EventView;

                    match ev.view() {
                        EventView::Eos(_) => {
                            panic!("Got EOS but expected state change");
                        }
                        _ => (),
                    }
                }
                Message::Message(msg) => {
                    use gst::MessageView;

                    match msg.view() {
                        MessageView::StateChanged(state) => {
                            return state.get_current();
                        }
                        MessageView::Error(err) => {
                            use std::error::Error;
                            panic!(
                                "Got error: {} ({})",
                                err.get_error().description(),
                                err.get_debug().unwrap_or_else(|| String::from("None"))
                            );
                        }
                        _ => (),
                    }
                }
                Message::Buffer(_buffer) => {
                    panic!("Got buffer but expected state change");
                }
            }
        }
    }

    fn wait_for_segment(
        &mut self,
        allow_buffer: bool,
    ) -> gst::FormattedSegment<gst::format::Bytes> {
        loop {
            match self.receiver.as_mut().unwrap().recv().unwrap() {
                Message::ServerError(err) => {
                    panic!("Got server error: {}", err);
                }
                Message::Event(ev) => {
                    use gst::EventView;

                    match ev.view() {
                        EventView::Segment(seg) => {
                            return seg
                                .get_segment()
                                .clone()
                                .downcast::<gst::format::Bytes>()
                                .unwrap();
                        }
                        _ => (),
                    }
                }
                Message::Message(msg) => {
                    use gst::MessageView;

                    match msg.view() {
                        MessageView::Error(err) => {
                            use std::error::Error;
                            panic!(
                                "Got error: {} ({})",
                                err.get_error().description(),
                                err.get_debug().unwrap_or_else(|| String::from("None"))
                            );
                        }
                        _ => (),
                    }
                }
                Message::Buffer(_buffer) => {
                    if !allow_buffer {
                        panic!("Got buffer but expected segment");
                    }
                }
            }
        }
    }

    /// Wait until a buffer is available or EOS was reached
    ///
    /// This function will panic on errors.
    fn wait_buffer_or_eos(&mut self) -> Option<gst::Buffer> {
        loop {
            match self.receiver.as_mut().unwrap().recv().unwrap() {
                Message::ServerError(err) => {
                    panic!("Got server error: {}", err);
                }
                Message::Event(ev) => {
                    use gst::EventView;

                    match ev.view() {
                        EventView::Eos(_) => return None,
                        _ => (),
                    }
                }
                Message::Message(msg) => {
                    use gst::MessageView;

                    match msg.view() {
                        MessageView::Error(err) => {
                            use std::error::Error;

                            panic!(
                                "Got error: {} ({})",
                                err.get_error().description(),
                                err.get_debug().unwrap_or_else(|| String::from("None"))
                            );
                        }
                        _ => (),
                    }
                }
                Message::Buffer(buffer) => return Some(buffer),
            }
        }
    }

    /// Run some code asynchronously on another thread with the HTTP source
    fn run<F: FnOnce(&gst::Element) + Send + 'static>(&self, func: F) {
        self.src.call_async(move |src| func(src));
    }
}

impl Drop for Harness {
    fn drop(&mut self) {
        use tokio::prelude::*;

        // Shut down everything that was set up for this test harness
        // and wait until the tokio runtime exited
        let bus = self.src.get_bus().unwrap();
        bus.set_flushing(true);

        // Drop the receiver first before setting the state so that
        // any threads that might still be blocked on the sender
        // are immediately unblocked
        self.receiver.take().unwrap();

        self.pad.set_active(false).unwrap();
        self.src.set_state(gst::State::Null).unwrap();

        self.rt.take().unwrap().shutdown_now().wait().unwrap();
    }
}

#[test]
fn test_basic_request() {
    use std::io::{Cursor, Read};
    init();

    // Set up a simple harness that returns "Hello World" for any HTTP request
    let mut h = Harness::new(
        |_req| {
            use hyper::{Body, Response};

            Response::new(Body::from("Hello World"))
        },
        |_src| {
            // No additional setup needed here
        },
    );

    // Set the HTTP source to Playing so that everything can start
    h.run(|src| {
        src.set_state(gst::State::Playing).unwrap();
    });

    // And now check if the data we receive is exactly what we expect it to be
    let expected_output = "Hello World";
    let mut cursor = Cursor::new(expected_output);

    while let Some(buffer) = h.wait_buffer_or_eos() {
        // On the first buffer also check if the duration reported by the HTTP source is what we
        // would expect it to be
        if cursor.position() == 0 {
            assert_eq!(
                h.src.query_duration::<gst::format::Bytes>(),
                Some(gst::format::Bytes::from(expected_output.len() as u64))
            );
        }

        // Map the buffer readable and check if it contains exactly the data we would expect at
        // this point after reading everything else we read in previous runs
        let map = buffer.map_readable().unwrap();
        let mut read_buf = vec![0; map.get_size()];
        assert_eq!(cursor.read(&mut read_buf).unwrap(), map.get_size());
        assert_eq!(&*map, &*read_buf);
    }

    // Check if everything was read
    assert_eq!(cursor.position(), 11);
}

#[test]
fn test_404_error() {
    use reqwest::StatusCode;
    init();

    let mut h = Harness::new(
        |_req| {
            use hyper::{Body, Response};

            Response::builder()
                .status(StatusCode::NOT_FOUND.as_u16())
                .body(Body::empty())
                .unwrap()
        },
        |_src| {},
    );

    h.run(|src| {
        let _ = src.set_state(gst::State::Playing);
    });

    let err_code = h.wait_for_error();
    if let Some(err) = err_code.kind::<gst::ResourceError>() {
        assert_eq!(err, gst::ResourceError::NotFound);
    }
}

#[test]
fn test_seek_after_ready() {
    use std::io::{Cursor, Read};
    init();

    let mut h = Harness::new(
        |req| {
            use hyper::{Body, Response};

            if req.headers().contains_key("Range") {
                let range = req.headers().get("Range").unwrap();
                if range == "bytes=123-" {
                    let mut data_seek = vec![0; 8192 - 123];
                    for (i, d) in data_seek.iter_mut().enumerate() {
                        *d = (i + 123 % 256) as u8;
                    }

                    Response::builder()
                        .header("content-length", 8192 - 123)
                        .header("accept-ranges", "bytes")
                        .header("content-range", "bytes 123-8192/8192")
                        .body(Body::from(data_seek))
                        .unwrap()
                } else {
                    panic!("Received an unexpected Range header")
                }
            } else {
                // `panic!("Received no Range header")` should be called here but due to a bug
                // in `basesrc` we cant do that here. If we do a seek in READY state, basesrc
                // will do a `start()` call without seek. Once we get seek forwarded, the call
                // with seek is made. This issue has to be solved.
                // issue link: https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/413
                let mut data_full = vec![0; 8192];
                for (i, d) in data_full.iter_mut().enumerate() {
                    *d = (i % 256) as u8;
                }

                Response::builder()
                    .header("content-length", 8192)
                    .header("accept-ranges", "bytes")
                    .body(Body::from(data_full))
                    .unwrap()
            }
        },
        |_src| {},
    );

    h.run(|src| {
        src.set_state(gst::State::Ready).unwrap();
    });

    let current_state = h.wait_for_state_change();
    assert_eq!(current_state, gst::State::Ready);

    h.run(|src| {
        src.seek_simple(gst::SeekFlags::FLUSH, gst::format::Bytes::from(123))
            .unwrap();
        src.set_state(gst::State::Playing).unwrap();
    });

    let segment = h.wait_for_segment(false);
    assert_eq!(
        gst::format::Bytes::from(segment.get_start()),
        gst::format::Bytes::from(123)
    );

    let mut expected_output = vec![0; 8192 - 123];
    for (i, d) in expected_output.iter_mut().enumerate() {
        *d = ((123 + i) % 256) as u8;
    }
    let mut cursor = Cursor::new(expected_output);

    while let Some(buffer) = h.wait_buffer_or_eos() {
        assert_eq!(buffer.get_offset(), 123 + cursor.position());

        let map = buffer.map_readable().unwrap();
        let mut read_buf = vec![0; map.get_size()];

        assert_eq!(cursor.read(&mut read_buf).unwrap(), map.get_size());
        assert_eq!(&*map, &*read_buf);
    }
}

#[test]
fn test_seek_after_buffer_received() {
    use std::io::{Cursor, Read};
    init();

    let mut h = Harness::new(
        |req| {
            use hyper::{Body, Response};

            if req.headers().contains_key("Range") {
                let range = req.headers().get("Range").unwrap();
                if range == "bytes=123-" {
                    let mut data_seek = vec![0; 8192 - 123];
                    for (i, d) in data_seek.iter_mut().enumerate() {
                        *d = (i + 123 % 256) as u8;
                    }

                    Response::builder()
                        .header("content-length", 8192 - 123)
                        .header("accept-ranges", "bytes")
                        .header("content-range", "bytes 123-8192/8192")
                        .body(Body::from(data_seek))
                        .unwrap()
                } else {
                    panic!("Received an unexpected Range header")
                }
            } else {
                let mut data_full = vec![0; 8192];
                for (i, d) in data_full.iter_mut().enumerate() {
                    *d = (i % 256) as u8;
                }

                Response::builder()
                    .header("content-length", 8192)
                    .header("accept-ranges", "bytes")
                    .body(Body::from(data_full))
                    .unwrap()
            }
        },
        |_src| {},
    );

    h.run(|src| {
        src.set_state(gst::State::Playing).unwrap();
    });

    //wait for a buffer
    let buffer = h.wait_buffer_or_eos().unwrap();
    assert_eq!(buffer.get_offset(), 0);

    //seek to a position after a buffer is Received
    h.run(|src| {
        src.seek_simple(gst::SeekFlags::FLUSH, gst::format::Bytes::from(123))
            .unwrap();
    });

    let segment = h.wait_for_segment(true);
    assert_eq!(
        gst::format::Bytes::from(segment.get_start()),
        gst::format::Bytes::from(123)
    );

    let mut expected_output = vec![0; 8192 - 123];
    for (i, d) in expected_output.iter_mut().enumerate() {
        *d = ((123 + i) % 256) as u8;
    }
    let mut cursor = Cursor::new(expected_output);

    while let Some(buffer) = h.wait_buffer_or_eos() {
        assert_eq!(buffer.get_offset(), 123 + cursor.position());

        let map = buffer.map_readable().unwrap();
        let mut read_buf = vec![0; map.get_size()];

        assert_eq!(cursor.read(&mut read_buf).unwrap(), map.get_size());
        assert_eq!(&*map, &*read_buf);
    }
}
<|endoftext|>


<commit_before>pub mod v1 {
    pub enum Entity {
        Account,
        Application,
        Attachment,
        Card,
        Context,
        Error,
        Instance,
        Mention,
        Notification,
        Relationship,
        Report,
        Results,
        Status,
        Tag
    }

    pub enum Method {
        Accounts,
        Apps,
        Blocks,
        Favorites,
        FollowRequests,
        Follows,
        Instances,
        Media,
        Mutes,
        Notifications,
        Reports,
        Search,
        Statuses,
        Timelines
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Account {
        id: i32,
        username: String,
        acct: String,
        display_name: String,
        note: String,
        url: String,
        avatar: String,
        header: String,
        locked: bool,
        created_at: String,
        followers_count: i32,
        following_count: i32,
        statuses_count: i32
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Application {
        pub name: String,
        pub website: Option<String>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Attachment {
        #[serde(rename = "id")]
        pub attachment_id: i32,
        #[serde(rename = "type")]
        pub attachment_type: String,
        pub url: String,
        pub remote_url: String,
        pub preview_url: String,
        pub text_url: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Card {
        pub url: String,
        pub title: String,
        pub description: String,
        pub image: String,
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Context {
        ancestors: Vec<Status>,
        descendants: Vec<Status>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Error {
        pub error: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Instance {
        pub url: String,
        pub title: String,
        pub description: String,
        pub email: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Mention {
        #[serde(rename = "id")]
        pub mention_id: i32,
        pub url: String,
        pub username: String,
        pub acct: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Notification {
        id: i32,
        notification_type: String,
        created_at: String,
        account: Account,
        status: Option<Status>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Relationship {
        #[serde(rename = "id")]
        pub relationship_id: i32,
        pub following: bool,
        pub followed_by: bool,
        pub blocking: bool,
        pub muting: bool,
        pub requested: bool
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Report {
        #[serde(rename = "id")]
        pub report_id: i32,
        pub action_taken: String,
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Results {
        accounts: Vec<Account>,
        statuses: Vec<Status>,
        hashtags: Vec<String>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Status {
        id: i32,
        uri: String,
        url: String,
        account: Account,
        in_reply_to_id: Option<i32>,
        in_reply_to_account_id: Option<i32>,
        reblog: Option<Box<Status>>,
        content: String,
        created_at: String,
        reblogs_count: i32,
        favourites_count: i32,
        reblogged: bool,
        favourited: bool,
        sensitive: bool,
        spoiler_text: String,
        visibility: String,
        media_attachments: Vec<Attachment>,
        mentions: Vec<Mention>,
        tags: Vec<Tag>,
        application: Application
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Tag {
        pub name: String,
        pub url: String
    }
}
<commit_msg>rename fields on some entities to avoid reserved keywords<commit_after>pub mod v1 {
    pub enum Entity {
        Account,
        Application,
        Attachment,
        Card,
        Context,
        Error,
        Instance,
        Mention,
        Notification,
        Relationship,
        Report,
        Results,
        Status,
        Tag
    }

    pub enum Method {
        Accounts,
        Apps,
        Blocks,
        Favorites,
        FollowRequests,
        Follows,
        Instances,
        Media,
        Mutes,
        Notifications,
        Reports,
        Search,
        Statuses,
        Timelines
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Account {
        #[serde(rename = "id")]
        account_id: i32,
        username: String,
        acct: String,
        display_name: String,
        note: String,
        url: String,
        avatar: String,
        header: String,
        locked: bool,
        created_at: String,
        followers_count: i32,
        following_count: i32,
        statuses_count: i32
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Application {
        pub name: String,
        pub website: Option<String>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Attachment {
        #[serde(rename = "id")]
        pub attachment_id: i32,
        #[serde(rename = "type")]
        pub attachment_type: String,
        pub url: String,
        pub remote_url: String,
        pub preview_url: String,
        pub text_url: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Card {
        pub url: String,
        pub title: String,
        pub description: String,
        pub image: String,
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Context {
        ancestors: Vec<Status>,
        descendants: Vec<Status>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Error {
        pub error: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Instance {
        pub url: String,
        pub title: String,
        pub description: String,
        pub email: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Mention {
        #[serde(rename = "id")]
        pub mention_id: i32,
        pub url: String,
        pub username: String,
        pub acct: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Notification {
        #[serde( rename = "id")]
        notification_id: i32,
        #[serde( rename = "type")]
        notification_type: String,
        created_at: String,
        account: Account,
        status: Option<Status>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Relationship {
        #[serde(rename = "id")]
        pub relationship_id: i32,
        pub following: bool,
        pub followed_by: bool,
        pub blocking: bool,
        pub muting: bool,
        pub requested: bool
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Report {
        #[serde(rename = "id")]
        pub report_id: i32,
        pub action_taken: String,
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Results {
        accounts: Vec<Account>,
        statuses: Vec<Status>,
        hashtags: Vec<String>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Status {
        #[serde(rename = "id")]
        status_id: i32,
        uri: String,
        url: String,
        account: Account,
        in_reply_to_id: Option<i32>,
        in_reply_to_account_id: Option<i32>,
        reblog: Option<Box<Status>>,
        content: String,
        created_at: String,
        reblogs_count: i32,
        favourites_count: i32,
        reblogged: bool,
        favourited: bool,
        sensitive: bool,
        spoiler_text: String,
        visibility: String,
        media_attachments: Vec<Attachment>,
        mentions: Vec<Mention>,
        tags: Vec<Tag>,
        application: Application
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Tag {
        pub name: String,
        pub url: String
    }
}
<|endoftext|>


<commit_before>include!(concat!(env!("OUT_DIR"), "/constants.rs"));

use std::collections::BTreeMap;
use std::convert::TryInto;
use std::net::Ipv4Addr;
use std::slice;

use smoltcp::iface::{EthernetInterfaceBuilder, NeighborCache, Routes};
#[cfg(feature = "trace")]
use smoltcp::phy::EthernetTracer;
use smoltcp::phy::{self, Device, DeviceCapabilities};
use smoltcp::socket::SocketSet;
use smoltcp::time::Instant;
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address};

use crate::net::NetworkInterface;

extern "Rust" {
	fn sys_get_mac_address() -> Result<[u8; 6], ()>;
	fn sys_get_mtu() -> Result<u16, ()>;
	fn sys_get_tx_buffer(len: usize) -> Result<(*mut u8, usize), ()>;
	fn sys_send_tx_buffer(handle: usize, len: usize) -> Result<(), ()>;
	fn sys_receive_rx_buffer() -> Result<&'static mut [u8], ()>;
	fn sys_rx_buffer_consumed() -> Result<(), ()>;
	fn sys_free_tx_buffer(handle: usize);
}

/// Data type to determine the mac address
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct HermitNet {
	pub mtu: u16,
}

impl HermitNet {
	pub fn new(mtu: u16) -> Self {
		Self { mtu }
	}
}

impl NetworkInterface<HermitNet> {
	pub fn new() -> Option<Self> {
		let mtu = match unsafe { sys_get_mtu() } {
			Ok(mtu) => mtu,
			Err(_) => {
				return None;
			}
		};
		let device = HermitNet::new(mtu);
		#[cfg(feature = "trace")]
		let device = EthernetTracer::new(device, |_timestamp, printer| {
			trace!("{}", printer);
		});

		let mac: [u8; 6] = match unsafe { sys_get_mac_address() } {
			Ok(mac) => mac,
			Err(_) => {
				return None;
			}
		};
		let myip: Ipv4Addr = HERMIT_IP.parse().expect("Unable to parse IPv4 address");
		let myip = myip.octets();
		let mygw: Ipv4Addr = HERMIT_GATEWAY
			.parse()
			.expect("Unable to parse IPv4 address");
		let mygw = mygw.octets();
		let mymask: Ipv4Addr = HERMIT_MASK.parse().expect("Unable to parse IPv4 address");
		let mymask = mymask.octets();

		// calculate the netmask length
		// => count the number of contiguous 1 bits,
		// starting at the most significant bit in the first octet
		let mut prefix_len = (!mymask[0]).trailing_zeros();
		if prefix_len == 8 {
			prefix_len += (!mymask[1]).trailing_zeros();
		}
		if prefix_len == 16 {
			prefix_len += (!mymask[2]).trailing_zeros();
		}
		if prefix_len == 24 {
			prefix_len += (!mymask[3]).trailing_zeros();
		}

		let neighbor_cache = NeighborCache::new(BTreeMap::new());
		let ethernet_addr = EthernetAddress([mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]]);
		let ip_addrs = [IpCidr::new(
			IpAddress::v4(myip[0], myip[1], myip[2], myip[3]),
			prefix_len.try_into().unwrap(),
		)];
		let default_v4_gw = Ipv4Address::new(mygw[0], mygw[1], mygw[2], mygw[3]);
		let mut routes = Routes::new(BTreeMap::new());
		routes.add_default_ipv4_route(default_v4_gw).unwrap();

		info!("MAC address {}", ethernet_addr);
		info!("Configure network interface with address {}", ip_addrs[0]);
		info!("Configure gateway with address {}", default_v4_gw);
		info!("MTU: {} bytes", mtu);

		let iface = EthernetInterfaceBuilder::new(device)
			.ethernet_addr(ethernet_addr)
			.neighbor_cache(neighbor_cache)
			.ip_addrs(ip_addrs)
			.routes(routes)
			.finalize();

		Some(Self {
			iface,
			sockets: SocketSet::new(vec![]),
			wait_for: BTreeMap::new(),
		})
	}
}

impl<'a> Device<'a> for HermitNet {
	type RxToken = RxToken;
	type TxToken = TxToken;

	fn capabilities(&self) -> DeviceCapabilities {
		let mut cap = DeviceCapabilities::default();
		cap.max_transmission_unit = self.mtu.into();
		cap
	}

	fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
		match unsafe { sys_receive_rx_buffer() } {
			Ok(buffer) => Some((RxToken::new(buffer), TxToken::new())),
			_ => None,
		}
	}

	fn transmit(&'a mut self) -> Option<Self::TxToken> {
		trace!("create TxToken to transfer data");
		Some(TxToken::new())
	}
}

#[doc(hidden)]
pub struct RxToken {
	buffer: &'static mut [u8],
}

impl RxToken {
	pub fn new(buffer: &'static mut [u8]) -> Self {
		Self { buffer }
	}
}

impl phy::RxToken for RxToken {
	#[allow(unused_mut)]
	fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> smoltcp::Result<R>
	where
		F: FnOnce(&mut [u8]) -> smoltcp::Result<R>,
	{
		let result = f(self.buffer);
		if unsafe { sys_rx_buffer_consumed().is_ok() } {
			result
		} else {
			Err(smoltcp::Error::Exhausted)
		}
	}
}

#[doc(hidden)]
pub struct TxToken;

impl TxToken {
	pub fn new() -> Self {
		Self {}
	}
}

impl phy::TxToken for TxToken {
	fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> smoltcp::Result<R>
	where
		F: FnOnce(&mut [u8]) -> smoltcp::Result<R>,
	{
		let (tx_buffer, handle) =
			unsafe { sys_get_tx_buffer(len).map_err(|_| smoltcp::Error::Exhausted)? };
		let tx_slice: &'static mut [u8] = unsafe { slice::from_raw_parts_mut(tx_buffer, len) };
		match f(tx_slice) {
			Ok(result) => {
				if unsafe { sys_send_tx_buffer(handle, len).is_ok() } {
					Ok(result)
				} else {
					Err(smoltcp::Error::Exhausted)
				}
			}
			Err(e) => {
				unsafe { sys_free_tx_buffer(handle) };
				Err(e)
			}
		}
	}
}
<commit_msg>PR #112 requires minor changes to the system interface<commit_after>include!(concat!(env!("OUT_DIR"), "/constants.rs"));

use std::collections::BTreeMap;
use std::convert::TryInto;
use std::net::Ipv4Addr;
use std::slice;

use smoltcp::iface::{EthernetInterfaceBuilder, NeighborCache, Routes};
#[cfg(feature = "trace")]
use smoltcp::phy::EthernetTracer;
use smoltcp::phy::{self, Device, DeviceCapabilities};
use smoltcp::socket::SocketSet;
use smoltcp::time::Instant;
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address};

use crate::net::NetworkInterface;

extern "Rust" {
	fn sys_get_mac_address() -> Result<[u8; 6], ()>;
	fn sys_get_mtu() -> Result<u16, ()>;
	fn sys_get_tx_buffer(len: usize) -> Result<(*mut u8, usize), ()>;
	fn sys_send_tx_buffer(handle: usize, len: usize) -> Result<(), ()>;
	fn sys_receive_rx_buffer() -> Result<(&'static mut [u8], usize), ()>;
	fn sys_rx_buffer_consumed(handle: usize) -> Result<(), ()>;
	fn sys_free_tx_buffer(handle: usize);
}

/// Data type to determine the mac address
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct HermitNet {
	pub mtu: u16,
}

impl HermitNet {
	pub fn new(mtu: u16) -> Self {
		Self { mtu }
	}
}

impl NetworkInterface<HermitNet> {
	pub fn new() -> Option<Self> {
		let mtu = match unsafe { sys_get_mtu() } {
			Ok(mtu) => mtu,
			Err(_) => {
				return None;
			}
		};
		let device = HermitNet::new(mtu);
		#[cfg(feature = "trace")]
		let device = EthernetTracer::new(device, |_timestamp, printer| {
			trace!("{}", printer);
		});

		let mac: [u8; 6] = match unsafe { sys_get_mac_address() } {
			Ok(mac) => mac,
			Err(_) => {
				return None;
			}
		};
		let myip: Ipv4Addr = HERMIT_IP.parse().expect("Unable to parse IPv4 address");
		let myip = myip.octets();
		let mygw: Ipv4Addr = HERMIT_GATEWAY
			.parse()
			.expect("Unable to parse IPv4 address");
		let mygw = mygw.octets();
		let mymask: Ipv4Addr = HERMIT_MASK.parse().expect("Unable to parse IPv4 address");
		let mymask = mymask.octets();

		// calculate the netmask length
		// => count the number of contiguous 1 bits,
		// starting at the most significant bit in the first octet
		let mut prefix_len = (!mymask[0]).trailing_zeros();
		if prefix_len == 8 {
			prefix_len += (!mymask[1]).trailing_zeros();
		}
		if prefix_len == 16 {
			prefix_len += (!mymask[2]).trailing_zeros();
		}
		if prefix_len == 24 {
			prefix_len += (!mymask[3]).trailing_zeros();
		}

		let neighbor_cache = NeighborCache::new(BTreeMap::new());
		let ethernet_addr = EthernetAddress([mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]]);
		let ip_addrs = [IpCidr::new(
			IpAddress::v4(myip[0], myip[1], myip[2], myip[3]),
			prefix_len.try_into().unwrap(),
		)];
		let default_v4_gw = Ipv4Address::new(mygw[0], mygw[1], mygw[2], mygw[3]);
		let mut routes = Routes::new(BTreeMap::new());
		routes.add_default_ipv4_route(default_v4_gw).unwrap();

		info!("MAC address {}", ethernet_addr);
		info!("Configure network interface with address {}", ip_addrs[0]);
		info!("Configure gateway with address {}", default_v4_gw);
		info!("MTU: {} bytes", mtu);

		let iface = EthernetInterfaceBuilder::new(device)
			.ethernet_addr(ethernet_addr)
			.neighbor_cache(neighbor_cache)
			.ip_addrs(ip_addrs)
			.routes(routes)
			.finalize();

		Some(Self {
			iface,
			sockets: SocketSet::new(vec![]),
			wait_for: BTreeMap::new(),
		})
	}
}

impl<'a> Device<'a> for HermitNet {
	type RxToken = RxToken;
	type TxToken = TxToken;

	fn capabilities(&self) -> DeviceCapabilities {
		let mut cap = DeviceCapabilities::default();
		cap.max_transmission_unit = self.mtu.into();
		cap
	}

	fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
		match unsafe { sys_receive_rx_buffer() } {
			Ok((buffer, handle)) => Some((RxToken::new(buffer, handle), TxToken::new())),
			_ => None,
		}
	}

	fn transmit(&'a mut self) -> Option<Self::TxToken> {
		trace!("create TxToken to transfer data");
		Some(TxToken::new())
	}
}

#[doc(hidden)]
pub struct RxToken {
	buffer: &'static mut [u8],
	handle: usize,
}

impl RxToken {
	pub fn new(buffer: &'static mut [u8], handle: usize) -> Self {
		Self { buffer, handle }
	}
}

impl phy::RxToken for RxToken {
	#[allow(unused_mut)]
	fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> smoltcp::Result<R>
	where
		F: FnOnce(&mut [u8]) -> smoltcp::Result<R>,
	{
		let result = f(self.buffer);
		if unsafe { sys_rx_buffer_consumed(self.handle).is_ok() } {
			result
		} else {
			Err(smoltcp::Error::Exhausted)
		}
	}
}

#[doc(hidden)]
pub struct TxToken;

impl TxToken {
	pub fn new() -> Self {
		Self {}
	}
}

impl phy::TxToken for TxToken {
	fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> smoltcp::Result<R>
	where
		F: FnOnce(&mut [u8]) -> smoltcp::Result<R>,
	{
		let (tx_buffer, handle) =
			unsafe { sys_get_tx_buffer(len).map_err(|_| smoltcp::Error::Exhausted)? };
		let tx_slice: &'static mut [u8] = unsafe { slice::from_raw_parts_mut(tx_buffer, len) };
		match f(tx_slice) {
			Ok(result) => {
				if unsafe { sys_send_tx_buffer(handle, len).is_ok() } {
					Ok(result)
				} else {
					Err(smoltcp::Error::Exhausted)
				}
			}
			Err(e) => {
				unsafe { sys_free_tx_buffer(handle) };
				Err(e)
			}
		}
	}
}
<|endoftext|>


<commit_before>pub struct Range {
    priv off: u16,
    priv len: u16
}

pub pure fn Range(off: uint, len: uint) -> Range {
    assert off <= u16::max_value as uint;
    assert len <= u16::max_value as uint;

    Range {
        off: off as u16,
        len: len as u16
    }
}

pub pure fn empty() -> Range { Range(0,0) }

enum RangeRelation {
    OverlapsBegin(/* overlap */ uint),
    OverlapsEnd(/* overlap */ uint),
    ContainedBy,
    Contains,
    Coincides,
    EntirelyBefore,
    EntirelyAfter
}

pub impl Range {
    pub pure fn begin() -> uint { self.off as uint }
    pub pure fn length() -> uint { self.len as uint }
    pub pure fn end() -> uint { (self.off as uint) + (self.len as uint) }

    pub pure fn eachi(cb: fn&(uint) -> bool) {
        do uint::range(self.off as uint,
                       (self.off as uint) + (self.len as uint)) |i| {
            cb(i)
        }
    }

    pub pure fn is_valid_for_string(s: &str) -> bool {
        self.begin() < s.len() && self.end() <= s.len() && self.length() <= s.len()
    }

    pub pure fn shift_by(i: int) -> Range {
        Range(((self.off as int) + i) as uint, self.len as uint)
    }

    pub pure fn extend_by(i: int) -> Range {
        Range(self.off as uint, ((self.len as int) + i) as uint)
    }

    pub pure fn adjust_by(off_i: int, len_i: int) -> Range {
        Range(((self.off as int) + off_i) as uint, ((self.len as int) + len_i) as uint)
    }

    /// Computes the relationship between two ranges (`self` and `other`),
    /// from the point of view of `self`. So, 'EntirelyBefore' means
    /// that the `self` range is entirely before `other` range.
    fn relation_to_range(&self, other: Range) -> RangeRelation {
        if other.begin() > self.end() {
            return EntirelyBefore;
        }
        if self.begin() > other.end() {
            return EntirelyAfter;
        }
        if self.begin() == other.begin() && self.end() == other.end() {
            return Coincides;
        }
        if self.begin() <= other.begin() && self.end() >= other.end() {
            return Contains;
        }
        if self.begin() >= other.begin() && self.end() <= other.end() {
            return ContainedBy;
        }
        if self.begin() < other.begin() && self.end() < other.end() {
            let overlap = self.end() - other.begin();
            return OverlapsBegin(overlap);
        }
        if self.begin() > other.begin() && self.end() > other.end() {
            let overlap = other.end() - self.begin();
            return OverlapsEnd(overlap);
        }
        fail fmt!("relation_to_range(): didn't classify self=%?, other=%?",
                  self, other);
    }

    fn repair_after_coalesced_range(&self, other: Range) -> Range {
        let relation = self.relation_to_range(other);
        debug!("repair_after_coalesced_range: possibly repairing range %?", self);
        debug!("repair_after_coalesced_range: relation of original range and coalesced range(%?): %?",
               other, relation);
        let new_range = match relation {
            EntirelyBefore => { *self },
            EntirelyAfter =>  { self.shift_by(-(other.length() as int)) },
            Coincides | ContainedBy =>   { Range(other.begin(), 1) },
            Contains =>      { self.extend_by(-(other.length() as int)) },
            OverlapsBegin(overlap) => { self.extend_by(1 - (overlap as int)) },
            OverlapsEnd(overlap) =>
            { Range(other.begin(), self.length() - overlap + 1) }
        };
        debug!("repair_after_coalesced_range: new range: ---- %?", new_range);
        new_range
    }
}

pub pure fn empty_mut() -> MutableRange { MutableRange::new(0, 0) }

pub struct MutableRange {
    priv off: uint,
    priv len: uint
}

pub impl MutableRange {
    static pub pure fn new(off: uint, len: uint) -> MutableRange {
        MutableRange { off: off, len: len }
    }

    static pub pure fn empty() -> MutableRange {
        MutableRange::new(0, 0)
    }
}

pub impl MutableRange {
    pure fn begin(&const self) -> uint { self.off  }
    pure fn length(&const self) -> uint { self.len }
    pure fn end(&const self) -> uint { self.off + self.len }
    pure fn eachi(&const self, cb: fn&(uint) -> bool) {
        do uint::range(self.off, self.off + self.len) |i| { cb(i) }
    }

    pure fn contains(&const self, i: uint) -> bool {
        i >= self.begin() && i < self.end()
    }

    fn relation_to_range(&const self, other: &MutableRange) -> RangeRelation {
        self.as_immutable().relation_to_range(other.as_immutable())
    }

    pure fn as_immutable(&const self) -> Range {
        Range(self.begin(), self.length())
    }

    pure fn is_valid_for_string(&const self, s: &str) -> bool {
        self.begin() < s.len() && self.end() <= s.len() && self.length() <= s.len()
    }

    fn shift_by(&mut self, i: int) {
        self.off = ((self.off as int) + i) as uint;
    }

    fn extend_by(&mut self, i: int) {
        self.len = ((self.len as int) + i) as uint;
    }

    fn extend_to(&mut self, i: uint) {
        self.len = i - self.off;
    }

    fn adjust_by(&mut self, off_i: int, len_i: int) {
        self.off = ((self.off as int) + off_i) as uint;
        self.len = ((self.len as int) + len_i) as uint;
    }

    fn reset(&mut self, off_i: uint, len_i: uint) {
        self.off = off_i;
        self.len = len_i;
    }
}
<commit_msg>Move Range::relation_to_range<commit_after>pub struct Range {
    priv off: u16,
    priv len: u16
}

pub pure fn Range(off: uint, len: uint) -> Range {
    assert off <= u16::max_value as uint;
    assert len <= u16::max_value as uint;

    Range {
        off: off as u16,
        len: len as u16
    }
}

pub pure fn empty() -> Range { Range(0,0) }

enum RangeRelation {
    OverlapsBegin(/* overlap */ uint),
    OverlapsEnd(/* overlap */ uint),
    ContainedBy,
    Contains,
    Coincides,
    EntirelyBefore,
    EntirelyAfter
}

pub impl Range {
    pub pure fn begin() -> uint { self.off as uint }
    pub pure fn length() -> uint { self.len as uint }
    pub pure fn end() -> uint { (self.off as uint) + (self.len as uint) }

    pub pure fn eachi(cb: fn&(uint) -> bool) {
        do uint::range(self.off as uint,
                       (self.off as uint) + (self.len as uint)) |i| {
            cb(i)
        }
    }

    pub pure fn is_valid_for_string(s: &str) -> bool {
        self.begin() < s.len() && self.end() <= s.len() && self.length() <= s.len()
    }

    pub pure fn shift_by(i: int) -> Range {
        Range(((self.off as int) + i) as uint, self.len as uint)
    }

    pub pure fn extend_by(i: int) -> Range {
        Range(self.off as uint, ((self.len as int) + i) as uint)
    }

    pub pure fn adjust_by(off_i: int, len_i: int) -> Range {
        Range(((self.off as int) + off_i) as uint, ((self.len as int) + len_i) as uint)
    }
}

pub pure fn empty_mut() -> MutableRange { MutableRange::new(0, 0) }

pub struct MutableRange {
    priv off: uint,
    priv len: uint
}

pub impl MutableRange {
    static pub pure fn new(off: uint, len: uint) -> MutableRange {
        MutableRange { off: off, len: len }
    }

    static pub pure fn empty() -> MutableRange {
        MutableRange::new(0, 0)
    }
}

pub impl MutableRange {
    pure fn begin(&const self) -> uint { self.off  }
    pure fn length(&const self) -> uint { self.len }
    pure fn end(&const self) -> uint { self.off + self.len }
    pure fn eachi(&const self, cb: fn&(uint) -> bool) {
        do uint::range(self.off, self.off + self.len) |i| { cb(i) }
    }

    pure fn contains(&const self, i: uint) -> bool {
        i >= self.begin() && i < self.end()
    }

    pure fn as_immutable(&const self) -> Range {
        Range(self.begin(), self.length())
    }

    pure fn is_valid_for_string(&const self, s: &str) -> bool {
        self.begin() < s.len() && self.end() <= s.len() && self.length() <= s.len()
    }

    fn shift_by(&mut self, i: int) {
        self.off = ((self.off as int) + i) as uint;
    }

    fn extend_by(&mut self, i: int) {
        self.len = ((self.len as int) + i) as uint;
    }

    fn extend_to(&mut self, i: uint) {
        self.len = i - self.off;
    }

    fn adjust_by(&mut self, off_i: int, len_i: int) {
        self.off = ((self.off as int) + off_i) as uint;
        self.len = ((self.len as int) + len_i) as uint;
    }

    fn reset(&mut self, off_i: uint, len_i: uint) {
        self.off = off_i;
        self.len = len_i;
    }

    /// Computes the relationship between two ranges (`self` and `other`),
    /// from the point of view of `self`. So, 'EntirelyBefore' means
    /// that the `self` range is entirely before `other` range.
    pure fn relation_to_range(&const self, other: &const MutableRange) -> RangeRelation {
        if other.begin() > self.end() {
            return EntirelyBefore;
        }
        if self.begin() > other.end() {
            return EntirelyAfter;
        }
        if self.begin() == other.begin() && self.end() == other.end() {
            return Coincides;
        }
        if self.begin() <= other.begin() && self.end() >= other.end() {
            return Contains;
        }
        if self.begin() >= other.begin() && self.end() <= other.end() {
            return ContainedBy;
        }
        if self.begin() < other.begin() && self.end() < other.end() {
            let overlap = self.end() - other.begin();
            return OverlapsBegin(overlap);
        }
        if self.begin() > other.begin() && self.end() > other.end() {
            let overlap = other.end() - self.begin();
            return OverlapsEnd(overlap);
        }
        fail fmt!("relation_to_range(): didn't classify self=%?, other=%?",
                  self, other);
    }

    fn repair_after_coalesced_range(&mut self, other: &const MutableRange) {
        let relation = self.relation_to_range(other);
        debug!("repair_after_coalesced_range: possibly repairing range %?", self);
        debug!("repair_after_coalesced_range: relation of original range and coalesced range(%?): %?",
               other, relation);
        match relation {
            EntirelyBefore => { },
            EntirelyAfter =>  { self.shift_by(-(other.length() as int)); },
            Coincides | ContainedBy =>   { self.reset(other.begin(), 1); },
            Contains =>      { self.extend_by(-(other.length() as int)); },
            OverlapsBegin(overlap) => { self.extend_by(1 - (overlap as int)); },
            OverlapsEnd(overlap) =>
            { self.reset(other.begin(), self.length() - overlap + 1); }
        };
        debug!("repair_after_coalesced_range: new range: ---- %?", self);
    }
}
<|endoftext|>


<commit_before>use ffi::*;
use element::Element;
use element::ElementT;
use util::*;

/**
GstBin is an element that can contain other GstElement, allowing them to be managed as a group. Pads from the child elements can be ghosted to the bin, see GstGhostPad. This makes the bin look like any other elements and enables creation of higher-level abstraction elements.

A new GstBin is created with gst_bin_new(). Use a GstPipeline instead if you want to create a toplevel bin because a normal bin doesn't have a bus or handle clock distribution of its own.

After the bin has been created you will typically add elements to it with gst_bin_add(). You can remove elements with gst_bin_remove().

An element can be retrieved from a bin with gst_bin_get_by_name(), using the elements name. gst_bin_get_by_name_recurse_up() is mainly used for internal purposes and will query the parent bins when the element is not found in the current bin.

An iterator of elements in a bin can be retrieved with gst_bin_iterate_elements(). Various other iterators exist to retrieve the elements in a bin.

gst_object_unref() is used to drop your reference to the bin.

The “element-added” signal is fired whenever a new element is added to the bin. Likewise the “element-removed” signal is fired whenever an element is removed from the bin.
Notes

A GstBin internally intercepts every GstMessage posted by its children and implements the following default behaviour for each of them:

GST_MESSAGE_EOS

This message is only posted by sinks in the PLAYING state. If all sinks posted the EOS message, this bin will post and EOS message upwards.

GST_MESSAGE_SEGMENT_START

just collected and never forwarded upwards. The messages are used to decide when all elements have completed playback of their segment.

GST_MESSAGE_SEGMENT_DONE

Is posted by GstBin when all elements that posted a SEGMENT_START have posted a SEGMENT_DONE.

GST_MESSAGE_DURATION_CHANGED

Is posted by an element that detected a change in the stream duration. The default bin behaviour is to clear any cached duration values so that the next duration query will perform a full duration recalculation. The duration change is posted to the application so that it can refetch the new duration with a duration query. Note that these messages can be posted before the bin is prerolled, in which case the duration query might fail.

GST_MESSAGE_CLOCK_LOST

This message is posted by an element when it can no longer provide a clock. The default bin behaviour is to check if the lost clock was the one provided by the bin. If so and the bin is currently in the PLAYING state, the message is forwarded to the bin parent. This message is also generated when a clock provider is removed from the bin. If this message is received by the application, it should PAUSE the pipeline and set it back to PLAYING to force a new clock distribution.

GST_MESSAGE_CLOCK_PROVIDE

This message is generated when an element can provide a clock. This mostly happens when a new clock provider is added to the bin. The default behaviour of the bin is to mark the currently selected clock as dirty, which will perform a clock recalculation the next time the bin is asked to provide a clock. This message is never sent tot the application but is forwarded to the parent of the bin.

OTHERS

posted upwards.

A GstBin implements the following default behaviour for answering to a GstQuery:

GST_QUERY_DURATION

If the query has been asked before with the same format and the bin is a toplevel bin (ie. has no parent), use the cached previous value. If no previous value was cached, the query is sent to all sink elements in the bin and the MAXIMUM of all values is returned. If the bin is a toplevel bin the value is cached. If no sinks are available in the bin, the query fails.

GST_QUERY_POSITION

The query is sent to all sink elements in the bin and the MAXIMUM of all values is returned. If no sinks are available in the bin, the query fails.

OTHERS

the query is forwarded to all sink elements, the result of the first sink that answers the query successfully is returned. If no sink is in the bin, the query fails.

A GstBin will by default forward any event sent to it to all sink elements. If all the sinks return TRUE, the bin will also return TRUE, else FALSE is returned. If no sinks are in the bin, the event handler will return TRUE.*/
pub struct Bin{
    bin: Element
}

unsafe impl Sync for Bin {}
unsafe impl Send for Bin {}

impl Bin{
    /// Creates a new bin with the given name.
    pub fn new(name: &str) -> Option<Bin>{
        unsafe{
            let cname = CString::new(name).unwrap();
            let name = if name != "" {
                cname.as_ptr()
            } else {
                ptr::null()
            };
            let bin = gst_bin_new(name);
            if bin != ptr::null_mut(){
	            gst_object_ref_sink(mem::transmute(bin));
	            Bin::new_from_gst_bin(bin as *mut GstBin)
	        }else{
	            None
	        }
        }
    }

    /// Creates a new bin from an already existing raw pointer to a GstBin.
    /// The passed element has to be fully referenced
    pub unsafe fn new_from_gst_bin(element: *mut GstBin) -> Option<Bin>{
        match Element::new_from_gst_element(element as *mut GstElement){
            Some(element) => Some( Bin{ bin: element } ),
            None => None
        }
    }
}

pub trait BinT: ElementT{
    fn as_bin(&self) -> &Bin;
    fn as_bin_mut(&mut self) -> &mut Bin;

    fn to_bin(&self) -> Bin{
        Bin{bin: self.to_element()}
    }

    /// Adds the given element to the bin. Sets the element's parent,
    /// and thus adds a reference.
    ///
    /// If the element's pads are linked to other pads, the pads will
    /// be unlinked before the element is added to the bin.
    ///
    /// > When you add an element to an already-running pipeline, you
    /// > will have to take care to set the state of the newly-added
    /// > element to the desired state (usually PLAYING or PAUSED, same
    /// > you set the pipeline to originally) with Element::set_state(),
    /// > or use gst_element_sync_state_with_parent(). The bin or pipeline
    /// > will not take care of this for you.
    fn add<E:ElementT>(&mut self, element: E) -> bool{
        unsafe{
            gst_bin_add(self.gst_bin_mut(), element.transfer() as *mut GstElement) == 1
        }
    }

    /// Remove the element from its associated bin.
    ///
    /// If the element's pads are linked to other pads, the pads will be
    /// unlinked before the element is removed from the bin.
    fn remove(&mut self, element: &ElementT) -> bool{
        unsafe{
            gst_bin_remove(self.gst_bin_mut(), mem::transmute(element.gst_element())) == 1
        }
    }

    /// Get the element with the given name from this bin.
    ///
    /// Returns None if no element with the given name is found in the bin.
    fn get_by_name(&self, name: &str) -> Option<Element>{
        let cname = CString::new(name).unwrap();
        unsafe{
            let element = gst_bin_get_by_name(self.gst_bin() as *mut GstBin, cname.as_ptr());
            Element::new_from_gst_element(element)
        }
    }

    /// Query bin for the current latency using and reconfigures this latency
    /// to all the elements with a LATENCY event.
	///
	/// This method is typically called on the pipeline when a
	/// GST_MESSAGE_LATENCY is posted on the bus.
	///
	/// This function simply emits the 'do-latency' signal so any custom
	/// latency calculations will be performed.
    fn recalculate_latency(&mut self) -> bool{
        unsafe{
            gst_bin_recalculate_latency(self.gst_bin() as *mut GstBin) == 1
        }
    }

    /// If set to true, the bin will handle asynchronous state changes.
    /// This should be used only if the bin subclass is modifying the state
    /// of its children on its own
    fn set_async_handling(&mut self, async: bool){
        self.as_bin_mut().set("async-handling", async);
    }

    /// Forward all children messages, even those that would normally be
    /// filtered by the bin. This can be interesting when one wants to be
    /// notified of the EOS state of individual elements, for example.
	///
	/// The messages are converted to an ELEMENT message with the bin as the
	/// source. The structure of the message is named 'GstBinForwarded' and
	/// contains a field named 'message' of type GST_TYPE_MESSAGE that
	/// contains the original forwarded message.
    fn set_message_forward(&mut self, forward: bool){
        self.as_bin_mut().set("message-forward", forward);
    }

    /// Returns a const raw pointer to the internal GstElement
    unsafe fn gst_bin(&self) -> *const GstBin{
        self.as_bin().gst_bin()
    }

    /// Returns a mut raw pointer to the internal GstElement
    unsafe fn gst_bin_mut(&mut self) -> *mut GstBin{
        self.as_bin_mut().gst_bin_mut()
    }
}

impl BinT for Bin{
    fn as_bin(&self) -> &Bin{
        self
    }

    fn as_bin_mut(&mut self) -> &mut Bin{
        self
    }

    unsafe fn gst_bin(&self) -> *const GstBin{
        self.bin.gst_element() as *const GstBin
    }

    unsafe fn gst_bin_mut(&mut self) -> *mut GstBin{
        self.bin.gst_element() as *mut GstBin
    }
}

impl<B:BinT> ElementT for B{
    fn as_element(&self) -> &Element{
        &self.as_bin().bin
    }

    fn as_element_mut(&mut self) -> &mut Element{
        &mut self.as_bin_mut().bin
    }
}

impl ::Transfer for Bin{
    unsafe fn transfer(self) -> *mut GstElement{
        self.bin.transfer()
    }
}
<commit_msg>add_and_link: allows to add 2 elements and link them<commit_after>use ffi::*;
use element::Element;
use element::ElementT;
use util::*;

/**
GstBin is an element that can contain other GstElement, allowing them to be managed as a group. Pads from the child elements can be ghosted to the bin, see GstGhostPad. This makes the bin look like any other elements and enables creation of higher-level abstraction elements.

A new GstBin is created with gst_bin_new(). Use a GstPipeline instead if you want to create a toplevel bin because a normal bin doesn't have a bus or handle clock distribution of its own.

After the bin has been created you will typically add elements to it with gst_bin_add(). You can remove elements with gst_bin_remove().

An element can be retrieved from a bin with gst_bin_get_by_name(), using the elements name. gst_bin_get_by_name_recurse_up() is mainly used for internal purposes and will query the parent bins when the element is not found in the current bin.

An iterator of elements in a bin can be retrieved with gst_bin_iterate_elements(). Various other iterators exist to retrieve the elements in a bin.

gst_object_unref() is used to drop your reference to the bin.

The “element-added” signal is fired whenever a new element is added to the bin. Likewise the “element-removed” signal is fired whenever an element is removed from the bin.
Notes

A GstBin internally intercepts every GstMessage posted by its children and implements the following default behaviour for each of them:

GST_MESSAGE_EOS

This message is only posted by sinks in the PLAYING state. If all sinks posted the EOS message, this bin will post and EOS message upwards.

GST_MESSAGE_SEGMENT_START

just collected and never forwarded upwards. The messages are used to decide when all elements have completed playback of their segment.

GST_MESSAGE_SEGMENT_DONE

Is posted by GstBin when all elements that posted a SEGMENT_START have posted a SEGMENT_DONE.

GST_MESSAGE_DURATION_CHANGED

Is posted by an element that detected a change in the stream duration. The default bin behaviour is to clear any cached duration values so that the next duration query will perform a full duration recalculation. The duration change is posted to the application so that it can refetch the new duration with a duration query. Note that these messages can be posted before the bin is prerolled, in which case the duration query might fail.

GST_MESSAGE_CLOCK_LOST

This message is posted by an element when it can no longer provide a clock. The default bin behaviour is to check if the lost clock was the one provided by the bin. If so and the bin is currently in the PLAYING state, the message is forwarded to the bin parent. This message is also generated when a clock provider is removed from the bin. If this message is received by the application, it should PAUSE the pipeline and set it back to PLAYING to force a new clock distribution.

GST_MESSAGE_CLOCK_PROVIDE

This message is generated when an element can provide a clock. This mostly happens when a new clock provider is added to the bin. The default behaviour of the bin is to mark the currently selected clock as dirty, which will perform a clock recalculation the next time the bin is asked to provide a clock. This message is never sent tot the application but is forwarded to the parent of the bin.

OTHERS

posted upwards.

A GstBin implements the following default behaviour for answering to a GstQuery:

GST_QUERY_DURATION

If the query has been asked before with the same format and the bin is a toplevel bin (ie. has no parent), use the cached previous value. If no previous value was cached, the query is sent to all sink elements in the bin and the MAXIMUM of all values is returned. If the bin is a toplevel bin the value is cached. If no sinks are available in the bin, the query fails.

GST_QUERY_POSITION

The query is sent to all sink elements in the bin and the MAXIMUM of all values is returned. If no sinks are available in the bin, the query fails.

OTHERS

the query is forwarded to all sink elements, the result of the first sink that answers the query successfully is returned. If no sink is in the bin, the query fails.

A GstBin will by default forward any event sent to it to all sink elements. If all the sinks return TRUE, the bin will also return TRUE, else FALSE is returned. If no sinks are in the bin, the event handler will return TRUE.*/
pub struct Bin{
    bin: Element
}

unsafe impl Sync for Bin {}
unsafe impl Send for Bin {}

impl Bin{
    /// Creates a new bin with the given name.
    pub fn new(name: &str) -> Option<Bin>{
        unsafe{
            let cname = CString::new(name).unwrap();
            let name = if name != "" {
                cname.as_ptr()
            } else {
                ptr::null()
            };
            let bin = gst_bin_new(name);
            if bin != ptr::null_mut(){
	            gst_object_ref_sink(mem::transmute(bin));
	            Bin::new_from_gst_bin(bin as *mut GstBin)
	        }else{
	            None
	        }
        }
    }

    /// Creates a new bin from an already existing raw pointer to a GstBin.
    /// The passed element has to be fully referenced
    pub unsafe fn new_from_gst_bin(element: *mut GstBin) -> Option<Bin>{
        match Element::new_from_gst_element(element as *mut GstElement){
            Some(element) => Some( Bin{ bin: element } ),
            None => None
        }
    }
}

pub trait BinT: ElementT{
    fn as_bin(&self) -> &Bin;
    fn as_bin_mut(&mut self) -> &mut Bin;

    fn to_bin(&self) -> Bin{
        Bin{bin: self.to_element()}
    }

    /// Adds the given element to the bin. Sets the element's parent,
    /// and thus adds a reference.
    ///
    /// If the element's pads are linked to other pads, the pads will
    /// be unlinked before the element is added to the bin.
    ///
    /// > When you add an element to an already-running pipeline, you
    /// > will have to take care to set the state of the newly-added
    /// > element to the desired state (usually PLAYING or PAUSED, same
    /// > you set the pipeline to originally) with Element::set_state(),
    /// > or use gst_element_sync_state_with_parent(). The bin or pipeline
    /// > will not take care of this for you.
    fn add<E:ElementT>(&mut self, element: E) -> bool{
        unsafe{
            gst_bin_add(self.gst_bin_mut(), element.transfer() as *mut GstElement) == 1
        }
    }

    fn add_and_link<E:ElementT>(&mut self, mut src: E, mut sink: E) -> bool{
        self.add(src.to_element()) &&
        self.add(sink.to_element()) &&
        src.link(&mut sink)
    }

    /// Remove the element from its associated bin.
    ///
    /// If the element's pads are linked to other pads, the pads will be
    /// unlinked before the element is removed from the bin.
    fn remove(&mut self, element: &ElementT) -> bool{
        unsafe{
            gst_bin_remove(self.gst_bin_mut(), mem::transmute(element.gst_element())) == 1
        }
    }

    /// Get the element with the given name from this bin.
    ///
    /// Returns None if no element with the given name is found in the bin.
    fn get_by_name(&self, name: &str) -> Option<Element>{
        let cname = CString::new(name).unwrap();
        unsafe{
            let element = gst_bin_get_by_name(self.gst_bin() as *mut GstBin, cname.as_ptr());
            Element::new_from_gst_element(element)
        }
    }

    /// Query bin for the current latency using and reconfigures this latency
    /// to all the elements with a LATENCY event.
	///
	/// This method is typically called on the pipeline when a
	/// GST_MESSAGE_LATENCY is posted on the bus.
	///
	/// This function simply emits the 'do-latency' signal so any custom
	/// latency calculations will be performed.
    fn recalculate_latency(&mut self) -> bool{
        unsafe{
            gst_bin_recalculate_latency(self.gst_bin() as *mut GstBin) == 1
        }
    }

    /// If set to true, the bin will handle asynchronous state changes.
    /// This should be used only if the bin subclass is modifying the state
    /// of its children on its own
    fn set_async_handling(&mut self, async: bool){
        self.as_bin_mut().set("async-handling", async);
    }

    /// Forward all children messages, even those that would normally be
    /// filtered by the bin. This can be interesting when one wants to be
    /// notified of the EOS state of individual elements, for example.
	///
	/// The messages are converted to an ELEMENT message with the bin as the
	/// source. The structure of the message is named 'GstBinForwarded' and
	/// contains a field named 'message' of type GST_TYPE_MESSAGE that
	/// contains the original forwarded message.
    fn set_message_forward(&mut self, forward: bool){
        self.as_bin_mut().set("message-forward", forward);
    }

    /// Returns a const raw pointer to the internal GstElement
    unsafe fn gst_bin(&self) -> *const GstBin{
        self.as_bin().gst_bin()
    }

    /// Returns a mut raw pointer to the internal GstElement
    unsafe fn gst_bin_mut(&mut self) -> *mut GstBin{
        self.as_bin_mut().gst_bin_mut()
    }
}

impl BinT for Bin{
    fn as_bin(&self) -> &Bin{
        self
    }

    fn as_bin_mut(&mut self) -> &mut Bin{
        self
    }

    unsafe fn gst_bin(&self) -> *const GstBin{
        self.bin.gst_element() as *const GstBin
    }

    unsafe fn gst_bin_mut(&mut self) -> *mut GstBin{
        self.bin.gst_element() as *mut GstBin
    }
}

impl<B:BinT> ElementT for B{
    fn as_element(&self) -> &Element{
        &self.as_bin().bin
    }

    fn as_element_mut(&mut self) -> &mut Element{
        &mut self.as_bin_mut().bin
    }
}

impl ::Transfer for Bin{
    unsafe fn transfer(self) -> *mut GstElement{
        self.bin.transfer()
    }
}
<|endoftext|>


<commit_before>
use std::io::{BufRead,ErrorKind,Result,Write};

/// This trait extends any type that implements BufRead with a
/// stream_until_token() function.
pub trait BufReadPlus: BufRead {
    /// Stream all bytes to out until the `token` delimiter is reached.
    ///
    /// This function will continue to read (and stream) bytes from the
    /// underlying stream until the token or EOF is found. Once found, all
    /// bytes up to the token (if found) will have been streamed to `out` and
    /// this input stream will advance past the token (the token will be
    /// discarded).
    ///
    /// This function will return `Ok(n)` where `n` is the number of bytes
    /// which were read, counting the token if it was found.  If the token was
    /// not found, it will still return `Ok(n)`
    ///
    /// # Errors
    ///
    /// This function will ignore all instances of `ErrorKind::Interrupted` and
    /// will otherwise return any errors returned by `fill_buf`.
    fn stream_until_token<W: Write>(&mut self, token: &[u8], out: &mut W) -> Result<usize> {
        stream_until_token(self, token, out)
    }
}

// Implement BufReadPlus for everything that implements BufRead
impl<T: BufRead> BufReadPlus for T {}

fn stream_until_token<R: BufRead + ?Sized, W: Write>(r: &mut R, token: &[u8], mut out: &mut W)
                                                     -> Result<usize> {
    let mut read = 0;
    // Partial represents the size of a token prefix found at the end of a buffer,
    // usually 0.  If not zero, the beginning of the next buffer is checked for the
    // suffix to find matches that straddle two buffers
    let mut partial: usize = 0;
    loop {
        let (done,used) = {
            let available = match r.fill_buf() {
                Ok(n) => n,
                Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
                Err(e) => return Err(e)
            };
            // If last buffer ended in a token prefix, check if this one starts with the
            // matching suffix
            if partial > 0 && available[..token.len() - partial] == token[partial..] {
                (true, token.len() - partial)
            }
            else {
                if partial > 0 {
                    // Last buffer ended in a token prefix, but it didn't pan out, so
                    // we need to push it along
                    try!( out.write_all(&token[..partial]) );
                }
                // Search for the token
                match available
                    .windows(token.len())
                    .enumerate()
                    .filter(|&(_,w)| { w == token })
                    .map(|(i,_)| { i })
                    .next()
                {
                    Some(i) => {
                        try!( out.write_all(&available[..i]) );
                        (true, i + token.len())
                    },
                    None => {
                        // Check for partial matches at the end of the buffer
                        partial = if available.len() > token.len() - 1 {
                            match (1..(token.len()-1))
                                .rev()
                                .filter(|&width| {
                                    token[..width] == available[available.len() - width..]
                                })
                                .next()
                            {
                                Some(width) => width,
                                None => 0
                            }
                        } else { 0 };
                        // Push all except the partial token at the end (if any)
                        try!( out.write_all(&available[..available.len()-partial]) );
                        (false, available.len()) // But mark it all consumed
                    }
                }
            }
        };
        r.consume(used);
        read += used;
        if done || used == 0 {
            return Ok(read);
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::{Cursor,BufReader};
    use super::BufReadPlus;

    #[test]
    fn stream_until_token() {
        let mut buf = Cursor::new(&b"123456"[..]);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"78", &mut v).unwrap(), 6);
        assert_eq!(v, b"123456");
        let mut buf = Cursor::new(&b"12345678"[..]);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"34", &mut v).unwrap(), 4);
        assert_eq!(v, b"12");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"78", &mut v).unwrap(), 4);
        assert_eq!(v, b"56");

        let mut buf = Cursor::new(&b"bananas for nana"[..]);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"nan", &mut v).unwrap(), 5);
        assert_eq!(v, b"ba");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut v).unwrap(), 10);
        assert_eq!(v, b"as for ");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut v).unwrap(), 1);
        assert_eq!(v, b"a");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut v).unwrap(), 0);
        assert_eq!(v, b"");
    }

    #[test]
    fn stream_until_token_straddle_test() {
        let cursor = Cursor::new(&b"12345TOKEN345678"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut v).unwrap(), 10);
        assert_eq!(v, b"12345");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut v).unwrap(), 6);
        assert_eq!(v, b"345678");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut v).unwrap(), 0);
        assert_eq!(v, b"");

        let cursor = Cursor::new(&b"12345TOKE23456781TOKEN78"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut v).unwrap(), 22);
        assert_eq!(v, b"12345TOKE23456781");
    }
}
<commit_msg>minor: rename a variable 'done' to 'found'<commit_after>
use std::io::{BufRead,ErrorKind,Result,Write};

/// This trait extends any type that implements BufRead with a
/// stream_until_token() function.
pub trait BufReadPlus: BufRead {
    /// Stream all bytes to out until the `token` delimiter is reached.
    ///
    /// This function will continue to read (and stream) bytes from the
    /// underlying stream until the token or EOF is found. Once found, all
    /// bytes up to the token (if found) will have been streamed to `out` and
    /// this input stream will advance past the token (the token will be
    /// discarded).
    ///
    /// This function will return `Ok(n)` where `n` is the number of bytes
    /// which were read, counting the token if it was found.  If the token was
    /// not found, it will still return `Ok(n)`
    ///
    /// # Errors
    ///
    /// This function will ignore all instances of `ErrorKind::Interrupted` and
    /// will otherwise return any errors returned by `fill_buf`.
    fn stream_until_token<W: Write>(&mut self, token: &[u8], out: &mut W) -> Result<usize> {
        stream_until_token(self, token, out)
    }
}

// Implement BufReadPlus for everything that implements BufRead
impl<T: BufRead> BufReadPlus for T {}

fn stream_until_token<R: BufRead + ?Sized, W: Write>(r: &mut R, token: &[u8], mut out: &mut W)
                                                     -> Result<usize> {
    let mut read = 0;

    // Partial represents the size of a token prefix found at the end of a buffer,
    // usually 0.  If not zero, the beginning of the next buffer is checked for the
    // suffix to find matches that straddle two buffers
    let mut partial: usize = 0;

    loop {
        let (found,used) = {
            let available = match r.fill_buf() {
                Ok(n) => n,
                Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
                Err(e) => return Err(e)
            };
            // If last buffer ended in a token prefix, check if this one starts with the
            // matching suffix
            if partial > 0 && available[..token.len() - partial] == token[partial..] {
                (true, token.len() - partial)
            }
            else {
                if partial > 0 {
                    // Last buffer ended in a token prefix, but it didn't pan out, so
                    // we need to push it along
                    try!( out.write_all(&token[..partial]) );
                }
                // Search for the token
                match available
                    .windows(token.len())
                    .enumerate()
                    .filter(|&(_,w)| { w == token })
                    .map(|(i,_)| { i })
                    .next()
                {
                    Some(i) => {
                        try!( out.write_all(&available[..i]) );
                        (true, i + token.len())
                    },
                    None => {
                        // Check for partial matches at the end of the buffer
                        partial = if available.len() > token.len() - 1 {
                            match (1..(token.len()-1))
                                .rev()
                                .filter(|&width| {
                                    token[..width] == available[available.len() - width..]
                                })
                                .next()
                            {
                                Some(width) => width,
                                None => 0
                            }
                        } else { 0 };
                        // Push all except the partial token at the end (if any)
                        try!( out.write_all(&available[..available.len()-partial]) );
                        (false, available.len()) // But mark it all consumed
                    }
                }
            }
        };
        r.consume(used);
        read += used;
        if found || used == 0 {
            return Ok(read);
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::{Cursor,BufReader};
    use super::BufReadPlus;

    #[test]
    fn stream_until_token() {
        let mut buf = Cursor::new(&b"123456"[..]);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"78", &mut v).unwrap(), 6);
        assert_eq!(v, b"123456");
        let mut buf = Cursor::new(&b"12345678"[..]);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"34", &mut v).unwrap(), 4);
        assert_eq!(v, b"12");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"78", &mut v).unwrap(), 4);
        assert_eq!(v, b"56");

        let mut buf = Cursor::new(&b"bananas for nana"[..]);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"nan", &mut v).unwrap(), 5);
        assert_eq!(v, b"ba");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut v).unwrap(), 10);
        assert_eq!(v, b"as for ");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut v).unwrap(), 1);
        assert_eq!(v, b"a");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut v).unwrap(), 0);
        assert_eq!(v, b"");
    }

    #[test]
    fn stream_until_token_straddle_test() {
        let cursor = Cursor::new(&b"12345TOKEN345678"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut v).unwrap(), 10);
        assert_eq!(v, b"12345");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut v).unwrap(), 6);
        assert_eq!(v, b"345678");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut v).unwrap(), 0);
        assert_eq!(v, b"");

        let cursor = Cursor::new(&b"12345TOKE23456781TOKEN78"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut v).unwrap(), 22);
        assert_eq!(v, b"12345TOKE23456781");
    }
}
<|endoftext|>