<commit_before>use std::io::Write;
use std::result::Result as StdResult;
use std::fmt::Display;
use std::borrow::Cow;
use std::mem::replace;
use {Image, Run, Time, TimeSpan, base64};
use time::formatter::{Complete, TimeFormatter};
use chrono::{DateTime, Utc};
use byteorder::{WriteBytesExt, LE};
use quick_xml::Writer;
use quick_xml::events::{BytesDecl, BytesEnd, BytesStart, BytesText, Event};
use quick_xml::errors::Error as XmlError;

static LSS_IMAGE_HEADER: &[u8; 156] = include_bytes!("lss_image_header.bin");

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Xml(err: XmlError) {
            from()
        }
    }
}

pub type Result<T> = StdResult<T, Error>;

fn new_tag(name: &[u8]) -> BytesStart {
    BytesStart::borrowed(name, name.len())
}

fn write_start<W: Write>(writer: &mut Writer<W>, tag: BytesStart) -> Result<()> {
    writer.write_event(Event::Start(tag))?;
    Ok(())
}

fn write_end<W: Write>(writer: &mut Writer<W>, tag: &[u8]) -> Result<()> {
    writer.write_event(Event::End(BytesEnd::borrowed(tag)))?;
    Ok(())
}

fn split_tag<'a>(tag: &'a BytesStart<'a>) -> (BytesStart<'a>, BytesEnd<'a>) {
    (
        BytesStart::borrowed(&tag, tag.name().len()),
        BytesEnd::borrowed(tag.name()),
    )
}

fn bool(value: bool) -> &'static [u8] {
    if value {
        b"True"
    } else {
        b"False"
    }
}

fn scoped<W, F>(writer: &mut Writer<W>, tag: BytesStart, is_empty: bool, scope: F) -> Result<()>
where
    W: Write,
    F: FnOnce(&mut Writer<W>) -> Result<()>,
{
    if is_empty {
        writer.write_event(Event::Empty(tag))?;
    } else {
        let (start, end) = split_tag(&tag);
        writer.write_event(Event::Start(start))?;
        scope(writer)?;
        writer.write_event(Event::End(end))?;
    }
    Ok(())
}

fn scoped_iter<W, F, I>(
    writer: &mut Writer<W>,
    tag: BytesStart,
    iter: I,
    mut scope: F,
) -> Result<()>
where
    W: Write,
    I: IntoIterator,
    F: FnMut(&mut Writer<W>, <I as IntoIterator>::Item) -> Result<()>,
{
    let mut iter = iter.into_iter().peekable();
    scoped(writer, tag, iter.peek().is_none(), |writer| {
        for item in iter {
            scope(writer, item)?;
        }
        Ok(())
    })
}

fn text<W: Write, T: AsRef<[u8]>>(writer: &mut Writer<W>, tag: BytesStart, text: T) -> Result<()> {
    let text = text.as_ref();
    scoped(writer, tag, text.is_empty(), |writer| {
        writer.write_event(Event::Text(BytesText::borrowed(text)))?;
        Ok(())
    })
}

fn vec_as_string<F, R>(vec: &mut Vec<u8>, f: F) -> R
where
    F: FnOnce(&mut String) -> R,
{
    let taken = replace(vec, Vec::new());
    let mut string = String::from_utf8(taken).unwrap();
    let result = f(&mut string);
    let bytes = string.into_bytes();
    replace(vec, bytes);
    result
}

fn image<W: Write>(
    writer: &mut Writer<W>,
    tag: BytesStart,
    image: &Image,
    buf: &mut Vec<u8>,
    image_buf: &mut Cow<[u8]>,
) -> Result<()> {
    let url = image.url();
    if url.starts_with("data:;base64,") {
        let src = &url["data:;base64,".len()..];
        buf.clear();
        if base64::decode_config_buf(src, base64::STANDARD, buf).is_ok() {
            let len = buf.len();
            let image_buf = image_buf.to_mut();
            image_buf.truncate(LSS_IMAGE_HEADER.len());
            image_buf.reserve(len + 6);
            image_buf.write_u32::<LE>(len as u32).unwrap();
            image_buf.push(0x2);
            image_buf.append(buf);
            image_buf.push(0xB);
            buf.clear();
            vec_as_string(buf, |s| {
                base64::encode_config_buf(image_buf, base64::STANDARD, s)
            });
            return text(writer, tag, buf);
        }
    }
    writer.write_event(Event::Empty(tag))?;
    Ok(())
}

fn fmt_date(date: DateTime<Utc>, buf: &mut Vec<u8>) -> &[u8] {
    fmt_buf(date.format("%m/%d/%Y %T"), buf)
}

fn fmt_buf<D: Display>(value: D, buf: &mut Vec<u8>) -> &[u8] {
    buf.clear();
    write!(buf, "{}", value).unwrap();
    buf
}

fn write_display<W: Write, D: Display>(
    writer: &mut Writer<W>,
    tag: BytesStart,
    value: D,
    buf: &mut Vec<u8>,
) -> Result<()> {
    text(writer, tag, fmt_buf(value, buf))
}

fn time_span<W: Write>(
    writer: &mut Writer<W>,
    tag: BytesStart,
    time: TimeSpan,
    buf: &mut Vec<u8>,
) -> Result<()> {
    write_display(writer, tag, Complete.format(time), buf)
}

fn time_inner<W: Write>(writer: &mut Writer<W>, time: Time, buf: &mut Vec<u8>) -> Result<()> {
    if let Some(time) = time.real_time {
        time_span(writer, new_tag(b"RealTime"), time, buf)?;
    }

    if let Some(time) = time.game_time {
        time_span(writer, new_tag(b"GameTime"), time, buf)?;
    }

    Ok(())
}

fn time<W: Write>(
    writer: &mut Writer<W>,
    tag: BytesStart,
    time: Time,
    buf: &mut Vec<u8>,
) -> Result<()> {
    scoped(
        writer,
        tag,
        time.real_time.is_none() && time.game_time.is_none(),
        |writer| time_inner(writer, time, buf),
    )
}

pub fn save<W: Write>(run: &Run, writer: W) -> Result<()> {
    let writer = &mut Writer::new(writer);

    let buf = &mut Vec::new();
    let image_buf = &mut Cow::Borrowed(&LSS_IMAGE_HEADER[..]);

    writer.write_event(Event::Decl(BytesDecl::new(b"1.0", Some(b"UTF-8"), None)))?;
    writer.write_event(Event::Start(
        BytesStart::borrowed(br#"Run version="1.7.0""#, 3),
    ))?;

    image(
        writer,
        new_tag(b"GameIcon"),
        run.game_icon(),
        buf,
        image_buf,
    )?;
    text(writer, new_tag(b"GameName"), run.game_name())?;
    text(writer, new_tag(b"CategoryName"), run.category_name())?;

    write_start(writer, new_tag(b"Metadata"))?;
    let metadata = run.metadata();

    let mut tag = new_tag(b"Run");
    tag.push_attribute((&b"id"[..], metadata.run_id().as_bytes()));
    writer.write_event(Event::Empty(tag))?;

    tag = new_tag(b"Platform");
    tag.push_attribute((&b"usesEmulator"[..], bool(metadata.uses_emulator())));
    text(writer, tag, metadata.platform_name())?;

    text(writer, new_tag(b"Region"), metadata.region_name())?;

    scoped_iter(
        writer,
        new_tag(b"Variables"),
        metadata.variables(),
        |writer, (name, value)| {
            let mut tag = new_tag(b"Variable");
            tag.push_attribute((&b"name"[..], name.as_bytes()));
            text(writer, tag, value)
        },
    )?;
    write_end(writer, b"Metadata")?;

    time_span(writer, new_tag(b"Offset"), run.offset(), buf)?;
    write_display(writer, new_tag(b"AttemptCount"), run.attempt_count(), buf)?;

    scoped_iter(
        writer,
        new_tag(b"AttemptHistory"),
        run.attempt_history(),
        |writer, attempt| {
            let mut tag = new_tag(b"Attempt");
            tag.push_attribute((&b"id"[..], fmt_buf(attempt.index(), buf)));

            if let Some(started) = attempt.started() {
                tag.push_attribute((&b"started"[..], fmt_date(started.time, buf)));
                tag.push_attribute((
                    &b"isStartedSynced"[..],
                    bool(started.synced_with_atomic_clock),
                ));
            }

            if let Some(ended) = attempt.ended() {
                tag.push_attribute((&b"ended"[..], fmt_date(ended.time, buf)));
                tag.push_attribute((
                    &b"isEndedSynced"[..],
                    bool(ended.synced_with_atomic_clock),
                ));
            }

            let is_empty = attempt.time().real_time.is_none() &&
                attempt.time().game_time.is_none() &&
                attempt.pause_time().is_none();

            scoped(writer, tag, is_empty, |writer| {
                time_inner(writer, attempt.time(), buf)?;

                if let Some(pause_time) = attempt.pause_time() {
                    time_span(writer, new_tag(b"PauseTime"), pause_time, buf)?;
                }

                Ok(())
            })
        },
    )?;

    scoped_iter(
        writer,
        new_tag(b"Segments"),
        run.segments(),
        |writer, segment| {
            write_start(writer, new_tag(b"Segment"))?;

            text(writer, new_tag(b"Name"), segment.name())?;
            image(writer, new_tag(b"Icon"), segment.icon(), buf, image_buf)?;

            scoped_iter(
                writer,
                new_tag(b"SplitTimes"),
                run.custom_comparisons(),
                |writer, comparison| {
                    let mut tag = new_tag(b"SplitTime");
                    tag.push_attribute((&b"name"[..], comparison.as_bytes()));
                    time(writer, tag, segment.comparison(comparison), buf)
                },
            )?;

            time(
                writer,
                new_tag(b"BestSegmentTime"),
                segment.best_segment_time(),
                buf,
            )?;

            scoped_iter(
                writer,
                new_tag(b"SegmentHistory"),
                segment.segment_history(),
                |writer, &(index, history_time)| {
                    let mut tag = new_tag(b"Time");
                    tag.push_attribute((&b"id"[..], fmt_buf(index, buf)));
                    time(writer, tag, history_time, buf)
                },
            )?;

            write_end(writer, b"Segment")
        },
    )?;

    scoped_iter(
        writer,
        new_tag(b"AutoSplitterSettings"),
        run.auto_splitter_settings(),
        |writer, event| {
            writer.write_event(event)?;
            Ok(())
        },
    )?;

    write_end(writer, b"Run")?;
    Ok(())
}
<commit_msg>Use CData for the Images<commit_after>use std::io::Write;
use std::result::Result as StdResult;
use std::fmt::Display;
use std::borrow::Cow;
use std::mem::replace;
use {Image, Run, Time, TimeSpan, base64};
use time::formatter::{Complete, TimeFormatter};
use chrono::{DateTime, Utc};
use byteorder::{WriteBytesExt, LE};
use quick_xml::Writer;
use quick_xml::events::{BytesDecl, BytesEnd, BytesStart, BytesText, Event};
use quick_xml::errors::Error as XmlError;

static LSS_IMAGE_HEADER: &[u8; 156] = include_bytes!("lss_image_header.bin");

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Xml(err: XmlError) {
            from()
        }
    }
}

pub type Result<T> = StdResult<T, Error>;

fn new_tag(name: &[u8]) -> BytesStart {
    BytesStart::borrowed(name, name.len())
}

fn write_start<W: Write>(writer: &mut Writer<W>, tag: BytesStart) -> Result<()> {
    writer.write_event(Event::Start(tag))?;
    Ok(())
}

fn write_end<W: Write>(writer: &mut Writer<W>, tag: &[u8]) -> Result<()> {
    writer.write_event(Event::End(BytesEnd::borrowed(tag)))?;
    Ok(())
}

fn split_tag<'a>(tag: &'a BytesStart<'a>) -> (BytesStart<'a>, BytesEnd<'a>) {
    (
        BytesStart::borrowed(&tag, tag.name().len()),
        BytesEnd::borrowed(tag.name()),
    )
}

fn bool(value: bool) -> &'static [u8] {
    if value {
        b"True"
    } else {
        b"False"
    }
}

fn scoped<W, F>(writer: &mut Writer<W>, tag: BytesStart, is_empty: bool, scope: F) -> Result<()>
where
    W: Write,
    F: FnOnce(&mut Writer<W>) -> Result<()>,
{
    if is_empty {
        writer.write_event(Event::Empty(tag))?;
    } else {
        let (start, end) = split_tag(&tag);
        writer.write_event(Event::Start(start))?;
        scope(writer)?;
        writer.write_event(Event::End(end))?;
    }
    Ok(())
}

fn scoped_iter<W, F, I>(
    writer: &mut Writer<W>,
    tag: BytesStart,
    iter: I,
    mut scope: F,
) -> Result<()>
where
    W: Write,
    I: IntoIterator,
    F: FnMut(&mut Writer<W>, <I as IntoIterator>::Item) -> Result<()>,
{
    let mut iter = iter.into_iter().peekable();
    scoped(writer, tag, iter.peek().is_none(), |writer| {
        for item in iter {
            scope(writer, item)?;
        }
        Ok(())
    })
}

fn text<W: Write, T: AsRef<[u8]>>(writer: &mut Writer<W>, tag: BytesStart, text: T) -> Result<()> {
    let text = text.as_ref();
    scoped(writer, tag, text.is_empty(), |writer| {
        writer.write_event(Event::Text(BytesText::borrowed(text)))?;
        Ok(())
    })
}

fn vec_as_string<F, R>(vec: &mut Vec<u8>, f: F) -> R
where
    F: FnOnce(&mut String) -> R,
{
    let taken = replace(vec, Vec::new());
    let mut string = String::from_utf8(taken).unwrap();
    let result = f(&mut string);
    let bytes = string.into_bytes();
    replace(vec, bytes);
    result
}

fn image<W: Write>(
    writer: &mut Writer<W>,
    tag: BytesStart,
    image: &Image,
    buf: &mut Vec<u8>,
    image_buf: &mut Cow<[u8]>,
) -> Result<()> {
    let url = image.url();
    if url.starts_with("data:;base64,") {
        let src = &url["data:;base64,".len()..];
        buf.clear();
        if base64::decode_config_buf(src, base64::STANDARD, buf).is_ok() {
            let len = buf.len();
            let image_buf = image_buf.to_mut();
            image_buf.truncate(LSS_IMAGE_HEADER.len());
            image_buf.reserve(len + 6);
            image_buf.write_u32::<LE>(len as u32).unwrap();
            image_buf.push(0x2);
            image_buf.append(buf);
            image_buf.push(0xB);
            buf.clear();
            vec_as_string(buf, |s| {
                base64::encode_config_buf(image_buf, base64::STANDARD, s)
            });
            return scoped(writer, tag, buf.is_empty(), |writer| {
                writer.write_event(Event::CData(BytesText::borrowed(buf)))?;
                Ok(())
            });
        }
    }
    writer.write_event(Event::Empty(tag))?;
    Ok(())
}

fn fmt_date(date: DateTime<Utc>, buf: &mut Vec<u8>) -> &[u8] {
    fmt_buf(date.format("%m/%d/%Y %T"), buf)
}

fn fmt_buf<D: Display>(value: D, buf: &mut Vec<u8>) -> &[u8] {
    buf.clear();
    write!(buf, "{}", value).unwrap();
    buf
}

fn write_display<W: Write, D: Display>(
    writer: &mut Writer<W>,
    tag: BytesStart,
    value: D,
    buf: &mut Vec<u8>,
) -> Result<()> {
    text(writer, tag, fmt_buf(value, buf))
}

fn time_span<W: Write>(
    writer: &mut Writer<W>,
    tag: BytesStart,
    time: TimeSpan,
    buf: &mut Vec<u8>,
) -> Result<()> {
    write_display(writer, tag, Complete.format(time), buf)
}

fn time_inner<W: Write>(writer: &mut Writer<W>, time: Time, buf: &mut Vec<u8>) -> Result<()> {
    if let Some(time) = time.real_time {
        time_span(writer, new_tag(b"RealTime"), time, buf)?;
    }

    if let Some(time) = time.game_time {
        time_span(writer, new_tag(b"GameTime"), time, buf)?;
    }

    Ok(())
}

fn time<W: Write>(
    writer: &mut Writer<W>,
    tag: BytesStart,
    time: Time,
    buf: &mut Vec<u8>,
) -> Result<()> {
    scoped(
        writer,
        tag,
        time.real_time.is_none() && time.game_time.is_none(),
        |writer| time_inner(writer, time, buf),
    )
}

pub fn save<W: Write>(run: &Run, writer: W) -> Result<()> {
    let writer = &mut Writer::new(writer);

    let buf = &mut Vec::new();
    let image_buf = &mut Cow::Borrowed(&LSS_IMAGE_HEADER[..]);

    writer.write_event(Event::Decl(BytesDecl::new(b"1.0", Some(b"UTF-8"), None)))?;
    writer.write_event(Event::Start(
        BytesStart::borrowed(br#"Run version="1.7.0""#, 3),
    ))?;

    image(
        writer,
        new_tag(b"GameIcon"),
        run.game_icon(),
        buf,
        image_buf,
    )?;
    text(writer, new_tag(b"GameName"), run.game_name())?;
    text(writer, new_tag(b"CategoryName"), run.category_name())?;

    write_start(writer, new_tag(b"Metadata"))?;
    let metadata = run.metadata();

    let mut tag = new_tag(b"Run");
    tag.push_attribute((&b"id"[..], metadata.run_id().as_bytes()));
    writer.write_event(Event::Empty(tag))?;

    tag = new_tag(b"Platform");
    tag.push_attribute((&b"usesEmulator"[..], bool(metadata.uses_emulator())));
    text(writer, tag, metadata.platform_name())?;

    text(writer, new_tag(b"Region"), metadata.region_name())?;

    scoped_iter(
        writer,
        new_tag(b"Variables"),
        metadata.variables(),
        |writer, (name, value)| {
            let mut tag = new_tag(b"Variable");
            tag.push_attribute((&b"name"[..], name.as_bytes()));
            text(writer, tag, value)
        },
    )?;
    write_end(writer, b"Metadata")?;

    time_span(writer, new_tag(b"Offset"), run.offset(), buf)?;
    write_display(writer, new_tag(b"AttemptCount"), run.attempt_count(), buf)?;

    scoped_iter(
        writer,
        new_tag(b"AttemptHistory"),
        run.attempt_history(),
        |writer, attempt| {
            let mut tag = new_tag(b"Attempt");
            tag.push_attribute((&b"id"[..], fmt_buf(attempt.index(), buf)));

            if let Some(started) = attempt.started() {
                tag.push_attribute((&b"started"[..], fmt_date(started.time, buf)));
                tag.push_attribute((
                    &b"isStartedSynced"[..],
                    bool(started.synced_with_atomic_clock),
                ));
            }

            if let Some(ended) = attempt.ended() {
                tag.push_attribute((&b"ended"[..], fmt_date(ended.time, buf)));
                tag.push_attribute((
                    &b"isEndedSynced"[..],
                    bool(ended.synced_with_atomic_clock),
                ));
            }

            let is_empty = attempt.time().real_time.is_none() &&
                attempt.time().game_time.is_none() &&
                attempt.pause_time().is_none();

            scoped(writer, tag, is_empty, |writer| {
                time_inner(writer, attempt.time(), buf)?;

                if let Some(pause_time) = attempt.pause_time() {
                    time_span(writer, new_tag(b"PauseTime"), pause_time, buf)?;
                }

                Ok(())
            })
        },
    )?;

    scoped_iter(
        writer,
        new_tag(b"Segments"),
        run.segments(),
        |writer, segment| {
            write_start(writer, new_tag(b"Segment"))?;

            text(writer, new_tag(b"Name"), segment.name())?;
            image(writer, new_tag(b"Icon"), segment.icon(), buf, image_buf)?;

            scoped_iter(
                writer,
                new_tag(b"SplitTimes"),
                run.custom_comparisons(),
                |writer, comparison| {
                    let mut tag = new_tag(b"SplitTime");
                    tag.push_attribute((&b"name"[..], comparison.as_bytes()));
                    time(writer, tag, segment.comparison(comparison), buf)
                },
            )?;

            time(
                writer,
                new_tag(b"BestSegmentTime"),
                segment.best_segment_time(),
                buf,
            )?;

            scoped_iter(
                writer,
                new_tag(b"SegmentHistory"),
                segment.segment_history(),
                |writer, &(index, history_time)| {
                    let mut tag = new_tag(b"Time");
                    tag.push_attribute((&b"id"[..], fmt_buf(index, buf)));
                    time(writer, tag, history_time, buf)
                },
            )?;

            write_end(writer, b"Segment")
        },
    )?;

    scoped_iter(
        writer,
        new_tag(b"AutoSplitterSettings"),
        run.auto_splitter_settings(),
        |writer, event| {
            writer.write_event(event)?;
            Ok(())
        },
    )?;

    write_end(writer, b"Run")?;
    Ok(())
}
<|endoftext|>


<commit_before>use std::{mem, thread};

use chan;

use eventual::{self, Async};

use lang::{Context, Filter, Value};

pub enum ChannelError {
    /// This part of the channel is already closed. Occurs when calling `close` multiple times or when calling `send` after `close`.
    Closed
}

pub struct Sender {
    pub context: eventual::Complete<Context, ()>,
    pub values: chan::Sender<Value>
    //TODO namespaces
}

pub struct Receiver {
    pub context: eventual::Future<Context, ()>,
    pub values: chan::Receiver<Value>
    //TODO namespaces
}

impl Receiver {
    /// A closed receiver with no values.
    pub fn empty(context: Context) -> Receiver {
        let (_, val_rx) = chan::async();
        Receiver {
            context: eventual::Future::of(context),
            values: val_rx
        }
    }

    /// Takes the receiving end of a channel, asynchronously runs it through a filter, and returns the output channel.
    pub fn filter(self, f: &Filter) -> Receiver {
        let (tx, rx) = channel();
        let f = f.clone();
        thread::spawn(move || f.run(self, tx));
        rx
    }

    /// Same as `filter` but waits until the filter function returns.
    pub fn filter_sync(self, f: &Filter) -> Receiver {
        let (tx, rx) = channel();
        f.run(self, tx);
        rx
    }

    /// Asynchronously forwards all received values to `dst` and closes `self`'s value channel.
    ///
    /// Returns `dst`'s context future sender.
    pub fn forward_values(&mut self, dst: Sender) -> eventual::Complete<Context, ()> {
        let (_, val_rx) = chan::async();
        let vals_to_forward = mem::replace(&mut self.values, val_rx);
        let Sender { context, values } = dst;
        thread::spawn(move || {
            for val in vals_to_forward {
                values.send(val);
            }
        });
        context
    }

    /// Split `self` into two new receivers, forwarding everything to both.
    pub fn split(self) -> (Receiver, Receiver) {
        let (Sender { context: ctxt_tx1, values: val_tx1 }, rx1) = channel();
        let (Sender { context: ctxt_tx2, values: val_tx2 }, rx2) = channel();
        let Receiver { context, values } = self;
        thread::spawn(move || {
            let context = context.await().expect("failed to split contexts");
            ctxt_tx1.complete(context.clone());
            ctxt_tx2.complete(context);
        });
        thread::spawn(move || {
            for val in values {
                val_tx1.send(val.clone());
                val_tx2.send(val);
            }
        });
        (rx1, rx2)
    }
}

impl IntoIterator for Receiver {
    type Item = Value;
    type IntoIter = chan::Iter<Value>;

    fn into_iter(self) -> chan::Iter<Value> {
        self.values.into_iter()
    }
}

pub fn channel() -> (Sender, Receiver) {
    let (ctxt_tx, ctxt_fut) = eventual::Future::pair();
    let (val_tx, val_rx) = chan::async();
    let tx = Sender {
        context: ctxt_tx,
        values: val_tx
    };
    let rx = Receiver {
        context: ctxt_fut,
        values: val_rx
    };
    (tx, rx)
}
<commit_msg>Remove obsoleted ChannelError enum<commit_after>use std::{mem, thread};

use chan;

use eventual::{self, Async};

use lang::{Context, Filter, Value};

pub struct Sender {
    pub context: eventual::Complete<Context, ()>,
    pub values: chan::Sender<Value>
    //TODO namespaces
}

pub struct Receiver {
    pub context: eventual::Future<Context, ()>,
    pub values: chan::Receiver<Value>
    //TODO namespaces
}

impl Receiver {
    /// A closed receiver with no values.
    pub fn empty(context: Context) -> Receiver {
        let (_, val_rx) = chan::async();
        Receiver {
            context: eventual::Future::of(context),
            values: val_rx
        }
    }

    /// Takes the receiving end of a channel, asynchronously runs it through a filter, and returns the output channel.
    pub fn filter(self, f: &Filter) -> Receiver {
        let (tx, rx) = channel();
        let f = f.clone();
        thread::spawn(move || f.run(self, tx));
        rx
    }

    /// Same as `filter` but waits until the filter function returns.
    pub fn filter_sync(self, f: &Filter) -> Receiver {
        let (tx, rx) = channel();
        f.run(self, tx);
        rx
    }

    /// Asynchronously forwards all received values to `dst` and closes `self`'s value channel.
    ///
    /// Returns `dst`'s context future sender.
    pub fn forward_values(&mut self, dst: Sender) -> eventual::Complete<Context, ()> {
        let (_, val_rx) = chan::async();
        let vals_to_forward = mem::replace(&mut self.values, val_rx);
        let Sender { context, values } = dst;
        thread::spawn(move || {
            for val in vals_to_forward {
                values.send(val);
            }
        });
        context
    }

    /// Split `self` into two new receivers, forwarding everything to both.
    pub fn split(self) -> (Receiver, Receiver) {
        let (Sender { context: ctxt_tx1, values: val_tx1 }, rx1) = channel();
        let (Sender { context: ctxt_tx2, values: val_tx2 }, rx2) = channel();
        let Receiver { context, values } = self;
        thread::spawn(move || {
            let context = context.await().expect("failed to split contexts");
            ctxt_tx1.complete(context.clone());
            ctxt_tx2.complete(context);
        });
        thread::spawn(move || {
            for val in values {
                val_tx1.send(val.clone());
                val_tx2.send(val);
            }
        });
        (rx1, rx2)
    }
}

impl IntoIterator for Receiver {
    type Item = Value;
    type IntoIter = chan::Iter<Value>;

    fn into_iter(self) -> chan::Iter<Value> {
        self.values.into_iter()
    }
}

pub fn channel() -> (Sender, Receiver) {
    let (ctxt_tx, ctxt_fut) = eventual::Future::pair();
    let (val_tx, val_rx) = chan::async();
    let tx = Sender {
        context: ctxt_tx,
        values: val_tx
    };
    let rx = Receiver {
        context: ctxt_fut,
        values: val_rx
    };
    (tx, rx)
}
<|endoftext|>


<commit_before>use std::sync::{Arc, Mutex};

use super::*;

#[derive(Clone)]
pub(crate) struct Context {
    // TODO file from config should be in here
    config: Config,
    /// Periodically flushes dirty data. We keep this in an
    /// Arc separate from the PageCache below to separate
    /// "high-level" references from Db, Tree etc... from
    /// "low-level" references like background threads.
    /// When the last high-level reference is dropped, it
    /// should trigger all background threads to clean
    /// up synchronously.
    pub(crate) _flusher: Arc<Mutex<Option<flusher::Flusher>>>,
    pub(crate) pagecache: Arc<PageCache<BLinkMaterializer, Frag>>,
}

impl std::ops::Deref for Context {
    type Target = Config;

    fn deref(&self) -> &Config {
        &self.config
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        if let Err(e) = self.pagecache.flush() {
            error!(
                "failed to flush underlying \
                 pagecache during drop: {:?}",
                e
            );
        }

        #[cfg(feature = "event_log")]
        {
            let tx = Tx::new(0);

            self.config.event_log.meta_before_restart(
                self.pagecache
                    .meta(&tx)
                    .expect("should get meta under test")
                    .clone(),
            );
        }
    }
}

impl Context {
    pub(crate) fn start(config: Config) -> Result<Context> {
        #[cfg(any(test, feature = "check_snapshot_integrity"))]
        match config.verify_snapshot::<BLinkMaterializer, Frag>() {
            Ok(_) => {}
            #[cfg(feature = "failpoints")]
            Err(Error::FailPoint) => {}
            other => panic!("failed to verify snapshot: {:?}", other),
        }

        let pagecache = Arc::new(PageCache::start(config.clone())?);

        Ok(Context {
            config,
            pagecache,
            _flusher: Arc::new(Mutex::new(None)),
        })
    }

    /// Returns `true` if the database was
    /// recovered from a previous process.
    /// Note that database state is only
    /// guaranteed to be present up to the
    /// last call to `flush`! Otherwise state
    /// is synced to disk periodically if the
    /// `sync_every_ms` configuration option
    /// is set to `Some(number_of_ms_between_syncs)`
    /// or if the IO buffer gets filled to
    /// capacity before being rotated.
    pub fn was_recovered(&self) -> bool {
        self.pagecache.was_recovered()
    }

    /// Generate a monotonic ID. Not guaranteed to be
    /// contiguous. Written to disk every `idgen_persist_interval`
    /// operations, followed by a blocking flush. During recovery, we
    /// take the last recovered generated ID and add 2x
    /// the `idgen_persist_interval` to it. While persisting, if the
    /// previous persisted counter wasn't synced to disk yet, we will do
    /// a blocking flush to fsync the latest counter, ensuring
    /// that we will never give out the same counter twice.
    pub fn generate_id(&self) -> Result<u64> {
        self.pagecache.generate_id()
    }
}
<commit_msg>Fix sled event_log handling<commit_after>use std::sync::{Arc, Mutex};

use super::*;

#[derive(Clone)]
pub(crate) struct Context {
    // TODO file from config should be in here
    config: Config,
    /// Periodically flushes dirty data. We keep this in an
    /// Arc separate from the PageCache below to separate
    /// "high-level" references from Db, Tree etc... from
    /// "low-level" references like background threads.
    /// When the last high-level reference is dropped, it
    /// should trigger all background threads to clean
    /// up synchronously.
    pub(crate) _flusher: Arc<Mutex<Option<flusher::Flusher>>>,
    pub(crate) pagecache: Arc<PageCache<BLinkMaterializer, Frag>>,
}

impl std::ops::Deref for Context {
    type Target = Config;

    fn deref(&self) -> &Config {
        &self.config
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        if let Err(e) = self.pagecache.flush() {
            error!(
                "failed to flush underlying \
                 pagecache during drop: {:?}",
                e
            );
        }

        #[cfg(feature = "event_log")]
        {
            let tx = Tx::new(&self.pagecache, 0);

            self.config.event_log.meta_before_restart(
                self.pagecache
                    .meta(&tx)
                    .expect("should get meta under test")
                    .clone(),
            );
        }
    }
}

impl Context {
    pub(crate) fn start(config: Config) -> Result<Context> {
        #[cfg(any(test, feature = "check_snapshot_integrity"))]
        match config.verify_snapshot::<BLinkMaterializer, Frag>() {
            Ok(_) => {}
            #[cfg(feature = "failpoints")]
            Err(Error::FailPoint) => {}
            other => panic!("failed to verify snapshot: {:?}", other),
        }

        let pagecache = Arc::new(PageCache::start(config.clone())?);

        Ok(Context {
            config,
            pagecache,
            _flusher: Arc::new(Mutex::new(None)),
        })
    }

    /// Returns `true` if the database was
    /// recovered from a previous process.
    /// Note that database state is only
    /// guaranteed to be present up to the
    /// last call to `flush`! Otherwise state
    /// is synced to disk periodically if the
    /// `sync_every_ms` configuration option
    /// is set to `Some(number_of_ms_between_syncs)`
    /// or if the IO buffer gets filled to
    /// capacity before being rotated.
    pub fn was_recovered(&self) -> bool {
        self.pagecache.was_recovered()
    }

    /// Generate a monotonic ID. Not guaranteed to be
    /// contiguous. Written to disk every `idgen_persist_interval`
    /// operations, followed by a blocking flush. During recovery, we
    /// take the last recovered generated ID and add 2x
    /// the `idgen_persist_interval` to it. While persisting, if the
    /// previous persisted counter wasn't synced to disk yet, we will do
    /// a blocking flush to fsync the latest counter, ensuring
    /// that we will never give out the same counter twice.
    pub fn generate_id(&self) -> Result<u64> {
        self.pagecache.generate_id()
    }
}
<|endoftext|>


<commit_before>pub mod some_endpoint {
    use ruma_api::ruma_api;
    use ruma_common::Raw;
    use ruma_events::{tag::TagEvent, AnyRoomEvent};

    ruma_api! {
        metadata: {
            description: "Does something.",
            method: POST, // An `http::Method` constant. No imports required.
            name: "some_endpoint",
            path: "/_matrix/some/endpoint/:baz",
            rate_limited: false,
            requires_authentication: false,
        }

        request: {
            // With no attribute on the field, it will be put into the body of the request.
            pub foo: String,

            // This value will be put into the "Content-Type" HTTP header.
            #[ruma_api(header = CONTENT_TYPE)]
            pub content_type: String,

            // This value will be put into the query string of the request's URL.
            #[ruma_api(query)]
            pub bar: String,

            // This value will be inserted into the request's URL in place of the
            // ":baz" path component.
            #[ruma_api(path)]
            pub baz: String,
        }

        response: {
            // This value will be extracted from the "Content-Type" HTTP header.
            #[ruma_api(header = CONTENT_TYPE)]
            pub content_type: String,

            // With no attribute on the field, it will be extracted from the body of the response.
            pub value: String,

            // You can use serde attributes on any kind of field
            #[serde(skip_serializing_if = "Option::is_none")]
            pub optional_flag: Option<bool>,

            // Use `Raw` instead of the actual event to allow additional fields to be sent...
            pub event: Raw<TagEvent>,

            // ... and to allow unknown events when the endpoint deals with event collections.
            pub list_of_events: Vec<Raw<AnyRoomEvent>>,
        }
    }
}

pub mod newtype_body_endpoint {
    use ruma_api::ruma_api;

    #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
    pub struct MyCustomType {
        pub foo: String,
    }

    ruma_api! {
        metadata: {
            description: "Does something.",
            method: PUT,
            name: "newtype_body_endpoint",
            path: "/_matrix/some/newtype/body/endpoint",
            rate_limited: false,
            requires_authentication: false,
        }

        request: {
            #[ruma_api(body)]
            pub list_of_custom_things: Vec<MyCustomType>,
        }

        response: {
            #[ruma_api(body)]
            pub my_custom_thing: MyCustomType,
        }
    }
}

pub mod newtype_raw_body_endpoint {
    use ruma_api::ruma_api;

    #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
    pub struct MyCustomType {
        pub foo: String,
    }

    ruma_api! {
        metadata: {
            description: "Does something.",
            method: PUT,
            name: "newtype_body_endpoint",
            path: "/_matrix/some/newtype/body/endpoint",
            rate_limited: false,
            requires_authentication: false,
        }

        request: {
            #[ruma_api(raw_body)]
            pub file: Vec<u8>,
        }

        response: {
            #[ruma_api(raw_body)]
            pub file: Vec<u8>,
        }
    }
}

pub mod query_map_endpoint {
    use ruma_api::ruma_api;

    ruma_api! {
        metadata: {
            description: "Does something.",
            method: GET,
            name: "newtype_body_endpoint",
            path: "/_matrix/some/query/map/endpoint",
            rate_limited: false,
            requires_authentication: false,
        }

        request: {
            #[ruma_api(query_map)]
            pub fields: Vec<(String, String)>,
        }

        response: {
        }
    }
}
<commit_msg>Small style fix<commit_after>pub mod some_endpoint {
    use ruma_api::ruma_api;
    use ruma_common::Raw;
    use ruma_events::{tag::TagEvent, AnyRoomEvent};

    ruma_api! {
        metadata: {
            description: "Does something.",
            method: POST, // An `http::Method` constant. No imports required.
            name: "some_endpoint",
            path: "/_matrix/some/endpoint/:baz",
            rate_limited: false,
            requires_authentication: false,
        }

        request: {
            // With no attribute on the field, it will be put into the body of the request.
            pub foo: String,

            // This value will be put into the "Content-Type" HTTP header.
            #[ruma_api(header = CONTENT_TYPE)]
            pub content_type: String,

            // This value will be put into the query string of the request's URL.
            #[ruma_api(query)]
            pub bar: String,

            // This value will be inserted into the request's URL in place of the
            // ":baz" path component.
            #[ruma_api(path)]
            pub baz: String,
        }

        response: {
            // This value will be extracted from the "Content-Type" HTTP header.
            #[ruma_api(header = CONTENT_TYPE)]
            pub content_type: String,

            // With no attribute on the field, it will be extracted from the body of the response.
            pub value: String,

            // You can use serde attributes on any kind of field
            #[serde(skip_serializing_if = "Option::is_none")]
            pub optional_flag: Option<bool>,

            // Use `Raw` instead of the actual event to allow additional fields to be sent...
            pub event: Raw<TagEvent>,

            // ... and to allow unknown events when the endpoint deals with event collections.
            pub list_of_events: Vec<Raw<AnyRoomEvent>>,
        }
    }
}

pub mod newtype_body_endpoint {
    use ruma_api::ruma_api;

    #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
    pub struct MyCustomType {
        pub foo: String,
    }

    ruma_api! {
        metadata: {
            description: "Does something.",
            method: PUT,
            name: "newtype_body_endpoint",
            path: "/_matrix/some/newtype/body/endpoint",
            rate_limited: false,
            requires_authentication: false,
        }

        request: {
            #[ruma_api(body)]
            pub list_of_custom_things: Vec<MyCustomType>,
        }

        response: {
            #[ruma_api(body)]
            pub my_custom_thing: MyCustomType,
        }
    }
}

pub mod newtype_raw_body_endpoint {
    use ruma_api::ruma_api;

    #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
    pub struct MyCustomType {
        pub foo: String,
    }

    ruma_api! {
        metadata: {
            description: "Does something.",
            method: PUT,
            name: "newtype_body_endpoint",
            path: "/_matrix/some/newtype/body/endpoint",
            rate_limited: false,
            requires_authentication: false,
        }

        request: {
            #[ruma_api(raw_body)]
            pub file: Vec<u8>,
        }

        response: {
            #[ruma_api(raw_body)]
            pub file: Vec<u8>,
        }
    }
}

pub mod query_map_endpoint {
    use ruma_api::ruma_api;

    ruma_api! {
        metadata: {
            description: "Does something.",
            method: GET,
            name: "newtype_body_endpoint",
            path: "/_matrix/some/query/map/endpoint",
            rate_limited: false,
            requires_authentication: false,
        }

        request: {
            #[ruma_api(query_map)]
            pub fields: Vec<(String, String)>,
        }

        response: {}
    }
}
<|endoftext|>


<commit_before>use linalg::vector::Vector;
use linalg::matrix::Matrix;

use learning::SupModel;

pub struct GenLinearModel<C: Criterion> {
    parameters: Option<Vector<f64>>,
    criterion: C,
}

impl<C: Criterion> GenLinearModel<C> {
	pub fn new(criterion: C) -> GenLinearModel<C> {
		GenLinearModel {
			parameters: None,
			criterion: criterion,
		}
	}
}

impl<C: Criterion> SupModel<Matrix<f64>, Vector<f64>> for GenLinearModel<C> {
    /// Predict output from inputs.
    fn predict(&self, inputs: &Matrix<f64>) -> Vector<f64> {
        if let Some(ref v) = self.parameters {
            let ones = Matrix::<f64>::ones(inputs.rows(), 1);
            let full_inputs = ones.hcat(inputs);
            self.criterion.apply_link_inv(full_inputs * v)
        } else {
            panic!("The model has not been trained.");
        }
    }

    /// Train the model using inputs and targets.
    fn train(&mut self, inputs: &Matrix<f64>, targets: &Vector<f64>) {
        let n = inputs.rows();

        assert!(n == targets.size(),
                "Training data do not have the same dimensions.");

        // Construct mu as a non-zero estimate of targets.
        let mut mu_data = Vec::with_capacity(n);
        for y in targets.data() {
        	mu_data.push(0.5);//if *y > 0f64 { *y } else { 1e-3 })
        }

        let mut mu = Vector::new(mu_data);
        let mut z = mu.clone();
        let mut beta : Vector<f64> = Vector::new(vec![]);

        let ones = Matrix::<f64>::ones(inputs.rows(), 1);
        let full_inputs = ones.hcat(inputs);
        let x_t = full_inputs.transpose();

        // Iterate to convergence
        for k in 0..15 {
            let mut w_diag = Vec::with_capacity(n);
            let mut y_bar_data = Vec::with_capacity(n);

            for (idx, m) in mu.data().iter().enumerate() {
                y_bar_data.push(self.criterion.compute_y_bar(targets[idx], *m));
                w_diag.push(self.criterion.compute_working_weight(*m));
            }

            let i = 5;

            println!("-------- Iteration {0} --------", k+1);
            println!("mu[{0}] = {1}", i, mu[i]);
            println!("y[{0}] = {1}", i, targets[i]);
            println!("y_bar[{0}] = {1}", i, y_bar_data[i]);
            println!("w[{0}] = {1}", i, w_diag[i]);

            let w = Matrix::from_diag(&w_diag);
            let y_bar = Vector::new(y_bar_data);

            let x_t_w = &x_t * w;
            beta = (&x_t_w * &full_inputs).inverse() * x_t_w * z;

            //println!("Beta = {:?}", beta.data());

            // Update z and mu
            let fitted = &full_inputs * β
            z = y_bar + &fitted;
            mu = self.criterion.apply_link_inv(fitted);
        }

        self.parameters = Some(beta);
    }
}

/// Should include the link function and the variance from the distribution
pub trait Criterion {
	type Link : LinkFunc;

    fn model_variance(&self, mu: f64) -> f64;

    fn compute_working_weight(&self, mu: f64) -> f64 {
        1f64 / (self.model_variance(mu) * self.link_grad(mu) * self.link_grad(mu))
    }

    fn compute_y_bar(&self, y:f64, mu: f64) -> f64 {
        self.link_grad(mu) * (y - mu)
    }

    fn apply_link_func(&self, vec: Vector<f64>) -> Vector<f64> {
        vec.apply(&Self::Link::func)
    }

    fn apply_link_inv(&self, vec: Vector<f64>) -> Vector<f64> {
    	vec.apply(&Self::Link::func_inv)
    }

    fn link_grad(&self, mu: f64) -> f64 {
        Self::Link::func_grad(mu)
    }
}

pub trait LinkFunc {
    /// The link function.
    fn func(x: f64) -> f64;

    /// The gradient of the link function.
    fn func_grad(x: f64) -> f64;

    /// The inverse of the link function.
    /// Often called the 'mean' function.
    fn func_inv(x: f64) -> f64;
}

/// Sigmoid activation function.
pub struct Logit;

impl LinkFunc for Logit {
    /// Logit function.
    ///
    /// Returns ln(x / (1 - x)).
    fn func(x: f64) -> f64 {
        (x / (1f64 - x)).ln()
    }

    /// Gradient of logit function.
    ///
    /// Returns 1 / (x * (1-x))
    fn func_grad(x: f64) -> f64 {
        1f64 / (x * (1f64 - x))
    }

    fn func_inv(x: f64) -> f64 {
        1.0 / (1.0 + (-x).exp())
    }
}

pub struct Bernoulli;

impl Criterion for Bernoulli {
    type Link = Logit;

    fn model_variance(&self, mu: f64) -> f64 {
        mu * (1f64 - mu)
    }

    fn compute_working_weight(&self, mu: f64) -> f64 {
        self.model_variance(mu)
    }

    fn compute_y_bar(&self, y:f64, mu: f64) -> f64 {
        let target_diff = y - mu;

        if target_diff.abs() < 1e-15 {
            0f64
        }
        else {
            self.link_grad(mu) * target_diff
        }
    }
}
<commit_msg>Updating glm to include more docs, and some bug fixes.<commit_after>use linalg::vector::Vector;
use linalg::matrix::Matrix;

use learning::SupModel;

pub struct GenLinearModel<C: Criterion> {
    parameters: Option<Vector<f64>>,
    criterion: C,
}

impl<C: Criterion> GenLinearModel<C> {

    /// Constructs a new Generalized Linear Model.
    ///
    /// Takes a Criterion which fully specifies the family
    /// and the link function used by the GLM.
    ///
    /// ```
    /// use rusty_machine::learning::glm::GenLinearModel;
    /// //use rusty_machine::learning::glm::Criterion;
    /// use rusty_machine::learning::glm::Bernoulli;
    ///
    /// let glm = GenLinearModel::new(Bernoulli);
    ///
    /// ```
	pub fn new(criterion: C) -> GenLinearModel<C> {
		GenLinearModel {
			parameters: None,
			criterion: criterion,
		}
	}
}

impl<C: Criterion> SupModel<Matrix<f64>, Vector<f64>> for GenLinearModel<C> {
    /// Predict output from inputs.
    fn predict(&self, inputs: &Matrix<f64>) -> Vector<f64> {
        if let Some(ref v) = self.parameters {
            let ones = Matrix::<f64>::ones(inputs.rows(), 1);
            let full_inputs = ones.hcat(inputs);
            self.criterion.apply_link_inv(full_inputs * v)
        } else {
            panic!("The model has not been trained.");
        }
    }

    /// Train the model using inputs and targets.
    fn train(&mut self, inputs: &Matrix<f64>, targets: &Vector<f64>) {
        let n = inputs.rows();

        assert!(n == targets.size(),
                "Training data do not have the same dimensions.");

        // Construct initial estimate for mu
        let mut mu = Vector::new(self.criterion.initialize_mu(targets.data()));
        let mut z = mu.clone();
        let mut beta : Vector<f64> = Vector::new(vec![]);

        let ones = Matrix::<f64>::ones(inputs.rows(), 1);
        let full_inputs = ones.hcat(inputs);
        let x_t = full_inputs.transpose();

        // Iterate to convergence
        for _ in 0..8 {
            let w_diag = self.criterion.compute_working_weight(&mu.data());
            let y_bar_data = self.criterion.compute_y_bar(targets.data(), &mu.data());

            let w = Matrix::from_diag(&w_diag);
            let y_bar = Vector::new(y_bar_data);

            let x_t_w = &x_t * w;

            beta = (&x_t_w * &full_inputs).inverse() * x_t_w * z;

            // Update z and mu
            let fitted = &full_inputs * β
            z = y_bar + &fitted;
            mu = self.criterion.apply_link_inv(fitted);
        }

        self.parameters = Some(beta);
    }
}

/// The criterion for the Generalized Linear Model.
///
/// This trait specifies a Link function and requires a model
/// variance to be specified. The model variance must be defined
/// to specify the regression family. The other functions need not
/// be specified but can be used to control optimization.
pub trait Criterion {
	type Link : LinkFunc;

    /// The variance of the regression family.
    fn model_variance(&self, mu: f64) -> f64;

    /// Initializes the mean value.
    ///
    /// By default the mean takes the training target values.
    fn initialize_mu(&self, y: &[f64]) -> Vec<f64> {
        y.to_vec()
    }

    /// Computes the working weights that make up the diagonal
    /// of the `W` matrix used in the iterative reweighted least squares
    /// algorithm.
    ///
    /// This is equal to:
    ///
    /// 1 / (Var(u) * g'(u) * g'(u))
    fn compute_working_weight(&self, mu: &[f64]) -> Vec<f64> {
        let mut working_weights_vec = Vec::with_capacity(mu.len());

        for m in mu {
            let grad = self.link_grad(*m);
            working_weights_vec.push(1f64 / (self.model_variance(*m) * grad * grad));
        }

        working_weights_vec
    }

    /// Computes the adjustment to the fitted values used during
    /// fitting.
    ///
    /// This is equal to:
    ///
    /// g`(u) * (y - u)
    fn compute_y_bar(&self, y: &[f64], mu: &[f64]) -> Vec<f64> {
        let mut y_bar_vec = Vec::with_capacity(mu.len());

        for (idx, m) in mu.iter().enumerate() {
            y_bar_vec.push(self.link_grad(*m) * (y[idx] - m));
        }

        y_bar_vec
    }

    /// Applies the link function to a vector.
    fn apply_link_func(&self, vec: Vector<f64>) -> Vector<f64> {
        vec.apply(&Self::Link::func)
    }

    /// Applies the inverse of the link function to a vector.
    fn apply_link_inv(&self, vec: Vector<f64>) -> Vector<f64> {
    	vec.apply(&Self::Link::func_inv)
    }

    /// Computes the gradient of the link function.
    fn link_grad(&self, mu: f64) -> f64 {
        Self::Link::func_grad(mu)
    }
}

/// Link functions.
///
/// Used within Generalized Linear Regression models.
pub trait LinkFunc {
    /// The link function.
    fn func(x: f64) -> f64;

    /// The gradient of the link function.
    fn func_grad(x: f64) -> f64;

    /// The inverse of the link function.
    /// Often called the 'mean' function.
    fn func_inv(x: f64) -> f64;
}

/// The Logit link function.
///
/// Used primarily as the canonical link in Binomial Regression.
pub struct Logit;

/// The Logit link function.
///
/// g(u) = ln(x / (1 - x))
impl LinkFunc for Logit {

    fn func(x: f64) -> f64 {
        (x / (1f64 - x)).ln()
    }

    fn func_grad(x: f64) -> f64 {
        1f64 / (x * (1f64 - x))
    }

    fn func_inv(x: f64) -> f64 {
        1.0 / (1.0 + (-x).exp())
    }
}

/// The log link function.
///
/// Used primarily as the canonical link in Poisson Regression.
pub struct Log;

/// The log link function.
///
/// g(u) = ln(u)
impl LinkFunc for Log {
    fn func(x: f64) -> f64 {
        x.ln()
    }

    fn func_grad(x: f64) -> f64 {
        1f64 / x
    }

    fn func_inv(x: f64) -> f64 {
        x.exp()
    }
}

/// The Identity link function.
///
/// Used primarily as the canonical link in Linear Regression.
pub struct Identity;

/// The Identity link function.
///
/// g(u) = u
impl LinkFunc for Identity {
    fn func(x: f64) -> f64 {
        x
    }

    fn func_grad(_: f64) -> f64 {
        1f64
    }

    fn func_inv(x: f64) -> f64 {
        x
    }
}

/// The Bernoulli regression family.
///
/// This is equivalent to logistic regression.
pub struct Bernoulli;

impl Criterion for Bernoulli {
    type Link = Logit;

    fn model_variance(&self, mu: f64) -> f64 {
        let var = mu * (1f64 - mu);

        if var.abs() < 1e-10 {
            1e-10
        }
        else {
            var
        }
    }

    fn initialize_mu(&self, y: &[f64]) -> Vec<f64> {
        let mut mu_data = Vec::with_capacity(y.len());

        for y_val in y {
            mu_data.push(
                if *y_val < 1e-10 {
                    1e-10
                } else if *y_val > 1f64 - 1e-10 {
                    1f64 - 1e-10
                } else {
                    *y_val
                });
        }

        mu_data
    }

    fn compute_working_weight(&self, mu: &[f64]) -> Vec<f64> {
        let mut working_weights_vec = Vec::with_capacity(mu.len());

        for m in mu {
            let var = self.model_variance(*m);

            working_weights_vec.push(if var.abs() < 1e-5 {
                1e-5
            } else {
                var
            });
        }

        working_weights_vec
    }

    fn compute_y_bar(&self, y: &[f64], mu: &[f64]) -> Vec<f64> {
        let mut y_bar_vec = Vec::with_capacity(y.len());

        for (idx, m) in mu.iter().enumerate() {
            let target_diff = y[idx] - m;

            y_bar_vec.push(if target_diff.abs() < 1e-15 {
                0f64
            } else {
                self.link_grad(*m) * target_diff
            });
        }

        y_bar_vec
    }
}

/// The binomial regression family.
pub struct Binomial {
    weights: Vec<f64>,
}

impl Criterion for Binomial {
    type Link = Logit;

    fn model_variance(&self, mu: f64) -> f64 {
        let var = mu * (1f64 - mu);

        if var.abs() < 1e-10 {
            1e-10
        }
        else {
            var
        }

    }

    fn initialize_mu(&self, y: &[f64]) -> Vec<f64> {
        let mut mu_data = Vec::with_capacity(y.len());

        for y_val in y {
            mu_data.push(
                if *y_val < 1e-10 {
                    1e-10
                } else if *y_val > 1f64 - 1e-10 {
                    1f64 - 1e-10
                } else {
                    *y_val
                });
        }

        mu_data
    }

    fn compute_working_weight(&self, mu: &[f64]) -> Vec<f64> {
        let mut working_weights_vec = Vec::with_capacity(mu.len());

        for (idx, m) in mu.iter().enumerate() {
            let var = self.model_variance(*m) / self.weights[idx];

            working_weights_vec.push(if var.abs() < 1e-5 {
                1e-5
            } else {
                var
            });
        }

        working_weights_vec
    }

    fn compute_y_bar(&self, y: &[f64], mu: &[f64]) -> Vec<f64> {
        let mut y_bar_vec = Vec::with_capacity(y.len());

        for (idx, m) in mu.iter().enumerate() {
            let target_diff = y[idx] - m;

            y_bar_vec.push(if target_diff.abs() < 1e-15 {
                0f64
            } else {
                self.link_grad(*m) * target_diff
            });
        }

        y_bar_vec
    }
}

/// The Normal regression family.
///
/// This is equivalent to the Linear Regression model.
pub struct Normal;

impl Criterion for Normal {
    type Link = Identity;

    fn model_variance(&self, _: f64) -> f64 {
        1f64
    }
}

/// The Poisson regression family.
pub struct Poisson;

impl Criterion for Poisson {
    type Link = Log;

    fn model_variance(&self, mu: f64) -> f64 {
        mu
    }

    fn initialize_mu(&self, y: &[f64]) -> Vec<f64> {
        let mut mu_data = Vec::with_capacity(y.len());

        for y_val in y {
            mu_data.push(
                if *y_val < 1e-10 {
                    1e-10
                } else {
                    *y_val
                });
        }

        mu_data
    }
}<|endoftext|>


<commit_before>//! [POST /_matrix/client/r0/user_directory/search](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-user-directory-search)

use js_int::UInt;
use ruma_api::ruma_api;
use ruma_identifiers::UserId;
use serde::{Deserialize, Serialize};

ruma_api! {
    metadata {
        description: "Performs a search for users on the homeserver.",
        method: POST,
        name: "search_users",
        path: "/_matrix/client/r0/user_directory/search",
        rate_limited: true,
        requires_authentication: true,
    }

    request {
        /// The term to search for.
        pub search_term: String,

        /// The maximum number of results to return.
        ///
        /// Defaults to 10.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub limit: Option<UInt>,
    }

    response {
        /// Ordered by rank and then whether or not profile info is available.
        pub results: Vec<User>,

        /// Indicates if the result list has been truncated by the limit.
        pub limited: bool,
    }

    error: crate::Error
}

/// User data as result of a search.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct User {
    /// The user's matrix user ID.
    pub user_id: UserId,

    /// The display name of the user, if one exists.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub display_name: Option<String>,

    /// The avatar url, as an MXC, if one exists.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub avatar_url: Option<String>,
}
<commit_msg>Clarify search_users documentation based on the latest spec version<commit_after>//! [POST /_matrix/client/r0/user_directory/search](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-user-directory-search)

use js_int::UInt;
use ruma_api::ruma_api;
use ruma_identifiers::UserId;
use serde::{Deserialize, Serialize};

ruma_api! {
    metadata {
        description: "Performs a search for users.",
        method: POST,
        name: "search_users",
        path: "/_matrix/client/r0/user_directory/search",
        rate_limited: true,
        requires_authentication: true,
    }

    request {
        /// The term to search for.
        pub search_term: String,

        /// The maximum number of results to return.
        ///
        /// Defaults to 10.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub limit: Option<UInt>,
    }

    response {
        /// Ordered by rank and then whether or not profile info is available.
        pub results: Vec<User>,

        /// Indicates if the result list has been truncated by the limit.
        pub limited: bool,
    }

    error: crate::Error
}

/// User data as result of a search.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct User {
    /// The user's matrix user ID.
    pub user_id: UserId,

    /// The display name of the user, if one exists.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub display_name: Option<String>,

    /// The avatar url, as an MXC, if one exists.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub avatar_url: Option<String>,
}
<|endoftext|>


<commit_before>use gtk::prelude::*;
use gtk::FileChooserDialog;
use gtk::{Button, DrawingArea, Window, WindowType};
use relm::{DrawHandler, Relm, Update, Widget};

use gol::*;

pub struct MyModel {
    map: Map,
    size: Pos,
    center: Pos,
    scale: i32,
    mouse: Option<Pos>,
    draw_handler: DrawHandler<DrawingArea>,
}

impl MyModel {
    fn new() -> Self {
        MyModel {
            map: Map::acorn(),
            size: pos(500, 300),
            center: pos(0, 0),
            scale: 2,
            mouse: None,
            draw_handler: DrawHandler::new().unwrap(),
        }
    }
}

#[derive(Msg)]
pub enum MyMsg {
    Motion(((f64, f64), gdk::ModifierType)),
    Open,
    Draw,
    Quit,
    Next,
}

pub struct Win {
    window: Window,
    model: MyModel,
}

impl Win {
    fn draw(&mut self, cells: &[Pos], top_left: Pos) {
        let cr = self.model.draw_handler.get_context();
        cr.set_source_rgb(1., 1., 1.);
        cr.paint();
        cr.scale(self.model.scale.into(), self.model.scale.into());
        cr.set_source_rgb(0., 0., 0.);
        for pos in cells {
            cr.rectangle(
                (pos.x - top_left.x).into(),
                (pos.y - top_left.y).into(),
                1.,
                1.,
            );
        }
        cr.fill();
    }
}

impl Update for Win {
    type Model = MyModel;
    type ModelParam = ();
    type Msg = MyMsg;

    fn model(_: &Relm<Self>, _: ()) -> MyModel {
        MyModel::new()
    }

    fn subscriptions(&mut self, relm: &Relm<Self>) {
        relm::interval(relm.stream(), 1000 / 30, || MyMsg::Next);
    }

    fn update(&mut self, event: MyMsg) {
        match event {
            MyMsg::Next => {
                self.model.map.next_generation();
            }
            MyMsg::Draw => {
                let top_left = pos(
                    self.model.center.x - self.model.size.x / 2,
                    self.model.center.y - self.model.size.y / 2,
                );
                let cells = self.model.map.get_alive_cells_in(top_left, self.model.size);
                self.draw(&cells, top_left);
            }
            MyMsg::Open => {
                let dialog = FileChooserDialog::new(
                    Some("Open File"),
                    Some(&self.window),
                    gtk::FileChooserAction::Open,
                );
                let cancel = gtk::ResponseType::Cancel.into();
                let accept = gtk::ResponseType::Accept.into();
                dialog.add_button("Cancel", cancel);
                dialog.add_button("Open", accept);
                if let Ok(p) = std::env::current_dir() {
                    dialog.set_current_folder(p);
                } else if let Some(p) = dirs::home_dir() {
                    dialog.set_current_folder(p);
                }
                if accept == dialog.run() {
                    if let Some(path) = dialog.get_filename() {
                        self.model.map = rle::read_file(path).unwrap();
                        self.model.center = pos(0, 0);
                    }
                }
                dialog.close();
            }
            MyMsg::Motion(((x, y), t)) => {
                let p = pos(x as i32, y as i32);
                if (t & gdk::ModifierType::BUTTON1_MASK).bits() != 0 {
                    if let Some(mut old_pos) = self.model.mouse {
                        let new_center = pos(
                            self.model.center.x + (old_pos.x - p.x) / self.model.scale,
                            self.model.center.y + (old_pos.y - p.y) / self.model.scale,
                        );
                        if new_center.x != self.model.center.x {
                            old_pos.x = p.x;
                        }
                        if new_center.y != self.model.center.y {
                            old_pos.y = p.y;
                        }
                        self.model.center = new_center;
                        self.model.mouse = Some(old_pos);
                    } else {
                        self.model.mouse = Some(p);
                    }
                } else {
                    self.model.mouse = None;
                }
            }
            MyMsg::Quit => gtk::main_quit(),
        }
    }
}

impl Widget for Win {
    type Root = Window;

    fn root(&self) -> Self::Root {
        self.window.clone()
    }

    fn view(relm: &Relm<Self>, mut model: MyModel) -> Self {
        let window = Window::new(WindowType::Toplevel);

        let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
        let button_box = gtk::ButtonBox::new(gtk::Orientation::Vertical);

        let open_button = Button::new_with_label("Open");
        let save_button = Button::new_with_label("Save");
        save_button.set_sensitive(false);

        let area = DrawingArea::new();
        area.set_size_request(model.size.x * model.scale, model.size.y * model.scale);
        area.add_events(gdk::EventMask::POINTER_MOTION_MASK.bits() as i32);
        area.add_events(gdk::EventMask::BUTTON_PRESS_MASK.bits() as i32);
        model.draw_handler.init(&area);

        button_box.set_layout(gtk::ButtonBoxStyle::Start);
        button_box.pack_start(&open_button, false, false, 0);
        button_box.pack_start(&save_button, false, false, 0);
        hbox.pack_start(&area, false, false, 0);
        hbox.pack_start(&button_box, false, false, 0);
        window.add(&hbox);
        window.set_title("Game of Life");
        window.show_all();

        connect!(
            relm,
            window,
            connect_delete_event(_, _),
            return (Some(MyMsg::Quit), Inhibit(false))
        );
        connect!(
            relm,
            area,
            connect_motion_notify_event(_, ev),
            return (
                Some(MyMsg::Motion((ev.get_position(), ev.get_state()))),
                Inhibit(false)
            )
        );
        connect!(relm, open_button, connect_clicked(_), MyMsg::Open);
        connect!(
            relm,
            area,
            connect_draw(_, _),
            return (MyMsg::Draw, Inhibit(false))
        );

        Win { window, model }
    }
}
<commit_msg>do not use draw signal<commit_after>use gtk::prelude::*;
use gtk::FileChooserDialog;
use gtk::{Button, DrawingArea, Window, WindowType};
use relm::{DrawHandler, Relm, Update, Widget};

use gol::*;

pub struct MyModel {
    map: Map,
    size: Pos,
    center: Pos,
    scale: i32,
    mouse: Option<Pos>,
    draw_handler: DrawHandler<DrawingArea>,
}

impl MyModel {
    fn new() -> Self {
        MyModel {
            map: Map::acorn(),
            size: pos(500, 300),
            center: pos(0, 0),
            scale: 2,
            mouse: None,
            draw_handler: DrawHandler::new().unwrap(),
        }
    }
}

#[derive(Msg)]
pub enum MyMsg {
    Motion(((f64, f64), gdk::ModifierType)),
    Open,
    Quit,
    Next,
}

pub struct Win {
    window: Window,
    model: MyModel,
}

impl Win {
    fn draw(&mut self, cells: &[Pos], top_left: Pos) {
        let cr = self.model.draw_handler.get_context();
        cr.set_source_rgb(1., 1., 1.);
        cr.paint();
        cr.scale(self.model.scale.into(), self.model.scale.into());
        cr.set_source_rgb(0., 0., 0.);
        for pos in cells {
            cr.rectangle(
                (pos.x - top_left.x).into(),
                (pos.y - top_left.y).into(),
                1.,
                1.,
            );
        }
        cr.fill();
    }
}

impl Update for Win {
    type Model = MyModel;
    type ModelParam = ();
    type Msg = MyMsg;

    fn model(_: &Relm<Self>, _: ()) -> MyModel {
        MyModel::new()
    }

    fn subscriptions(&mut self, relm: &Relm<Self>) {
        relm::interval(relm.stream(), 1000 / 30, || MyMsg::Next);
    }

    fn update(&mut self, event: MyMsg) {
        match event {
            MyMsg::Next => {
                self.model.map.next_generation();
                let top_left = pos(
                    self.model.center.x - self.model.size.x / 2,
                    self.model.center.y - self.model.size.y / 2,
                );
                let cells = self.model.map.get_alive_cells_in(top_left, self.model.size);
                self.draw(&cells, top_left);
            }
            MyMsg::Open => {
                let dialog = FileChooserDialog::new(
                    Some("Open File"),
                    Some(&self.window),
                    gtk::FileChooserAction::Open,
                );
                let cancel = gtk::ResponseType::Cancel.into();
                let accept = gtk::ResponseType::Accept.into();
                dialog.add_button("Cancel", cancel);
                dialog.add_button("Open", accept);
                if let Ok(p) = std::env::current_dir() {
                    dialog.set_current_folder(p);
                } else if let Some(p) = dirs::home_dir() {
                    dialog.set_current_folder(p);
                }
                if accept == dialog.run() {
                    if let Some(path) = dialog.get_filename() {
                        self.model.map = rle::read_file(path).unwrap();
                        self.model.center = pos(0, 0);
                    }
                }
                dialog.close();
            }
            MyMsg::Motion(((x, y), t)) => {
                let p = pos(x as i32, y as i32);
                if (t & gdk::ModifierType::BUTTON1_MASK).bits() != 0 {
                    if let Some(mut old_pos) = self.model.mouse {
                        let new_center = pos(
                            self.model.center.x + (old_pos.x - p.x) / self.model.scale,
                            self.model.center.y + (old_pos.y - p.y) / self.model.scale,
                        );
                        if new_center.x != self.model.center.x {
                            old_pos.x = p.x;
                        }
                        if new_center.y != self.model.center.y {
                            old_pos.y = p.y;
                        }
                        self.model.center = new_center;
                        self.model.mouse = Some(old_pos);
                    } else {
                        self.model.mouse = Some(p);
                    }
                } else {
                    self.model.mouse = None;
                }
            }
            MyMsg::Quit => gtk::main_quit(),
        }
    }
}

impl Widget for Win {
    type Root = Window;

    fn root(&self) -> Self::Root {
        self.window.clone()
    }

    fn view(relm: &Relm<Self>, mut model: MyModel) -> Self {
        let window = Window::new(WindowType::Toplevel);

        let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
        let button_box = gtk::ButtonBox::new(gtk::Orientation::Vertical);

        let open_button = Button::new_with_label("Open");
        let save_button = Button::new_with_label("Save");
        save_button.set_sensitive(false);

        let area = DrawingArea::new();
        area.set_size_request(model.size.x * model.scale, model.size.y * model.scale);
        area.add_events(gdk::EventMask::POINTER_MOTION_MASK.bits() as i32);
        area.add_events(gdk::EventMask::BUTTON_PRESS_MASK.bits() as i32);
        model.draw_handler.init(&area);

        button_box.set_layout(gtk::ButtonBoxStyle::Start);
        button_box.pack_start(&open_button, false, false, 0);
        button_box.pack_start(&save_button, false, false, 0);
        hbox.pack_start(&area, false, false, 0);
        hbox.pack_start(&button_box, false, false, 0);
        window.add(&hbox);
        window.set_title("Game of Life");
        window.show_all();

        connect!(
            relm,
            window,
            connect_delete_event(_, _),
            return (Some(MyMsg::Quit), Inhibit(false))
        );
        connect!(
            relm,
            area,
            connect_motion_notify_event(_, ev),
            return (
                Some(MyMsg::Motion((ev.get_position(), ev.get_state()))),
                Inhibit(false)
            )
        );
        connect!(relm, open_button, connect_clicked(_), MyMsg::Open);

        Win { window, model }
    }
}
<|endoftext|>


<commit_before>// FIXME To see the "real" compiler error, change both `&'b` and `&'e` into `&`

fn main() { // `'main` starts ────────────────────────────────────────────┐
    let stack_integer = 5; // `'a` starts ──────────────────────────────┐ │
    let boxed_integer = box 4; // `'b` starts ────────────────────────┐ │ │
    //                                                                │ │ │
    // This is a valid operation                                      │ │ │
    let ref_to_box: &'b int = &*boxed_integer; // `'c` starts ──────┐ │ │ │
    //                                                              │ │ │ │
    // The compiler forbids this operation, because                 │ │ │ │
    // `ref_to_another_box` would become a dangling pointer         │ │ │ │
    let ref_to_another_box: &'e int = { // `'let` `'d` start ───┬─┐ │ │ │ │
        let another_boxed_integer = box 3; // `'e` starts ────┐ │ │ │ │ │ │
        //                                                    │ │ │ │ │ │ │
        &*another_boxed_integer //                            │ │ │ │ │ │ │
    }; // `'e` `'let` end ────────────────────────────────────┴─┘ │ │ │ │ │
    //                                                            │ │ │ │ │
    let invalid_dereference = *ref_to_another_box; //             │ │ │ │ │
} // `'d` `'c` `'b` `'a` `'main` end ─────────────────────────────┴─┴─┴─┴─┘
<commit_msg>fix for lifetime/borrow: ambiguous type error Close #148   - Added the explicit type declaration for `stack_integer`   - re-aligned lifetime lines for readability   - Tested successfully on the live site to verify that it works<commit_after>// FIXME To see the "real" compiler error, change both `&'b` and `&'e` into `&`

fn main() { // `'main` starts ────────────────────────────────────────────┐
    let stack_integer: int = 5; // `'a` starts ─────────────────────────┐ │
    let boxed_integer = box 4; // `'b` starts ────────────────────────┐ │ │
    //                                                                │ │ │
    // This is a valid operation                                      │ │ │
    let ref_to_box: &'b int = &*boxed_integer; // `'c` starts ──────┐ │ │ │
    //                                                              │ │ │ │
    // The compiler forbids this operation, because                 │ │ │ │
    // `ref_to_another_box` would become a dangling pointer         │ │ │ │
    let ref_to_another_box: &'e int = { // `'let` `'d` start ───┬─┐ │ │ │ │
        let another_boxed_integer = box 3; // `'e` starts ────┐ │ │ │ │ │ │
        //                                                    │ │ │ │ │ │ │
        &*another_boxed_integer //                            │ │ │ │ │ │ │
    }; // `'e` `'let` end ────────────────────────────────────┴─┘ │ │ │ │ │
    //                                                            │ │ │ │ │
    let invalid_dereference = *ref_to_another_box; //             │ │ │ │ │
} // `'d` `'c` `'b` `'a` `'main` end ─────────────────────────────┴─┴─┴─┴─┘
<|endoftext|>


<commit_before>use arc = std::arc;
use arc::ARC;
use au = gfx::geometry;
use font::{RunMetrics, Font};
use font_cache::FontCache;
use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::au;
use glyph::GlyphStore;
use layout::context::LayoutContext;
use libc::{c_void};
use servo_util::color;
use shaper::shape_textrun;
use std::arc;

pub struct TextRun {
    text: ~str,
    font: @Font,
    priv glyphs: GlyphStore,
}

pub struct TextRange {
    priv off: u16,
    priv len: u16
}

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

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

impl TextRange {
    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(i: int) -> TextRange {
        TextRange(((self.off as int) + i) as uint, self.len as uint)
    }

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

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

// This is a hack until TextRuns are normally sendable, or
// we instead use ARC<TextRun> everywhere.
pub struct SendableTextRun {
    text: ~str,
    font_descriptor: (),
    priv glyphs: GlyphStore,
}

pub fn serialize(_cache: @FontCache, run: &TextRun) -> ~SendableTextRun {
    ~SendableTextRun {
        text: copy run.text,
        // TODO: actually serialize a font descriptor thingy
        font_descriptor: (),
        glyphs: copy run.glyphs,
    }
}

pub fn deserialize(cache: @FontCache, run: &SendableTextRun) -> @TextRun {
    @TextRun {
        text: copy run.text,
        // TODO: actually deserialize a font descriptor thingy
        font: cache.get_test_font(),
        glyphs: copy run.glyphs
    }
}

trait TextRunMethods {
    pure fn glyphs(&self) -> &self/GlyphStore;
    pure fn iter_indivisible_pieces_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool);
    // TODO: needs to take box style as argument, or move to TextBox.
    // see Gecko's IsTrimmableSpace methods for details.
    pure fn range_is_trimmable_whitespace(&self, range: TextRange) -> bool;

    fn metrics_for_range(&self, range: TextRange) -> RunMetrics;
    fn min_width_for_range(&self, range: TextRange) -> au;
    fn iter_natural_lines_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool);
}

impl TextRun : TextRunMethods {
    pure fn glyphs(&self) -> &self/GlyphStore { &self.glyphs }

    pure fn range_is_trimmable_whitespace(&self, range: TextRange) -> bool {
        let mut i = range.begin();
        while i < range.end() {
            // jump i to each new char
            let {ch, next} = str::char_range_at(self.text, i);
            match ch {
                ' ' | '\t' | '\r'  => {},
                _ => { return false; }
            }
            i = next;
        }
        return true;
    }

    fn metrics_for_range(&self, range: TextRange) -> RunMetrics {
        self.font.measure_text(self, range.begin(), range.length())
    }

    fn min_width_for_range(&self, range: TextRange) -> au {
        assert range.is_valid_for_string(self.text);

        let mut max_piece_width = au(0);
        for self.iter_indivisible_pieces_for_range(range) |piece_offset, piece_len| {
            let metrics = self.font.measure_text(self, piece_offset, piece_len);
            max_piece_width = au::max(max_piece_width, metrics.advance_width);
        }
        return max_piece_width;
    }

    fn iter_natural_lines_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool) {
        assert range.is_valid_for_string(self.text);

        let mut clump_offset = range.begin();
        let mut clump_length = 0;
        let mut in_clump = false;

        // clump non-linebreaks of nonzero length
        for range.eachi |i| {
            match (self.glyphs.char_is_newline(i), in_clump) {
                (false, true)  => { clump_length += 1; }
                (false, false) => { in_clump = true; clump_offset = i; clump_length = 1; }
                (true, false) => { /* chomp whitespace */ }
                (true, true)  => {
                    in_clump = false;
                    // don't include the linebreak 'glyph'
                    // (we assume there's one GlyphEntry for a newline, and no actual glyphs)
                    if !f(clump_offset, clump_length) { break }
                }
            }
        }

        // flush any remaining chars as a line
        if in_clump {
            clump_length = range.end() - clump_offset;
            f(clump_offset, clump_length);
        }
    }

    pure fn iter_indivisible_pieces_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool) {
        assert range.is_valid_for_string(self.text);

        let mut clump_offset = range.begin();
        let mut clump_length;

        loop {
            // find next non-whitespace byte index, then clump all whitespace before it.
            match str::find_from(self.text, clump_offset, |c| !char::is_whitespace(c)) {
                Some(nonws_char_offset) => {
                    clump_length = nonws_char_offset - clump_offset;
                    if !f(clump_offset, clump_length) { break }
                    clump_offset += clump_length;
                    // reached end
                    if clump_offset == range.end() { break }
                },
                None => {
                    // nothing left, flush last piece containing only whitespace
                    if clump_offset < range.end() {
                        let clump_length = range.end() - clump_offset;
                        f(clump_offset, clump_length);
                    }
                    break
                }
            };

            // find next whitespace byte index, then clump all non-whitespace before it.
            match str::find_from(self.text, clump_offset, |c| char::is_whitespace(c)) {
                Some(ws_char_offset) => {
                    clump_length = ws_char_offset - clump_offset;
                    if !f(clump_offset, clump_length) { break }
                    clump_offset += clump_length;
                    // reached end
                    if clump_offset == range.end() { break }
                }
                None => {
                    // nothing left, flush last piece containing only non-whitespaces
                    if clump_offset < range.end() {
                        let clump_length = range.end() - clump_offset;
                        f(clump_offset, clump_length);
                    }
                    break
                }
            }
        }
    }
}

fn TextRun(font: @Font, text: ~str) -> TextRun {
    let glyph_store = GlyphStore(text.len());
    let run = TextRun {
        text: text,
        font: font,
        glyphs: glyph_store,
    };

    shape_textrun(&run);
    return run;
}

// this test can't run until LayoutContext is removed as an argument
// to min_width_for_range.
/*
#[test]
fn test_calc_min_break_width() {

    fn test_min_width_for_run(text: ~str, width: au) {
        let flib = FontCache();
        let font = flib.get_test_font();
        let run = TextRun(font, text);
        run.min_width_for_range(0, text.len())
    }

    test_min_width_for_run(~"firecracker", au::from_px(84));
    test_min_width_for_run(~"firecracker yumyum", au::from_px(84));
    test_min_width_for_run(~"yumyum firecracker", au::from_px(84));
    test_min_width_for_run(~"yumyum firecracker yumyum", au::from_px(84));
}
*/

#[test]
#[ignore]
fn test_iter_indivisible_pieces() {
    fn test_pieces(text: ~str, res: ~[~str]) {
        let flib = FontCache();
        let font = flib.get_test_font();
        let run = TextRun(font, copy text);
        let mut slices : ~[~str] = ~[];
        for run.iter_indivisible_pieces_for_range(TextRange(0, text.len())) |offset, length| {
            slices.push(str::slice(text, offset, length));
        }
        assert slices == res;
    }

    test_pieces(~"firecracker yumyum woopwoop", ~[~"firecracker", ~" ", ~"yumyum", ~" ", ~"woopwoop"]);
    test_pieces(~"firecracker yumyum     ", ~[~"firecracker", ~" ", ~"yumyum", ~"     "]);
    test_pieces(~"     firecracker yumyum", ~[~"     ", ~"firecracker", ~" ", ~"yumyum"]);
    test_pieces(~"  ", ~[~"  "]);
    test_pieces(~"", ~[]);
}

<commit_msg>More TextRange conversions.<commit_after>use arc = std::arc;
use arc::ARC;
use au = gfx::geometry;
use font::{RunMetrics, Font};
use font_cache::FontCache;
use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::au;
use glyph::GlyphStore;
use layout::context::LayoutContext;
use libc::{c_void};
use servo_util::color;
use shaper::shape_textrun;
use std::arc;

pub struct TextRun {
    text: ~str,
    font: @Font,
    priv glyphs: GlyphStore,
}

pub struct TextRange {
    priv off: u16,
    priv len: u16
}

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

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

impl TextRange {
    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) -> TextRange {
        TextRange(((self.off as int) + i) as uint, self.len as uint)
    }

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

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

pub struct MutableTextRange {
    priv mut off: uint,
    priv mut len: uint
}

pure fn MutableTextRange(off: uint, len :uint) -> MutableTextRange {
    MutableTextRange { off: off, len: len }
}

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

    pub pure fn as_immutable() -> TextRange {
        TextRange(self.begin(), self.length())
    }

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

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

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

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

    pub fn adjust_by(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;
    }

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

// This is a hack until TextRuns are normally sendable, or
// we instead use ARC<TextRun> everywhere.
pub struct SendableTextRun {
    text: ~str,
    font_descriptor: (),
    priv glyphs: GlyphStore,
}

pub fn serialize(_cache: @FontCache, run: &TextRun) -> ~SendableTextRun {
    ~SendableTextRun {
        text: copy run.text,
        // TODO: actually serialize a font descriptor thingy
        font_descriptor: (),
        glyphs: copy run.glyphs,
    }
}

pub fn deserialize(cache: @FontCache, run: &SendableTextRun) -> @TextRun {
    @TextRun {
        text: copy run.text,
        // TODO: actually deserialize a font descriptor thingy
        font: cache.get_test_font(),
        glyphs: copy run.glyphs
    }
}

trait TextRunMethods {
    pure fn glyphs(&self) -> &self/GlyphStore;
    fn iter_indivisible_pieces_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool);
    // TODO: needs to take box style as argument, or move to TextBox.
    // see Gecko's IsTrimmableSpace methods for details.
    pure fn range_is_trimmable_whitespace(&self, range: TextRange) -> bool;

    fn metrics_for_range(&self, range: TextRange) -> RunMetrics;
    fn min_width_for_range(&self, range: TextRange) -> au;
    fn iter_natural_lines_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool);
}

impl TextRun : TextRunMethods {
    pure fn glyphs(&self) -> &self/GlyphStore { &self.glyphs }

    pure fn range_is_trimmable_whitespace(&self, range: TextRange) -> bool {
        let mut i = range.begin();
        while i < range.end() {
            // jump i to each new char
            let {ch, next} = str::char_range_at(self.text, i);
            match ch {
                ' ' | '\t' | '\r'  => {},
                _ => { return false; }
            }
            i = next;
        }
        return true;
    }

    fn metrics_for_range(&self, range: TextRange) -> RunMetrics {
        self.font.measure_text(self, range.begin(), range.length())
    }

    fn min_width_for_range(&self, range: TextRange) -> au {
        assert range.is_valid_for_string(self.text);

        let mut max_piece_width = au(0);
        for self.iter_indivisible_pieces_for_range(range) |piece_offset, piece_len| {
            let metrics = self.font.measure_text(self, piece_offset, piece_len);
            max_piece_width = au::max(max_piece_width, metrics.advance_width);
        }
        return max_piece_width;
    }

    fn iter_natural_lines_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool) {
        assert range.is_valid_for_string(self.text);

        let clump = MutableTextRange(range.begin(), 0);
        let mut in_clump = false;

        // clump non-linebreaks of nonzero length
        for range.eachi |i| {
            match (self.glyphs.char_is_newline(i), in_clump) {
                (false, true)  => { clump.extend_by(1); }
                (false, false) => { in_clump = true; clump.reset(i, 1); }
                (true, false) => { /* chomp whitespace */ }
                (true, true)  => {
                    in_clump = false;
                    // don't include the linebreak 'glyph'
                    // (we assume there's one GlyphEntry for a newline, and no actual glyphs)
                    if !f(clump.begin(), clump.length()) { break }
                }
            }
        }

        // flush any remaining chars as a line
        if in_clump {
            clump.extend_to(range.end());
            f(clump.begin(), clump.length());
        }
    }

    fn iter_indivisible_pieces_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool) {
        assert range.is_valid_for_string(self.text);

        let clump = MutableTextRange(range.begin(), 0);

        loop {
            // find next non-whitespace byte index, then clump all whitespace before it.
            if clump.end() == range.end() { break }
            match str::find_from(self.text, clump.begin(), |c| !char::is_whitespace(c)) {
                Some(nonws_char_offset) => {
                    clump.extend_to(nonws_char_offset);
                    if !f(clump.begin(), clump.length()) { break }
                    clump.reset(clump.end(), 0);
                },
                None => {
                    // nothing left, flush last piece containing only whitespace
                    if clump.end() < range.end() {
                        clump.extend_to(range.end());
                        f(clump.begin(), clump.length());
                    }
                }
            };

            // find next whitespace byte index, then clump all non-whitespace before it.
            if clump.end() == range.end() { break }
            match str::find_from(self.text, clump.begin(), |c| char::is_whitespace(c)) {
                Some(ws_char_offset) => {
                    clump.extend_to(ws_char_offset);
                    if !f(clump.begin(), clump.length()) { break }
                    clump.reset(clump.end(), 0);
                }
                None => {
                    // nothing left, flush last piece containing only non-whitespaces
                    if clump.end() < range.end() {
                        clump.extend_to(range.end());
                        f(clump.begin(), clump.length());
                    }
                }
            }
        }
    }
}

fn TextRun(font: @Font, text: ~str) -> TextRun {
    let glyph_store = GlyphStore(text.len());
    let run = TextRun {
        text: text,
        font: font,
        glyphs: glyph_store,
    };

    shape_textrun(&run);
    return run;
}

// this test can't run until LayoutContext is removed as an argument
// to min_width_for_range.
/*
#[test]
fn test_calc_min_break_width() {

    fn test_min_width_for_run(text: ~str, width: au) {
        let flib = FontCache();
        let font = flib.get_test_font();
        let run = TextRun(font, text);
        run.min_width_for_range(0, text.len())
    }

    test_min_width_for_run(~"firecracker", au::from_px(84));
    test_min_width_for_run(~"firecracker yumyum", au::from_px(84));
    test_min_width_for_run(~"yumyum firecracker", au::from_px(84));
    test_min_width_for_run(~"yumyum firecracker yumyum", au::from_px(84));
}
*/

#[test]
#[ignore]
fn test_iter_indivisible_pieces() {
    fn test_pieces(text: ~str, res: ~[~str]) {
        let flib = FontCache();
        let font = flib.get_test_font();
        let run = TextRun(font, copy text);
        let mut slices : ~[~str] = ~[];
        for run.iter_indivisible_pieces_for_range(TextRange(0, text.len())) |offset, length| {
            slices.push(str::slice(text, offset, length));
        }
        assert slices == res;
    }

    test_pieces(~"firecracker yumyum woopwoop", ~[~"firecracker", ~" ", ~"yumyum", ~" ", ~"woopwoop"]);
    test_pieces(~"firecracker yumyum     ", ~[~"firecracker", ~" ", ~"yumyum", ~"     "]);
    test_pieces(~"     firecracker yumyum", ~[~"     ", ~"firecracker", ~" ", ~"yumyum"]);
    test_pieces(~"  ", ~[~"  "]);
    test_pieces(~"", ~[]);
}

<|endoftext|>