<commit_before>
use std::rc;
use std::cell;

use text;
use modifier;
use event;
use builder;
use transform;

use super::{ Shared };

type SharedPeek<S> = Shared<modifier::Peek<modifier::Expand<S>>>;

/// Select an elements contents.
pub struct SelectContent<S, B>
where
    S: event::ElementStream,
    B: builder::BuildOnce<CurrentContent<S>>,
{
    state: modifier::State<SelectContentState<S, B>>,
}

impl<S, B> SelectContent<S, B>
where
    S: event::ElementStream,
    B: builder::BuildOnce<CurrentContent<S>>,
{
    pub(crate) fn new(source: S, builder: B) -> SelectContent<S, B> {
        let source = modifier::Expand::new(source);
        SelectContent {
            state: modifier::State::new(SelectContentState::Open { source, builder }),
        }
    }
}

impl<S, B> event::ElementStream for SelectContent<S, B>
where
    S: event::ElementStream,
    B: builder::BuildOnce<CurrentContent<S>>,
{}

impl<S, B> event::Stream for SelectContent<S, B>
where
    S: event::ElementStream,
    B: builder::BuildOnce<CurrentContent<S>>,
{
    fn next_event(&mut self) -> event::StreamResult {
        self.state.step(|state| match state {
            SelectContentState::Open { mut source, builder } => {
                let event = match source.next_event_skip_noop()? {
                    Some(event) => event,
                    None => return Err(event::StreamError::expected_open(None)),
                };
                let tag = match event {
                    event::Event(event::EventKind::OpeningTag { ref tag, .. }) => tag.clone(),
                    event::Event(event::EventKind::VoidTag { tag, attributes }) =>
                        return Ok(Some((event::void(tag, attributes), None))),
                    other => return Err(event::StreamError::expected_open(Some(other))),
                };
                let source = rc::Rc::new(cell::RefCell::new(
                    modifier::Peek::new(source),
                ));
                let stream = transform::build_once(
                    CurrentContent::new(source.clone(), tag.clone()),
                    builder,
                );
                Ok(Some((event, Some(SelectContentState::Content { source, stream, tag }))))
            },
            SelectContentState::Content { source, mut stream, tag } =>
                match stream.next_event()? {
                    None => Ok(Some((
                        event::noop(),
                        Some(SelectContentState::Close { source, tag }),
                    ))),
                    Some(event) => Ok(Some((
                        event,
                        Some(SelectContentState::Content { source, stream, tag }),
                    ))),
                },
            SelectContentState::Close { mut source, tag } => {
                let event = match source.next_event_skip_noop()? {
                    Some(event::Event(event::EventKind::ClosingTag { tag: closed_tag })) =>
                        if closed_tag == tag {
                            event::close(closed_tag)
                        } else {
                            return Err(
                                event::StreamError::unexpected_close(closed_tag)
                            );
                        },
                    other => return Err(
                        event::StreamError::expected_close(other, tag),
                    ),
                };
                Ok(Some((event, None)))
            },
        })
    }
}

enum SelectContentState<S, B>
where
    S: event::ElementStream,
    B: builder::BuildOnce<CurrentContent<S>>,
{
    Open {
        source: modifier::Expand<S>,
        builder: B,
    },
    Content {
        source: SharedPeek<S>,
        stream: B::Stream,
        tag: text::Identifier,
    },
    Close {
        source: SharedPeek<S>,
        tag: text::Identifier,
    },
}

/// Stream containing the contents of the current element.
pub struct CurrentContent<S> {
    state: modifier::State<CurrentContentState<S>>,
}

impl<S> CurrentContent<S> where S: event::Stream {

    fn new(stream: SharedPeek<S>, tag: text::Identifier) -> CurrentContent<S> {
        CurrentContent {
            state: modifier::State::new(CurrentContentState {
                tag,
                stream,
                level: modifier::Level::new(),
            }),
        }
    }
}

fn has_reached_end<S: event::Stream>(
    stream: &mut SharedPeek<S>,
    level: &modifier::Level,
    tag: &text::Identifier,
) -> Result<bool, event::StreamError> {
    if !level.is_top_level() {
        return Ok(false);
    }
    match stream.borrow_mut().peek(|event| event.is_closing_tag_for(tag))? {
        Some(value) => Ok(value),
        None => Err(event::StreamError::missing_close(tag.clone())),
    }
}

impl<S> event::Stream for CurrentContent<S> where S: event::Stream {

    fn next_event(&mut self) -> event::StreamResult {
        self.state.step(|CurrentContentState { tag, mut stream, level }| {
            if has_reached_end(&mut stream, &level, &tag)? {
                return Ok(None);
            }
            let event = match stream.next_event()? {
                Some(event) => event,
                None => return Err(event::StreamError::missing_close(tag)),
            };
            let level = level.adjust(&event)
                .map_err(|_| event::StreamError::missing_close(tag.clone()))?;
            Ok(Some((event, Some(CurrentContentState { tag, level, stream }))))
        })
    }
}

struct CurrentContentState<S> {
    tag: text::Identifier,
    stream: SharedPeek<S>,
    level: modifier::Level,
}

#[cfg(test)]
mod tests {

    test_group!(select_contents:
        "remove" => transform_test!(
            "2345<c>67</c>89",
            "45<c>67</c>",
            |html| html.select("b", |html| html.subselect_contents(|html| html.remove())),
        ),
    );
}
<commit_msg>added element stream tests to subselect_contents<commit_after>
use std::rc;
use std::cell;

use text;
use modifier;
use event;
use builder;
use transform;

use super::{ Shared };

type SharedPeek<S> = Shared<modifier::Peek<modifier::Expand<S>>>;

/// Select an elements contents.
pub struct SelectContent<S, B>
where
    S: event::ElementStream,
    B: builder::BuildOnce<CurrentContent<S>>,
{
    state: modifier::State<SelectContentState<S, B>>,
}

impl<S, B> SelectContent<S, B>
where
    S: event::ElementStream,
    B: builder::BuildOnce<CurrentContent<S>>,
{
    pub(crate) fn new(source: S, builder: B) -> SelectContent<S, B> {
        let source = modifier::Expand::new(source);
        SelectContent {
            state: modifier::State::new(SelectContentState::Open { source, builder }),
        }
    }
}

impl<S, B> event::ElementStream for SelectContent<S, B>
where
    S: event::ElementStream,
    B: builder::BuildOnce<CurrentContent<S>>,
{}

impl<S, B> event::Stream for SelectContent<S, B>
where
    S: event::ElementStream,
    B: builder::BuildOnce<CurrentContent<S>>,
{
    fn next_event(&mut self) -> event::StreamResult {
        self.state.step(|state| match state {
            SelectContentState::Open { mut source, builder } => {
                let event = match source.next_event_skip_noop()? {
                    Some(event) => event,
                    None => return Err(event::StreamError::expected_open(None)),
                };
                let tag = match event {
                    event::Event(event::EventKind::OpeningTag { ref tag, .. }) => tag.clone(),
                    event::Event(event::EventKind::VoidTag { tag, attributes }) =>
                        return Ok(Some((event::void(tag, attributes), None))),
                    other => return Err(event::StreamError::expected_open(Some(other))),
                };
                let source = rc::Rc::new(cell::RefCell::new(
                    modifier::Peek::new(source),
                ));
                let stream = transform::build_once(
                    CurrentContent::new(source.clone(), tag.clone()),
                    builder,
                );
                Ok(Some((event, Some(SelectContentState::Content { source, stream, tag }))))
            },
            SelectContentState::Content { source, mut stream, tag } =>
                match stream.next_event()? {
                    None => Ok(Some((
                        event::noop(),
                        Some(SelectContentState::Close { source, tag }),
                    ))),
                    Some(event) => Ok(Some((
                        event,
                        Some(SelectContentState::Content { source, stream, tag }),
                    ))),
                },
            SelectContentState::Close { mut source, tag } => {
                let event = match source.next_event_skip_noop()? {
                    Some(event::Event(event::EventKind::ClosingTag { tag: closed_tag })) =>
                        if closed_tag == tag {
                            event::close(closed_tag)
                        } else {
                            return Err(
                                event::StreamError::unexpected_close(closed_tag)
                            );
                        },
                    other => return Err(
                        event::StreamError::expected_close(other, tag),
                    ),
                };
                Ok(Some((event, None)))
            },
        })
    }
}

enum SelectContentState<S, B>
where
    S: event::ElementStream,
    B: builder::BuildOnce<CurrentContent<S>>,
{
    Open {
        source: modifier::Expand<S>,
        builder: B,
    },
    Content {
        source: SharedPeek<S>,
        stream: B::Stream,
        tag: text::Identifier,
    },
    Close {
        source: SharedPeek<S>,
        tag: text::Identifier,
    },
}

/// Stream containing the contents of the current element.
pub struct CurrentContent<S> {
    state: modifier::State<CurrentContentState<S>>,
}

impl<S> CurrentContent<S> where S: event::Stream {

    fn new(stream: SharedPeek<S>, tag: text::Identifier) -> CurrentContent<S> {
        CurrentContent {
            state: modifier::State::new(CurrentContentState {
                tag,
                stream,
                level: modifier::Level::new(),
            }),
        }
    }
}

fn has_reached_end<S: event::Stream>(
    stream: &mut SharedPeek<S>,
    level: &modifier::Level,
    tag: &text::Identifier,
) -> Result<bool, event::StreamError> {
    if !level.is_top_level() {
        return Ok(false);
    }
    match stream.borrow_mut().peek(|event| event.is_closing_tag_for(tag))? {
        Some(value) => Ok(value),
        None => Err(event::StreamError::missing_close(tag.clone())),
    }
}

impl<S> event::Stream for CurrentContent<S> where S: event::Stream {

    fn next_event(&mut self) -> event::StreamResult {
        self.state.step(|CurrentContentState { tag, mut stream, level }| {
            if has_reached_end(&mut stream, &level, &tag)? {
                return Ok(None);
            }
            let event = match stream.next_event()? {
                Some(event) => event,
                None => return Err(event::StreamError::missing_close(tag)),
            };
            let level = level.adjust(&event)
                .map_err(|_| event::StreamError::missing_close(tag.clone()))?;
            Ok(Some((event, Some(CurrentContentState { tag, level, stream }))))
        })
    }
}

struct CurrentContentState<S> {
    tag: text::Identifier,
    stream: SharedPeek<S>,
    level: modifier::Level,
}

#[cfg(test)]
mod tests {

    test_group!(subselect_contents:
        "remove" => transform_test!(
            "2345<c>67</c>89",
            "45<c>67</c>",
            |html| html.select("b", |html| html.subselect_contents(|html| html.remove())),
        ),
        "ensure element stream" => transform_test!(
            "2345<c>67</c>89",
            "2345<c>67</c>89",
            |html| html.select("b", |html| html
                .subselect_contents(|html| html)
                .into_boxed_element()
            ),
        ),
    );
}
<|endoftext|>


<commit_before>/* Code to handle method lookups (which can be quite complex) */

import syntax::ast_map;
import regionmanip::universally_quantify_from_sty;
import middle::typeck::infer::methods; // next_ty_vars

enum lookup = {
    fcx: @fn_ctxt,
    expr: @ast::expr, // expr for a.b in a.b()
    node_id: ast::node_id, // node id of call (not always expr.id)
    m_name: ast::ident, // b in a.b(...)
    self_ty: ty::t, // type of a in a.b(...)
    supplied_tps: [ty::t], // Xs in a.b::<Xs>(...)
    include_private: bool
};

impl methods for lookup {
    // Entrypoint:
    fn method() -> option<method_origin> {
        // First, see whether this is an interface-bounded parameter
        let pass1 = alt ty::get(self.self_ty).struct {
          ty::ty_param(n, did) {
            self.method_from_param(n, did)
          }
          ty::ty_iface(did, substs) {
            self.method_from_iface(did, substs)
          }
          ty::ty_class(did, substs) {
            self.method_from_class(did, substs)
          }
          _ {
            none
          }
        };

        alt pass1 {
          some(r) { some(r) }
          none { self.method_from_scope() }
        }
    }

    fn tcx() -> ty::ctxt { self.fcx.ccx.tcx }

    fn method_from_param(n: uint, did: ast::def_id) -> option<method_origin> {
        let tcx = self.tcx();
        let mut iface_bnd_idx = 0u; // count only iface bounds
        let bounds = tcx.ty_param_bounds.get(did.node);
        let mut candidates = [];
        for vec::each(*bounds) {|bound|
            let (iid, bound_substs) = alt bound {
              ty::bound_copy | ty::bound_send | ty::bound_const {
                cont; /* ok */
              }
              ty::bound_iface(bound_t) {
                alt check ty::get(bound_t).struct {
                  ty::ty_iface(i, substs) { (i, substs) }
                }
              }
            };

            let ifce_methods = ty::iface_methods(tcx, iid);
            alt vec::position(*ifce_methods, {|m| m.ident == self.m_name}) {
              none {
                /* check next bound */
                iface_bnd_idx += 1u;
              }

              some(pos) {
                // Replace any appearance of `self` with the type of the
                // generic parameter itself.  Note that this is the only case
                // where this replacement is necessary: in all other cases, we
                // are either invoking a method directly from an impl or class
                // (where the self type is not permitted), or from a iface
                // type (in which case methods that refer to self are not
                // permitted).
                let substs = {self_ty: some(self.self_ty)
                              with bound_substs};
                candidates += [(substs, ifce_methods[pos],
                                iid, pos, n, iface_bnd_idx)];
              }
            }
        }

        if candidates.len() == 0u {
            ret none;
        }

        if candidates.len() > 1u {
            self.tcx().sess.span_err(
                self.expr.span,
                "multiple applicable methods in scope");

            for candidates.eachi { |i, candidate|
                let (_, _, iid, _, _, _) = candidate;
                self.tcx().sess.span_note(
                    self.expr.span,
                    #fmt["candidate #%u derives from the bound `%s`",
                         (i+1u), ty::item_path_str(self.tcx(), iid)]);
            }
        }

        let (substs, mty, iid, pos, n, iface_bnd_idx) = candidates[0u];
        ret some(self.write_mty_from_m(
            substs, mty, method_param(iid, pos, n, iface_bnd_idx)));
    }

    fn method_from_iface(
        did: ast::def_id, iface_substs: ty::substs) -> option<method_origin> {

        let ms = *ty::iface_methods(self.tcx(), did);
        for ms.eachi {|i, m|
            if m.ident != self.m_name { cont; }

            let m_fty = ty::mk_fn(self.tcx(), m.fty);

            if ty::type_has_self(m_fty) {
                self.tcx().sess.span_err(
                    self.expr.span,
                    "can not call a method that contains a \
                     self type through a boxed iface");
            }

            if (*m.tps).len() > 0u {
                self.tcx().sess.span_err(
                    self.expr.span,
                    "can not call a generic method through a \
                     boxed iface");
            }

            // Note: although it is illegal to invoke a method that uses self
            // through a iface instance, we use a dummy subst here so that we
            // can soldier on with the compilation.
            let substs = {self_ty: some(self.self_ty)
                          with iface_substs};

            ret some(self.write_mty_from_m(
                substs, m, method_iface(did, i)));
        }

        ret none;
    }

    fn method_from_class(did: ast::def_id, class_substs: ty::substs)
        -> option<method_origin> {

        let ms = *ty::iface_methods(self.tcx(), did);

        for ms.each {|m|
            if m.ident != self.m_name { cont; }

            if m.vis == ast::private && !self.include_private {
                self.tcx().sess.span_fatal(
                    self.expr.span,
                    "Call to private method not allowed outside \
                     its defining class");
            }

            // look up method named <name>.
            let m_declared = ty::lookup_class_method_by_name(
                self.tcx(), did, self.m_name, self.expr.span);

            ret some(self.write_mty_from_m(
                class_substs, m,
                method_static(m_declared)));
        }

        ret none;
    }

    fn ty_from_did(did: ast::def_id) -> ty::t {
        alt check ty::get(ty::lookup_item_type(self.tcx(), did).ty).struct {
          ty::ty_fn(fty) {
            ty::mk_fn(self.tcx(), {proto: ast::proto_box with fty})
          }
        }
        /*
        if did.crate == ast::local_crate {
            alt check self.tcx().items.get(did.node) {
              ast_map::node_method(m, _, _) {
                // NDM iface/impl regions
                let mt = ty_of_method(self.fcx.ccx, m, ast::rp_none);
                ty::mk_fn(self.tcx(), {proto: ast::proto_box with mt.fty})
              }
            }
        } else {
            alt check ty::get(csearch::get_type(self.tcx(), did).ty).struct {
              ty::ty_fn(fty) {
                ty::mk_fn(self.tcx(), {proto: ast::proto_box with fty})
              }
            }
        }
        */
    }

    fn method_from_scope() -> option<method_origin> {
        let impls_vecs = self.fcx.ccx.impl_map.get(self.expr.id);

        for list::each(impls_vecs) {|impls|
            let mut results = [];
            for vec::each(*impls) {|im|
                // Check whether this impl has a method with the right name.
                for im.methods.find({|m| m.ident == self.m_name}).each {|m|

                    // determine the `self` with fresh variables for
                    // each parameter:
                    let {substs: self_substs, ty: self_ty} =
                        impl_self_ty(self.fcx, im.did);

                    // Here "self" refers to the callee side...
                    let self_ty =
                        universally_quantify_from_sty(
                            self.fcx, self.expr.span, [self_ty],
                            ty::get(self_ty).struct);

                    // ... and "ty" refers to the caller side.
                    let ty = self.self_ty;

                    // if we can assign the caller to the callee, that's a
                    // potential match.  Collect those in the vector.
                    alt self.fcx.can_mk_subty(ty, self_ty) {
                      result::err(_) { /* keep looking */ }
                      result::ok(_) {
                        results += [(ty, self_ty, self_substs,
                                     m.n_tps, m.did)];
                      }
                    }
                }
            }

            if results.len() >= 1u {
                if results.len() > 1u {
                    self.tcx().sess.span_err(
                        self.expr.span,
                        "multiple applicable methods in scope");

                    // I would like to print out how each impl was imported,
                    // but I cannot for the life of me figure out how to
                    // annotate resolve to preserve this information.
                    for results.eachi { |i, result|
                        let (_, _, _, _, did) = result;
                        let span = if did.crate == ast::local_crate {
                            alt check self.tcx().items.get(did.node) {
                              ast_map::node_method(m, _, _) { m.span }
                            }
                        } else {
                            self.expr.span
                        };
                        self.tcx().sess.span_note(
                            span,
                            #fmt["candidate #%u is `%s`",
                                 (i+1u),
                                 ty::item_path_str(self.tcx(), did)]);
                    }
                }

                let (ty, self_ty, self_substs, n_tps, did) = results[0];
                alt self.fcx.mk_subty(ty, self_ty) {
                  result::ok(_) {}
                  result::err(_) {
                    self.tcx().sess.span_bug(
                        self.expr.span,
                        "what was a subtype now is not?");
                  }
                }
                let fty = self.ty_from_did(did);
                ret some(self.write_mty_from_fty(
                    self_substs, n_tps, fty,
                    method_static(did)));
            }
        }

        ret none;
    }

    fn write_mty_from_m(self_substs: ty::substs,
                        m: ty::method,
                        origin: method_origin) -> method_origin {
        let tcx = self.fcx.ccx.tcx;

        // a bit hokey, but the method unbound has a bare protocol, whereas
        // a.b has a protocol like fn@() (perhaps eventually fn&()):
        let fty = ty::mk_fn(tcx, {proto: ast::proto_box with m.fty});

        ret self.write_mty_from_fty(self_substs, (*m.tps).len(),
                                    fty, origin);
    }

    fn write_mty_from_fty(self_substs: ty::substs,
                          n_tps_m: uint,
                          fty: ty::t,
                          origin: method_origin) -> method_origin {

        let tcx = self.fcx.ccx.tcx;

        // Here I will use the "c_" prefix to refer to the method's
        // owner.  You can read it as class, but it may also be an iface.

        let n_tps_supplied = self.supplied_tps.len();
        let m_substs = {
            if n_tps_supplied == 0u {
                self.fcx.infcx.next_ty_vars(n_tps_m)
            } else if n_tps_m == 0u {
                tcx.sess.span_err(
                    self.expr.span,
                    "this method does not take type parameters");
                self.fcx.infcx.next_ty_vars(n_tps_m)
            } else if n_tps_supplied != n_tps_m {
                tcx.sess.span_err(
                    self.expr.span,
                    "incorrect number of type \
                     parameters given for this method");
                self.fcx.infcx.next_ty_vars(n_tps_m)
            } else {
                self.supplied_tps
            }
        };

        let all_substs = {tps: self_substs.tps + m_substs
                          with self_substs};

        self.fcx.write_ty_substs(self.node_id, fty, all_substs);

        ret origin;
    }
}

<commit_msg>remove useless invocations of universally_quantify_from_sty() in method lookup<commit_after>/* Code to handle method lookups (which can be quite complex) */

import syntax::ast_map;
import regionmanip::universally_quantify_from_sty;
import middle::typeck::infer::methods; // next_ty_vars

enum lookup = {
    fcx: @fn_ctxt,
    expr: @ast::expr, // expr for a.b in a.b()
    node_id: ast::node_id, // node id of call (not always expr.id)
    m_name: ast::ident, // b in a.b(...)
    self_ty: ty::t, // type of a in a.b(...)
    supplied_tps: [ty::t], // Xs in a.b::<Xs>(...)
    include_private: bool
};

impl methods for lookup {
    // Entrypoint:
    fn method() -> option<method_origin> {
        // First, see whether this is an interface-bounded parameter
        let pass1 = alt ty::get(self.self_ty).struct {
          ty::ty_param(n, did) {
            self.method_from_param(n, did)
          }
          ty::ty_iface(did, substs) {
            self.method_from_iface(did, substs)
          }
          ty::ty_class(did, substs) {
            self.method_from_class(did, substs)
          }
          _ {
            none
          }
        };

        alt pass1 {
          some(r) { some(r) }
          none { self.method_from_scope() }
        }
    }

    fn tcx() -> ty::ctxt { self.fcx.ccx.tcx }

    fn method_from_param(n: uint, did: ast::def_id) -> option<method_origin> {
        let tcx = self.tcx();
        let mut iface_bnd_idx = 0u; // count only iface bounds
        let bounds = tcx.ty_param_bounds.get(did.node);
        let mut candidates = [];
        for vec::each(*bounds) {|bound|
            let (iid, bound_substs) = alt bound {
              ty::bound_copy | ty::bound_send | ty::bound_const {
                cont; /* ok */
              }
              ty::bound_iface(bound_t) {
                alt check ty::get(bound_t).struct {
                  ty::ty_iface(i, substs) { (i, substs) }
                }
              }
            };

            let ifce_methods = ty::iface_methods(tcx, iid);
            alt vec::position(*ifce_methods, {|m| m.ident == self.m_name}) {
              none {
                /* check next bound */
                iface_bnd_idx += 1u;
              }

              some(pos) {
                // Replace any appearance of `self` with the type of the
                // generic parameter itself.  Note that this is the only case
                // where this replacement is necessary: in all other cases, we
                // are either invoking a method directly from an impl or class
                // (where the self type is not permitted), or from a iface
                // type (in which case methods that refer to self are not
                // permitted).
                let substs = {self_ty: some(self.self_ty)
                              with bound_substs};
                candidates += [(substs, ifce_methods[pos],
                                iid, pos, n, iface_bnd_idx)];
              }
            }
        }

        if candidates.len() == 0u {
            ret none;
        }

        if candidates.len() > 1u {
            self.tcx().sess.span_err(
                self.expr.span,
                "multiple applicable methods in scope");

            for candidates.eachi { |i, candidate|
                let (_, _, iid, _, _, _) = candidate;
                self.tcx().sess.span_note(
                    self.expr.span,
                    #fmt["candidate #%u derives from the bound `%s`",
                         (i+1u), ty::item_path_str(self.tcx(), iid)]);
            }
        }

        let (substs, mty, iid, pos, n, iface_bnd_idx) = candidates[0u];
        ret some(self.write_mty_from_m(
            substs, mty, method_param(iid, pos, n, iface_bnd_idx)));
    }

    fn method_from_iface(
        did: ast::def_id, iface_substs: ty::substs) -> option<method_origin> {

        let ms = *ty::iface_methods(self.tcx(), did);
        for ms.eachi {|i, m|
            if m.ident != self.m_name { cont; }

            let m_fty = ty::mk_fn(self.tcx(), m.fty);

            if ty::type_has_self(m_fty) {
                self.tcx().sess.span_err(
                    self.expr.span,
                    "can not call a method that contains a \
                     self type through a boxed iface");
            }

            if (*m.tps).len() > 0u {
                self.tcx().sess.span_err(
                    self.expr.span,
                    "can not call a generic method through a \
                     boxed iface");
            }

            // Note: although it is illegal to invoke a method that uses self
            // through a iface instance, we use a dummy subst here so that we
            // can soldier on with the compilation.
            let substs = {self_ty: some(self.self_ty)
                          with iface_substs};

            ret some(self.write_mty_from_m(
                substs, m, method_iface(did, i)));
        }

        ret none;
    }

    fn method_from_class(did: ast::def_id, class_substs: ty::substs)
        -> option<method_origin> {

        let ms = *ty::iface_methods(self.tcx(), did);

        for ms.each {|m|
            if m.ident != self.m_name { cont; }

            if m.vis == ast::private && !self.include_private {
                self.tcx().sess.span_fatal(
                    self.expr.span,
                    "Call to private method not allowed outside \
                     its defining class");
            }

            // look up method named <name>.
            let m_declared = ty::lookup_class_method_by_name(
                self.tcx(), did, self.m_name, self.expr.span);

            ret some(self.write_mty_from_m(
                class_substs, m,
                method_static(m_declared)));
        }

        ret none;
    }

    fn ty_from_did(did: ast::def_id) -> ty::t {
        alt check ty::get(ty::lookup_item_type(self.tcx(), did).ty).struct {
          ty::ty_fn(fty) {
            ty::mk_fn(self.tcx(), {proto: ast::proto_box with fty})
          }
        }
        /*
        if did.crate == ast::local_crate {
            alt check self.tcx().items.get(did.node) {
              ast_map::node_method(m, _, _) {
                // NDM iface/impl regions
                let mt = ty_of_method(self.fcx.ccx, m, ast::rp_none);
                ty::mk_fn(self.tcx(), {proto: ast::proto_box with mt.fty})
              }
            }
        } else {
            alt check ty::get(csearch::get_type(self.tcx(), did).ty).struct {
              ty::ty_fn(fty) {
                ty::mk_fn(self.tcx(), {proto: ast::proto_box with fty})
              }
            }
        }
        */
    }

    fn method_from_scope() -> option<method_origin> {
        let impls_vecs = self.fcx.ccx.impl_map.get(self.expr.id);

        for list::each(impls_vecs) {|impls|
            let mut results = [];
            for vec::each(*impls) {|im|
                // Check whether this impl has a method with the right name.
                for im.methods.find({|m| m.ident == self.m_name}).each {|m|

                    // determine the `self` of the impl with fresh
                    // variables for each parameter:
                    let {substs: impl_substs, ty: impl_ty} =
                        impl_self_ty(self.fcx, im.did);

                    // if we can assign the caller to the callee, that's a
                    // potential match.  Collect those in the vector.
                    alt self.fcx.can_mk_subty(self.self_ty, impl_ty) {
                      result::err(_) { /* keep looking */ }
                      result::ok(_) {
                        results += [(impl_ty, impl_substs, m.n_tps, m.did)];
                      }
                    }
                }
            }

            if results.len() >= 1u {
                if results.len() > 1u {
                    self.tcx().sess.span_err(
                        self.expr.span,
                        "multiple applicable methods in scope");

                    // I would like to print out how each impl was imported,
                    // but I cannot for the life of me figure out how to
                    // annotate resolve to preserve this information.
                    for results.eachi { |i, result|
                        let (_, _, _, did) = result;
                        let span = if did.crate == ast::local_crate {
                            alt check self.tcx().items.get(did.node) {
                              ast_map::node_method(m, _, _) { m.span }
                            }
                        } else {
                            self.expr.span
                        };
                        self.tcx().sess.span_note(
                            span,
                            #fmt["candidate #%u is `%s`",
                                 (i+1u),
                                 ty::item_path_str(self.tcx(), did)]);
                    }
                }

                let (impl_ty, impl_substs, n_tps, did) = results[0];
                alt self.fcx.mk_subty(self.self_ty, impl_ty) {
                  result::ok(_) {}
                  result::err(_) {
                    self.tcx().sess.span_bug(
                        self.expr.span,
                        "what was a subtype now is not?");
                  }
                }
                let fty = self.ty_from_did(did);
                ret some(self.write_mty_from_fty(
                    impl_substs, n_tps, fty,
                    method_static(did)));
            }
        }

        ret none;
    }

    fn write_mty_from_m(self_substs: ty::substs,
                        m: ty::method,
                        origin: method_origin) -> method_origin {
        let tcx = self.fcx.ccx.tcx;

        // a bit hokey, but the method unbound has a bare protocol, whereas
        // a.b has a protocol like fn@() (perhaps eventually fn&()):
        let fty = ty::mk_fn(tcx, {proto: ast::proto_box with m.fty});

        ret self.write_mty_from_fty(self_substs, (*m.tps).len(),
                                    fty, origin);
    }

    fn write_mty_from_fty(self_substs: ty::substs,
                          n_tps_m: uint,
                          fty: ty::t,
                          origin: method_origin) -> method_origin {

        let tcx = self.fcx.ccx.tcx;

        // Here I will use the "c_" prefix to refer to the method's
        // owner.  You can read it as class, but it may also be an iface.

        let n_tps_supplied = self.supplied_tps.len();
        let m_substs = {
            if n_tps_supplied == 0u {
                self.fcx.infcx.next_ty_vars(n_tps_m)
            } else if n_tps_m == 0u {
                tcx.sess.span_err(
                    self.expr.span,
                    "this method does not take type parameters");
                self.fcx.infcx.next_ty_vars(n_tps_m)
            } else if n_tps_supplied != n_tps_m {
                tcx.sess.span_err(
                    self.expr.span,
                    "incorrect number of type \
                     parameters given for this method");
                self.fcx.infcx.next_ty_vars(n_tps_m)
            } else {
                self.supplied_tps
            }
        };

        let all_substs = {tps: self_substs.tps + m_substs
                          with self_substs};

        self.fcx.write_ty_substs(self.node_id, fty, all_substs);

        ret origin;
    }
}

<|endoftext|>


<commit_before>use std::path::PathBuf;

#[derive(Debug, PartialEq, Clone)]
pub enum PlatformType {
    Unknown,
    OSX,
    Linux,
    Arch,
    Alpine,
}

pub fn is_alpine() -> bool {
    get() == PlatformType::Alpine
}

pub fn is_arch() -> bool {
    get() == PlatformType::Arch
}

pub fn is_mac() -> bool {
    get() == PlatformType::OSX
}

#[cfg(target_os = "macos")]
fn what_platform() -> PlatformType {
    PlatformType::OSX
}

#[cfg(target_os = "linux")]
fn what_platform() -> PlatformType {
    PlatformType::Linux
}

#[cfg(not(any(target_os = "linux", target_os = "macos",)))]
fn what_platform() -> PlatformType {
    PlatformType::Unknown
}

pub fn get() -> PlatformType {
    let mut platform = what_platform();
    if platform == PlatformType::Linux {
        if PathBuf::from("/etc/alpine-release").exists() {
            platform = PlatformType::Alpine
        } else if PathBuf::from("/etc/arch-release").exists() {
            platform = PlatformType::Arch
        }
    }
    platform
}
<commit_msg>nmk.rs: fix lint<commit_after>use std::path::PathBuf;

#[allow(dead_code)]
#[derive(Debug, PartialEq, Clone)]
pub enum PlatformType {
    Unknown,
    OSX,
    Linux,
    Arch,
    Alpine,
}

pub fn is_alpine() -> bool {
    get() == PlatformType::Alpine
}

pub fn is_arch() -> bool {
    get() == PlatformType::Arch
}

pub fn is_mac() -> bool {
    get() == PlatformType::OSX
}

#[cfg(target_os = "macos")]
fn what_platform() -> PlatformType {
    PlatformType::OSX
}

#[cfg(target_os = "linux")]
fn what_platform() -> PlatformType {
    PlatformType::Linux
}

#[cfg(not(any(target_os = "linux", target_os = "macos",)))]
fn what_platform() -> PlatformType {
    PlatformType::Unknown
}

pub fn get() -> PlatformType {
    let mut platform = what_platform();
    if platform == PlatformType::Linux {
        if PathBuf::from("/etc/alpine-release").exists() {
            platform = PlatformType::Alpine
        } else if PathBuf::from("/etc/arch-release").exists() {
            platform = PlatformType::Arch
        }
    }
    platform
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// ignore-pretty

use std::str;
use std::slice;

static TABLE: [u8, ..4] = [ 'A' as u8, 'C' as u8, 'G' as u8, 'T' as u8 ];
static TABLE_SIZE: uint = 2 << 16;

static OCCURRENCES: [&'static str, ..5] = [
    "GGT",
    "GGTA",
    "GGTATT",
    "GGTATTTTAATT",
    "GGTATTTTAATTTATAGT",
];

// Code implementation

#[deriving(Eq, Ord, TotalOrd, TotalEq)]
struct Code(u64);

impl Code {
    fn hash(&self) -> u64 {
        let Code(ret) = *self;
        return ret;
    }

    fn push_char(&self, c: u8) -> Code {
        Code((self.hash() << 2) + (pack_symbol(c) as u64))
    }

    fn rotate(&self, c: u8, frame: i32) -> Code {
        Code(self.push_char(c).hash() & ((1u64 << (2 * (frame as u64))) - 1))
    }

    fn pack(string: &str) -> Code {
        string.bytes().fold(Code(0u64), |a, b| a.push_char(b))
    }

    // FIXME: Inefficient.
    fn unpack(&self, frame: i32) -> ~str {
        let mut key = self.hash();
        let mut result = Vec::new();
        for _ in range(0, frame) {
            result.push(unpack_symbol((key as u8) & 3));
            key >>= 2;
        }

        result.reverse();
        str::from_utf8_owned(result.move_iter().collect()).unwrap()
    }
}

// Hash table implementation

trait TableCallback {
    fn f(&self, entry: &mut Entry);
}

struct BumpCallback;

impl TableCallback for BumpCallback {
    fn f(&self, entry: &mut Entry) {
        entry.count += 1;
    }
}

struct PrintCallback(&'static str);

impl TableCallback for PrintCallback {
    fn f(&self, entry: &mut Entry) {
        let PrintCallback(s) = *self;
        println!("{}\t{}", entry.count as int, s);
    }
}

struct Entry {
    code: Code,
    count: i32,
    next: Option<~Entry>,
}

struct Table {
    count: i32,
    items: Vec<Option<~Entry>> }

struct Items<'a> {
    cur: Option<&'a Entry>,
    items: slice::Items<'a, Option<~Entry>>,
}

impl Table {
    fn new() -> Table {
        Table {
            count: 0,
            items: Vec::from_fn(TABLE_SIZE, |_| None),
        }
    }

    fn search_remainder<C:TableCallback>(item: &mut Entry, key: Code, c: C) {
        match item.next {
            None => {
                let mut entry = ~Entry {
                    code: key,
                    count: 0,
                    next: None,
                };
                c.f(entry);
                item.next = Some(entry);
            }
            Some(ref mut entry) => {
                if entry.code == key {
                    c.f(*entry);
                    return;
                }

                Table::search_remainder(*entry, key, c)
            }
        }
    }

    fn lookup<C:TableCallback>(&mut self, key: Code, c: C) {
        let index = key.hash() % (TABLE_SIZE as u64);

        {
            if self.items.get(index as uint).is_none() {
                let mut entry = ~Entry {
                    code: key,
                    count: 0,
                    next: None,
                };
                c.f(entry);
                *self.items.get_mut(index as uint) = Some(entry);
                return;
            }
        }

        {
            let entry = &mut *self.items.get_mut(index as uint).get_mut_ref();
            if entry.code == key {
                c.f(*entry);
                return;
            }

            Table::search_remainder(*entry, key, c)
        }
    }

    fn iter<'a>(&'a self) -> Items<'a> {
        Items { cur: None, items: self.items.iter() }
    }
}

impl<'a> Iterator<&'a Entry> for Items<'a> {
    fn next(&mut self) -> Option<&'a Entry> {
        let ret = match self.cur {
            None => {
                let i;
                loop {
                    match self.items.next() {
                        None => return None,
                        Some(&None) => {}
                        Some(&Some(ref a)) => { i = &**a; break }
                    }
                }
                self.cur = Some(&*i);
                &*i
            }
            Some(c) => c
        };
        match ret.next {
            None => { self.cur = None; }
            Some(ref next) => { self.cur = Some(&**next); }
        }
        return Some(ret);
    }
}

// Main program

fn pack_symbol(c: u8) -> u8 {
    match c as char {
        'a' | 'A' => 0,
        'c' | 'C' => 1,
        'g' | 'G' => 2,
        't' | 'T' => 3,
        _ => fail!("{}", c as char),
    }
}

fn unpack_symbol(c: u8) -> u8 {
    TABLE[c]
}

fn next_char<'a>(mut buf: &'a [u8]) -> &'a [u8] {
    loop {
        buf = buf.slice(1, buf.len());
        if buf.len() == 0 {
            break;
        }
        if buf[0] != (' ' as u8) && buf[0] != ('\t' as u8) &&
                buf[0] != ('\n' as u8) && buf[0] != 0 {
            break;
        }
    }
    buf
}

fn generate_frequencies(frequencies: &mut Table,
                        mut input: &[u8],
                        frame: i32) {
    let mut code = Code(0);

    // Pull first frame.
    for _ in range(0, frame) {
        code = code.push_char(input[0]);
        input = next_char(input);
    }
    frequencies.lookup(code, BumpCallback);

    while input.len() != 0 && input[0] != ('>' as u8) {
        code = code.rotate(input[0], frame);
        frequencies.lookup(code, BumpCallback);
        input = next_char(input);
    }
}

fn print_frequencies(frequencies: &Table, frame: i32) {
    let mut vector = Vec::new();
    for entry in frequencies.iter() {
        vector.push((entry.code, entry.count));
    }
    vector.as_mut_slice().sort();

    let mut total_count = 0;
    for &(_, count) in vector.iter() {
        total_count += count;
    }

    for &(key, count) in vector.iter() {
        println!("{} {:.3f}",
                 key.unpack(frame),
                 (count as f32 * 100.0) / (total_count as f32));
    }
}

fn print_occurrences(frequencies: &mut Table, occurrence: &'static str) {
    frequencies.lookup(Code::pack(occurrence), PrintCallback(occurrence))
}

fn main() {
    let input = include_str!("shootout-k-nucleotide.data");
    let pos = input.find_str(">THREE").unwrap();
    let pos2 = pos + input.slice_from(pos).find_str("\n").unwrap();
    let input = input.slice_from(pos2 + 1).as_bytes();

    let mut frequencies = Table::new();
    generate_frequencies(&mut frequencies, input, 1);
    print_frequencies(&frequencies, 1);

    frequencies = Table::new();
    generate_frequencies(&mut frequencies, input, 2);
    print_frequencies(&frequencies, 2);

    for occurrence in OCCURRENCES.iter() {
        frequencies = Table::new();
        generate_frequencies(&mut frequencies,
                             input,
                             occurrence.len() as i32);
        print_occurrences(&mut frequencies, *occurrence);
    }
}
<commit_msg>make shootout-k-nucleotide.rs pass official test<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// ignore-android see #10393 #13206
// ignore-pretty

use std::ascii::OwnedStrAsciiExt;
use std::str;
use std::slice;

static TABLE: [u8, ..4] = [ 'A' as u8, 'C' as u8, 'G' as u8, 'T' as u8 ];
static TABLE_SIZE: uint = 2 << 16;

static OCCURRENCES: [&'static str, ..5] = [
    "GGT",
    "GGTA",
    "GGTATT",
    "GGTATTTTAATT",
    "GGTATTTTAATTTATAGT",
];

// Code implementation

#[deriving(Eq, Ord, TotalOrd, TotalEq)]
struct Code(u64);

impl Code {
    fn hash(&self) -> u64 {
        let Code(ret) = *self;
        return ret;
    }

    fn push_char(&self, c: u8) -> Code {
        Code((self.hash() << 2) + (pack_symbol(c) as u64))
    }

    fn rotate(&self, c: u8, frame: uint) -> Code {
        Code(self.push_char(c).hash() & ((1u64 << (2 * frame)) - 1))
    }

    fn pack(string: &str) -> Code {
        string.bytes().fold(Code(0u64), |a, b| a.push_char(b))
    }

    // FIXME: Inefficient.
    fn unpack(&self, frame: uint) -> ~str {
        let mut key = self.hash();
        let mut result = Vec::new();
        for _ in range(0, frame) {
            result.push(unpack_symbol((key as u8) & 3));
            key >>= 2;
        }

        result.reverse();
        str::from_utf8_owned(result.move_iter().collect()).unwrap()
    }
}

// Hash table implementation

trait TableCallback {
    fn f(&self, entry: &mut Entry);
}

struct BumpCallback;

impl TableCallback for BumpCallback {
    fn f(&self, entry: &mut Entry) {
        entry.count += 1;
    }
}

struct PrintCallback(&'static str);

impl TableCallback for PrintCallback {
    fn f(&self, entry: &mut Entry) {
        let PrintCallback(s) = *self;
        println!("{}\t{}", entry.count as int, s);
    }
}

struct Entry {
    code: Code,
    count: uint,
    next: Option<~Entry>,
}

struct Table {
    count: uint,
    items: Vec<Option<~Entry>> }

struct Items<'a> {
    cur: Option<&'a Entry>,
    items: slice::Items<'a, Option<~Entry>>,
}

impl Table {
    fn new() -> Table {
        Table {
            count: 0,
            items: Vec::from_fn(TABLE_SIZE, |_| None),
        }
    }

    fn search_remainder<C:TableCallback>(item: &mut Entry, key: Code, c: C) {
        match item.next {
            None => {
                let mut entry = ~Entry {
                    code: key,
                    count: 0,
                    next: None,
                };
                c.f(entry);
                item.next = Some(entry);
            }
            Some(ref mut entry) => {
                if entry.code == key {
                    c.f(*entry);
                    return;
                }

                Table::search_remainder(*entry, key, c)
            }
        }
    }

    fn lookup<C:TableCallback>(&mut self, key: Code, c: C) {
        let index = key.hash() % (TABLE_SIZE as u64);

        {
            if self.items.get(index as uint).is_none() {
                let mut entry = ~Entry {
                    code: key,
                    count: 0,
                    next: None,
                };
                c.f(entry);
                *self.items.get_mut(index as uint) = Some(entry);
                return;
            }
        }

        {
            let entry = &mut *self.items.get_mut(index as uint).get_mut_ref();
            if entry.code == key {
                c.f(*entry);
                return;
            }

            Table::search_remainder(*entry, key, c)
        }
    }

    fn iter<'a>(&'a self) -> Items<'a> {
        Items { cur: None, items: self.items.iter() }
    }
}

impl<'a> Iterator<&'a Entry> for Items<'a> {
    fn next(&mut self) -> Option<&'a Entry> {
        let ret = match self.cur {
            None => {
                let i;
                loop {
                    match self.items.next() {
                        None => return None,
                        Some(&None) => {}
                        Some(&Some(ref a)) => { i = &**a; break }
                    }
                }
                self.cur = Some(&*i);
                &*i
            }
            Some(c) => c
        };
        match ret.next {
            None => { self.cur = None; }
            Some(ref next) => { self.cur = Some(&**next); }
        }
        return Some(ret);
    }
}

// Main program

fn pack_symbol(c: u8) -> u8 {
    match c as char {
        'A' => 0,
        'C' => 1,
        'G' => 2,
        'T' => 3,
        _ => fail!("{}", c as char),
    }
}

fn unpack_symbol(c: u8) -> u8 {
    TABLE[c]
}

fn generate_frequencies(frequencies: &mut Table,
                        mut input: &[u8],
                        frame: uint) {
    if input.len() < frame { return; }
    let mut code = Code(0);

    // Pull first frame.
    for _ in range(0, frame) {
        code = code.push_char(input[0]);
        input = input.slice_from(1);
    }
    frequencies.lookup(code, BumpCallback);

    while input.len() != 0 && input[0] != ('>' as u8) {
        code = code.rotate(input[0], frame);
        frequencies.lookup(code, BumpCallback);
        input = input.slice_from(1);
    }
}

fn print_frequencies(frequencies: &Table, frame: uint) {
    let mut vector = Vec::new();
    for entry in frequencies.iter() {
        vector.push((entry.count, entry.code));
    }
    vector.as_mut_slice().sort();

    let mut total_count = 0;
    for &(count, _) in vector.iter() {
        total_count += count;
    }

    for &(count, key) in vector.iter().rev() {
        println!("{} {:.3f}",
                 key.unpack(frame),
                 (count as f32 * 100.0) / (total_count as f32));
    }
    println!("");
}

fn print_occurrences(frequencies: &mut Table, occurrence: &'static str) {
    frequencies.lookup(Code::pack(occurrence), PrintCallback(occurrence))
}

fn get_sequence<R: Buffer>(r: &mut R, key: &str) -> ~[u8] {
    let mut res = ~"";
    for l in r.lines().map(|l| l.ok().unwrap())
        .skip_while(|l| key != l.slice_to(key.len())).skip(1)
    {
        res.push_str(l.trim());
    }
    res.into_ascii_upper().into_bytes()
}

fn main() {
    let input = if std::os::getenv("RUST_BENCH").is_some() {
        let fd = std::io::File::open(&Path::new("shootout-k-nucleotide.data"));
        get_sequence(&mut std::io::BufferedReader::new(fd), ">THREE")
    } else {
        get_sequence(&mut std::io::stdin(), ">THREE")
    };

    let mut frequencies = Table::new();
    generate_frequencies(&mut frequencies, input, 1);
    print_frequencies(&frequencies, 1);

    frequencies = Table::new();
    generate_frequencies(&mut frequencies, input, 2);
    print_frequencies(&frequencies, 2);

    for occurrence in OCCURRENCES.iter() {
        frequencies = Table::new();
        generate_frequencies(&mut frequencies,
                             input,
                             occurrence.len());
        print_occurrences(&mut frequencies, *occurrence);
    }
}
<|endoftext|>


<commit_before>// FIXME #7306
// xfail-fast

use std::io;

fn f1(ref_string: &str) {
    match ref_string {
        "a" => io::println("found a"),
        "b" => io::println("found b"),
        _ => io::println("not found")
    }
}

fn f2(ref_string: &str) {
    match ref_string {
        "a" => io::println("found a"),
        "b" => io::println("found b"),
        s => io::println(fmt!("not found (%s)", s))
    }
}

fn g1(ref_1: &str, ref_2: &str) {
    match (ref_1, ref_2) {
        ("a", "b") => io::println("found a,b"),
        ("b", "c") => io::println("found b,c"),
        _ => io::println("not found")
    }
}

fn g2(ref_1: &str, ref_2: &str) {
    match (ref_1, ref_2) {
        ("a", "b") => io::println("found a,b"),
        ("b", "c") => io::println("found b,c"),
        (s1, s2) => io::println(fmt!("not found (%s, %s)", s1, s2))
    }
}

pub fn main() {
    f1(@"a");
    f1(~"b");
    f1(&"c");
    f1("d");
    f2(@"a");
    f2(~"b");
    f2(&"c");
    f2("d");
    g1(@"a", @"b");
    g1(~"b", ~"c");
    g1(&"c", &"d");
    g1("d", "e");
    g2(@"a", @"b");
    g2(~"b", ~"c");
    g2(&"c", &"d");
    g2("d", "e");
}
<commit_msg>Fix run-pass/match-borrowed_str.rs Fixes #7306<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

fn f1(ref_string: &str) -> ~str {
    match ref_string {
        "a" => ~"found a",
        "b" => ~"found b",
        _ => ~"not found"
    }
}

fn f2(ref_string: &str) -> ~str {
    match ref_string {
        "a" => ~"found a",
        "b" => ~"found b",
        s => fmt!("not found (%s)", s)
    }
}

fn g1(ref_1: &str, ref_2: &str) -> ~str {
    match (ref_1, ref_2) {
        ("a", "b") => ~"found a,b",
        ("b", "c") => ~"found b,c",
        _ => ~"not found"
    }
}

fn g2(ref_1: &str, ref_2: &str) -> ~str {
    match (ref_1, ref_2) {
        ("a", "b") => ~"found a,b",
        ("b", "c") => ~"found b,c",
        (s1, s2) => fmt!("not found (%s, %s)", s1, s2)
    }
}

pub fn main() {
    assert_eq!(f1(@"a"), ~"found a");
    assert_eq!(f1(~"b"), ~"found b");
    assert_eq!(f1(&"c"), ~"not found");
    assert_eq!(f1("d"), ~"not found");
    assert_eq!(f2(@"a"), ~"found a");
    assert_eq!(f2(~"b"), ~"found b");
    assert_eq!(f2(&"c"), ~"not found (c)");
    assert_eq!(f2("d"), ~"not found (d)");
    assert_eq!(g1(@"a", @"b"), ~"found a,b");
    assert_eq!(g1(~"b", ~"c"), ~"found b,c");
    assert_eq!(g1(&"c", &"d"), ~"not found");
    assert_eq!(g1("d", "e"), ~"not found");
    assert_eq!(g2(@"a", @"b"), ~"found a,b");
    assert_eq!(g2(~"b", ~"c"), ~"found b,c");
    assert_eq!(g2(&"c", &"d"), ~"not found (c, d)");
    assert_eq!(g2("d", "e"), ~"not found (d, e)");
}

<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![feature(rustc_private)]

extern crate syntax;
extern crate rustdoc;
extern crate serialize as rustc_serialize;

use std::collections::BTreeMap;
use std::env;
use std::error::Error;
use std::fs::{read_dir, File};
use std::io::{Read, Write};
use std::path::Path;
use std::path::PathBuf;

use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};

use rustdoc::html::markdown::{Markdown, PLAYGROUND, RenderType};
use rustc_serialize::json;

enum OutputFormat {
    HTML(HTMLFormatter),
    Markdown(MarkdownFormatter),
    Unknown(String),
}

impl OutputFormat {
    fn from(format: &str) -> OutputFormat {
        match &*format.to_lowercase() {
            "html"     => OutputFormat::HTML(HTMLFormatter),
            "markdown" => OutputFormat::Markdown(MarkdownFormatter),
            s          => OutputFormat::Unknown(s.to_owned()),
        }
    }
}

trait Formatter {
    fn header(&self, output: &mut Write) -> Result<(), Box<Error>>;
    fn title(&self, output: &mut Write) -> Result<(), Box<Error>>;
    fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata,
                        err_code: &str) -> Result<(), Box<Error>>;
    fn footer(&self, output: &mut Write) -> Result<(), Box<Error>>;
}

struct HTMLFormatter;
struct MarkdownFormatter;

impl Formatter for HTMLFormatter {
    fn header(&self, output: &mut Write) -> Result<(), Box<Error>> {
        write!(output, r##"<!DOCTYPE html>

<title>Rust Compiler Error Index</title>
<meta charset="utf-8">

<link rel="stylesheet" type="text/css" href="main.css"/>
<link rel="stylesheet" type="text/css" href="rust.css"/>

"##)?;
        Ok(())
    }

    fn title(&self, output: &mut Write) -> Result<(), Box<Error>> {
        write!(output, "
Rust Compiler Error Index
\n")?;
        Ok(())
    }

    fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata,
                        err_code: &str) -> Result<(), Box<Error>> {
        // Enclose each error in a div so they can be shown/hidden en masse.
        let desc_desc = match info.description {
            Some(_) => "error-described",
            None => "error-undescribed",
        };
        let use_desc = match info.use_site {
            Some(_) => "error-used",
            None => "error-unused",
        };
        write!(output, "
", desc_desc, use_desc)?;

        // Error title (with self-link).
        write!(output,
               "
{0}
\n",
               err_code)?;

        // Description rendered as markdown.
        match info.description {
            Some(ref desc) => write!(output, "{}", Markdown(desc, RenderType::Hoedown))?,
            None => write!(output, "
No description.
\n")?,
        }

        write!(output, "
\n")?;
        Ok(())
    }

    fn footer(&self, output: &mut Write) -> Result<(), Box<Error>> {
        write!(output, r##"

"##)?;
        Ok(())
    }
}

impl Formatter for MarkdownFormatter {
    #[allow(unused_variables)]
    fn header(&self, output: &mut Write) -> Result<(), Box<Error>> {
        Ok(())
    }

    fn title(&self, output: &mut Write) -> Result<(), Box<Error>> {
        write!(output, "# Rust Compiler Error Index\n")?;
        Ok(())
    }

    fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata,
                        err_code: &str) -> Result<(), Box<Error>> {
        Ok(match info.description {
            Some(ref desc) => write!(output, "## {}\n{}\n", err_code, desc)?,
            None => (),
        })
    }

    #[allow(unused_variables)]
    fn footer(&self, output: &mut Write) -> Result<(), Box<Error>> {
        Ok(())
    }
}

/// Load all the metadata files from `metadata_dir` into an in-memory map.
fn load_all_errors(metadata_dir: &Path) -> Result<ErrorMetadataMap, Box<Error>> {
    let mut all_errors = BTreeMap::new();

    for entry in read_dir(metadata_dir)? {
        let path = entry?.path();

        let mut metadata_str = String::new();
        File::open(&path).and_then(|mut f| f.read_to_string(&mut metadata_str))?;

        let some_errors: ErrorMetadataMap = json::decode(&metadata_str)?;

        for (err_code, info) in some_errors {
            all_errors.insert(err_code, info);
        }
    }

    Ok(all_errors)
}

/// Output an HTML page for the errors in `err_map` to `output_path`.
fn render_error_page<T: Formatter>(err_map: &ErrorMetadataMap, output_path: &Path,
                                   formatter: T) -> Result<(), Box<Error>> {
    let mut output_file = File::create(output_path)?;

    formatter.header(&mut output_file)?;
    formatter.title(&mut output_file)?;

    for (err_code, info) in err_map {
        formatter.error_code_block(&mut output_file, info, err_code)?;
    }

    formatter.footer(&mut output_file)
}

fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<Error>> {
    let build_arch = env::var("CFG_BUILD")?;
    let metadata_dir = get_metadata_dir(&build_arch);
    let err_map = load_all_errors(&metadata_dir)?;
    match format {
        OutputFormat::Unknown(s)  => panic!("Unknown output format: {}", s),
        OutputFormat::HTML(h)     => render_error_page(&err_map, dst, h)?,
        OutputFormat::Markdown(m) => render_error_page(&err_map, dst, m)?,
    }
    Ok(())
}

fn parse_args() -> (OutputFormat, PathBuf) {
    let mut args = env::args().skip(1);
    let format = args.next().map(|a| OutputFormat::from(&a))
                            .unwrap_or(OutputFormat::from("html"));
    let dst = args.next().map(PathBuf::from).unwrap_or_else(|| {
        match format {
            OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"),
            OutputFormat::Markdown(..) => PathBuf::from("doc/error-index.md"),
            OutputFormat::Unknown(..) => PathBuf::from("<nul>"),
        }
    });
    (format, dst)
}

fn main() {
    PLAYGROUND.with(|slot| {
        *slot.borrow_mut() = Some((None, String::from("https://play.rust-lang.org/")));
    });
    let (format, dst) = parse_args();
    if let Err(e) = main_with_result(format, &dst) {
        panic!("{}", e.description());
    }
}
<commit_msg>fix error_index_generator<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![feature(rustc_private)]

extern crate syntax;
extern crate rustdoc;
extern crate serialize as rustc_serialize;

use std::collections::BTreeMap;
use std::env;
use std::error::Error;
use std::fs::{read_dir, File};
use std::io::{Read, Write};
use std::path::Path;
use std::path::PathBuf;

use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};

use rustdoc::html::markdown::{Markdown, PLAYGROUND, RenderType};
use rustc_serialize::json;

enum OutputFormat {
    HTML(HTMLFormatter),
    Markdown(MarkdownFormatter),
    Unknown(String),
}

impl OutputFormat {
    fn from(format: &str) -> OutputFormat {
        match &*format.to_lowercase() {
            "html"     => OutputFormat::HTML(HTMLFormatter),
            "markdown" => OutputFormat::Markdown(MarkdownFormatter),
            s          => OutputFormat::Unknown(s.to_owned()),
        }
    }
}

trait Formatter {
    fn header(&self, output: &mut Write) -> Result<(), Box<Error>>;
    fn title(&self, output: &mut Write) -> Result<(), Box<Error>>;
    fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata,
                        err_code: &str) -> Result<(), Box<Error>>;
    fn footer(&self, output: &mut Write) -> Result<(), Box<Error>>;
}

struct HTMLFormatter;
struct MarkdownFormatter;

impl Formatter for HTMLFormatter {
    fn header(&self, output: &mut Write) -> Result<(), Box<Error>> {
        write!(output, r##"<!DOCTYPE html>

<title>Rust Compiler Error Index</title>
<meta charset="utf-8">

<link rel="stylesheet" type="text/css" href="main.css"/>
<link rel="stylesheet" type="text/css" href="rust.css"/>

"##)?;
        Ok(())
    }

    fn title(&self, output: &mut Write) -> Result<(), Box<Error>> {
        write!(output, "
Rust Compiler Error Index
\n")?;
        Ok(())
    }

    fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata,
                        err_code: &str) -> Result<(), Box<Error>> {
        // Enclose each error in a div so they can be shown/hidden en masse.
        let desc_desc = match info.description {
            Some(_) => "error-described",
            None => "error-undescribed",
        };
        let use_desc = match info.use_site {
            Some(_) => "error-used",
            None => "error-unused",
        };
        write!(output, "
", desc_desc, use_desc)?;

        // Error title (with self-link).
        write!(output,
               "
{0}
\n",
               err_code)?;

        // Description rendered as markdown.
        match info.description {
            Some(ref desc) => write!(output, "{}", Markdown(desc, &[], RenderType::Hoedown))?,
            None => write!(output, "
No description.
\n")?,
        }

        write!(output, "
\n")?;
        Ok(())
    }

    fn footer(&self, output: &mut Write) -> Result<(), Box<Error>> {
        write!(output, r##"

"##)?;
        Ok(())
    }
}

impl Formatter for MarkdownFormatter {
    #[allow(unused_variables)]
    fn header(&self, output: &mut Write) -> Result<(), Box<Error>> {
        Ok(())
    }

    fn title(&self, output: &mut Write) -> Result<(), Box<Error>> {
        write!(output, "# Rust Compiler Error Index\n")?;
        Ok(())
    }

    fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata,
                        err_code: &str) -> Result<(), Box<Error>> {
        Ok(match info.description {
            Some(ref desc) => write!(output, "## {}\n{}\n", err_code, desc)?,
            None => (),
        })
    }

    #[allow(unused_variables)]
    fn footer(&self, output: &mut Write) -> Result<(), Box<Error>> {
        Ok(())
    }
}

/// Load all the metadata files from `metadata_dir` into an in-memory map.
fn load_all_errors(metadata_dir: &Path) -> Result<ErrorMetadataMap, Box<Error>> {
    let mut all_errors = BTreeMap::new();

    for entry in read_dir(metadata_dir)? {
        let path = entry?.path();

        let mut metadata_str = String::new();
        File::open(&path).and_then(|mut f| f.read_to_string(&mut metadata_str))?;

        let some_errors: ErrorMetadataMap = json::decode(&metadata_str)?;

        for (err_code, info) in some_errors {
            all_errors.insert(err_code, info);
        }
    }

    Ok(all_errors)
}

/// Output an HTML page for the errors in `err_map` to `output_path`.
fn render_error_page<T: Formatter>(err_map: &ErrorMetadataMap, output_path: &Path,
                                   formatter: T) -> Result<(), Box<Error>> {
    let mut output_file = File::create(output_path)?;

    formatter.header(&mut output_file)?;
    formatter.title(&mut output_file)?;

    for (err_code, info) in err_map {
        formatter.error_code_block(&mut output_file, info, err_code)?;
    }

    formatter.footer(&mut output_file)
}

fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<Error>> {
    let build_arch = env::var("CFG_BUILD")?;
    let metadata_dir = get_metadata_dir(&build_arch);
    let err_map = load_all_errors(&metadata_dir)?;
    match format {
        OutputFormat::Unknown(s)  => panic!("Unknown output format: {}", s),
        OutputFormat::HTML(h)     => render_error_page(&err_map, dst, h)?,
        OutputFormat::Markdown(m) => render_error_page(&err_map, dst, m)?,
    }
    Ok(())
}

fn parse_args() -> (OutputFormat, PathBuf) {
    let mut args = env::args().skip(1);
    let format = args.next().map(|a| OutputFormat::from(&a))
                            .unwrap_or(OutputFormat::from("html"));
    let dst = args.next().map(PathBuf::from).unwrap_or_else(|| {
        match format {
            OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"),
            OutputFormat::Markdown(..) => PathBuf::from("doc/error-index.md"),
            OutputFormat::Unknown(..) => PathBuf::from("<nul>"),
        }
    });
    (format, dst)
}

fn main() {
    PLAYGROUND.with(|slot| {
        *slot.borrow_mut() = Some((None, String::from("https://play.rust-lang.org/")));
    });
    let (format, dst) = parse_args();
    if let Err(e) = main_with_result(format, &dst) {
        panic!("{}", e.description());
    }
}
<|endoftext|>


<commit_before>use iced::{
  canvas, executor, mouse, Application, Canvas, Color, Command, Element, Length, Point, Rectangle, Settings, Vector,
};
use oppai_field::field::{self, Field, Pos};
use oppai_field::player::Player;
use oppai_field::zobrist::Zobrist;
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;

const FIELD_WIDTH: u32 = 39;
const FIELD_HEIGHT: u32 = 32;

pub fn main() -> iced::Result {
  Game::run(Settings {
    antialiasing: true,
    ..Settings::default()
  })
}

struct Game {
  player: Player,
  field: Field,
  captures: Vec<(Vec<Pos>, Player)>,
  field_cache: canvas::Cache,
}

#[derive(Debug, Clone, Copy)]
enum Message {
  PutPoint(Pos),
}

impl Application for Game {
  type Executor = executor::Default;
  type Message = Message;
  type Flags = ();

  fn new(_flags: ()) -> (Self, Command<Self::Message>) {
    let mut rng = XorShiftRng::from_entropy();
    let zobrist = Zobrist::new(field::length(FIELD_WIDTH, FIELD_HEIGHT) * 2, &mut rng);
    let field = Field::new(FIELD_WIDTH, FIELD_HEIGHT, std::sync::Arc::new(zobrist));
    (
      Game {
        player: Player::Red,
        field,
        captures: Vec::new(),
        field_cache: Default::default(),
      },
      Command::none(),
    )
  }

  fn title(&self) -> String {
    "OpPAI".into()
  }

  fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
    let Message::PutPoint(pos) = message;
    if self.field.put_point(pos, self.player) {
      let last_chain = self.field.get_last_chain();
      if let Some(&pos) = last_chain.first() {
        let player = self.field.cell(pos).get_player();
        self.captures.push((last_chain, player));
      }

      let n = self.field.n(pos);
      let s = self.field.s(pos);
      let w = self.field.w(pos);
      let e = self.field.e(pos);
      let nw = self.field.nw(pos);
      let ne = self.field.ne(pos);
      let sw = self.field.sw(pos);
      let se = self.field.se(pos);

      let mut check = |pos1: Pos, pos2: Pos| {
        if self.field.cell(pos1).get_players_point() == Some(self.player)
          && self.field.cell(pos2).get_players_point() == Some(self.player)
        {
          self.captures.push((vec![pos, pos1, pos2], self.player));
          true
        } else {
          false
        }
      };

      let _ = !check(s, e) && (check(s, se) || check(e, se));
      let _ = !check(e, n) && (check(e, ne) || check(n, ne));
      let _ = !check(n, w) && (check(n, nw) || check(w, nw));
      let _ = !check(w, s) && (check(w, sw) || check(s, sw));

      self.player = self.player.next();

      self.field_cache.clear();
    }

    Command::none()
  }

  fn view(&mut self) -> iced::Element<'_, Self::Message> {
    let canvas = Canvas::new(self).height(Length::Fill).width(Length::Fill);
    Element::<Pos>::from(canvas).map(Message::PutPoint)
  }
}

impl canvas::Program<Pos> for Game {
  fn update(
    &mut self,
    event: canvas::Event,
    bounds: Rectangle,
    cursor: canvas::Cursor,
  ) -> (canvas::event::Status, Option<Pos>) {
    let cursor_position = if let Some(position) = cursor.position_in(&bounds) {
      position
    } else {
      return (canvas::event::Status::Ignored, None);
    };
    match event {
      canvas::Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
        let field_width = self.field.width();
        let field_height = self.field.height();
        let width = bounds
          .width
          .min(bounds.height / field_height as f32 * field_width as f32);
        let height = bounds
          .height
          .min(bounds.width / field_width as f32 * field_height as f32);
        let step_x = width / field_width as f32;
        let step_y = height / field_height as f32;
        let shift = Vector::new(
          ((bounds.width - width) / 2.0).round(),
          ((bounds.height - height) / 2.0).round(),
        );
        let cursor_shift = Vector::new(step_x / 2.0, step_y / 2.0);

        let point = cursor_position - shift;
        if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
          let point = point - cursor_shift;
          let x = (point.x / step_x).round() as u32;
          let y = (point.y / step_y).round() as u32;
          (canvas::event::Status::Captured, Some(self.field.to_pos(x, y)))
        } else {
          (canvas::event::Status::Captured, None)
        }
      }
      _ => (canvas::event::Status::Ignored, None),
    }
  }

  fn draw(&self, bounds: Rectangle, cursor: canvas::Cursor) -> Vec<canvas::Geometry> {
    fn color(player: Player) -> Color {
      match player {
        Player::Red => Color::from_rgb8(0xFF, 0x00, 0x00),
        Player::Black => Color::BLACK,
      }
    }

    let field_width = self.field.width();
    let field_height = self.field.height();
    let width = bounds
      .width
      .min(bounds.height / field_height as f32 * field_width as f32);
    let height = bounds
      .height
      .min(bounds.width / field_width as f32 * field_height as f32);
    let step_x = width / field_width as f32;
    let step_y = height / field_height as f32;
    let shift = Vector::new(
      ((bounds.width - width) / 2.0).round(),
      ((bounds.height - height) / 2.0).round(),
    );
    let cursor_shift = Vector::new(step_x / 2.0, step_y / 2.0);

    let xy_to_point = |x: u32, y: u32| {
      let offset_x = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
      let offset_y = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
      Point::new(offset_x, offset_y) + shift
    };
    let pos_to_point = |pos: Pos| {
      let x = self.field.to_x(pos);
      let y = self.field.to_y(pos);
      xy_to_point(x, y)
    };

    let point_radius = width / field_width as f32 / 6.0;

    let field = self.field_cache.draw(bounds.size(), |frame| {
      let grid = canvas::Path::new(|path| {
        for x in 0..field_width {
          let offset = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
          path.move_to(Point::new(offset, 0.0) + shift);
          path.line_to(Point::new(offset, height) + shift);
        }
        for y in 0..field_height {
          let offset = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
          path.move_to(Point::new(0.0, offset) + shift);
          path.line_to(Point::new(width, offset) + shift);
        }
      });

      frame.stroke(
        &grid,
        canvas::Stroke {
          width: 1.0,
          color: Color::BLACK,
          ..canvas::Stroke::default()
        },
      );

      for &player in &[Player::Red, Player::Black] {
        let points = canvas::Path::new(|path| {
          for &pos in self
            .field
            .points_seq()
            .iter()
            .filter(|&&pos| self.field.cell(pos).is_players_point(player))
          {
            path.circle(pos_to_point(pos), point_radius)
          }
        });

        frame.fill(&points, color(player));
      }

      for (chain, player) in &self.captures {
        let path = canvas::Path::new(|path| {
          path.move_to(pos_to_point(chain[0]));
          for &pos in chain.iter().skip(1) {
            path.line_to(pos_to_point(pos));
          }
        });

        let mut color = color(*player);
        color.a = 0.5;

        frame.fill(&path, color);
      }

      if let Some(&pos) = self.field.points_seq().last() {
        let last_point = canvas::Path::new(|path| path.circle(pos_to_point(pos), point_radius * 1.5));

        let color = color(self.field.cell(pos).get_player());

        frame.stroke(
          &last_point,
          canvas::Stroke {
            width: 2.0,
            color,
            ..canvas::Stroke::default()
          },
        );
      }
    });

    let mut frame = canvas::Frame::new(bounds.size());

    if let Some(point) = cursor.position().and_then(|cursor_position| {
      let point = cursor_position - shift;
      if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
        let point = point - cursor_shift;
        let x = (point.x / step_x).round() as u32;
        let y = (point.y / step_y).round() as u32;
        let pos = self.field.to_pos(x, y);
        if self.field.is_putting_allowed(pos) {
          Some(xy_to_point(x, y))
        } else {
          None
        }
      } else {
        None
      }
    }) {
      let cursor_point = canvas::Path::new(|path| path.circle(point, point_radius));

      let mut color = color(self.player);
      color.a = 0.5;

      frame.fill(&cursor_point, color);
    }

    vec![field, frame.into_geometry()]
  }
}
<commit_msg>Add undo hotkey.<commit_after>use iced::{
  canvas, executor, keyboard, mouse, Application, Canvas, Color, Command, Element, Length, Point, Rectangle, Settings,
  Vector,
};
use oppai_field::field::{self, Field, Pos};
use oppai_field::player::Player;
use oppai_field::zobrist::Zobrist;
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;

const FIELD_WIDTH: u32 = 39;
const FIELD_HEIGHT: u32 = 32;

pub fn main() -> iced::Result {
  Game::run(Settings {
    antialiasing: true,
    ..Settings::default()
  })
}

struct Game {
  player: Player,
  field: Field,
  captures: Vec<(Vec<Pos>, Player, usize)>,
  field_cache: canvas::Cache,
}

#[derive(Debug, Clone, Copy)]
enum CanvasMessage {
  PutPoint(Pos),
  Undo,
}

#[derive(Debug, Clone, Copy)]
enum Message {
  Canvas(CanvasMessage),
}

impl Application for Game {
  type Executor = executor::Default;
  type Message = Message;
  type Flags = ();

  fn new(_flags: ()) -> (Self, Command<Self::Message>) {
    let mut rng = XorShiftRng::from_entropy();
    let zobrist = Zobrist::new(field::length(FIELD_WIDTH, FIELD_HEIGHT) * 2, &mut rng);
    let field = Field::new(FIELD_WIDTH, FIELD_HEIGHT, std::sync::Arc::new(zobrist));
    (
      Game {
        player: Player::Red,
        field,
        captures: Vec::new(),
        field_cache: Default::default(),
      },
      Command::none(),
    )
  }

  fn title(&self) -> String {
    "OpPAI".into()
  }

  fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
    match message {
      Message::Canvas(CanvasMessage::PutPoint(pos)) => {
        if self.field.put_point(pos, self.player) {
          let last_chain = self.field.get_last_chain();
          if let Some(&pos) = last_chain.first() {
            let player = self.field.cell(pos).get_player();
            self.captures.push((last_chain, player, self.field.moves_count()));
          }

          let n = self.field.n(pos);
          let s = self.field.s(pos);
          let w = self.field.w(pos);
          let e = self.field.e(pos);
          let nw = self.field.nw(pos);
          let ne = self.field.ne(pos);
          let sw = self.field.sw(pos);
          let se = self.field.se(pos);

          let mut check = |pos1: Pos, pos2: Pos| {
            if self.field.cell(pos1).get_players_point() == Some(self.player)
              && self.field.cell(pos2).get_players_point() == Some(self.player)
            {
              self.captures.push((vec![pos, pos1, pos2], self.player, self.field.moves_count()));
              true
            } else {
              false
            }
          };

          let _ = !check(s, e) && (check(s, se) || check(e, se));
          let _ = !check(e, n) && (check(e, ne) || check(n, ne));
          let _ = !check(n, w) && (check(n, nw) || check(w, nw));
          let _ = !check(w, s) && (check(w, sw) || check(s, sw));

          self.player = self.player.next();

          self.field_cache.clear();
        }
      }
      Message::Canvas(CanvasMessage::Undo) => {
        if let Some(player) = self.field.last_player() {
          self.player = player;
          self.field.undo();

          while self.captures.last().map_or(false, |&(_, _, c)| c > self.field.moves_count()) {
            self.captures.pop();
          }

          self.field_cache.clear();
        }
      }
    }

    Command::none()
  }

  fn view(&mut self) -> iced::Element<'_, Self::Message> {
    let canvas = Canvas::new(self).height(Length::Fill).width(Length::Fill);
    Element::<CanvasMessage>::from(canvas).map(Message::Canvas)
  }
}

impl canvas::Program<CanvasMessage> for Game {
  fn update(
    &mut self,
    event: canvas::Event,
    bounds: Rectangle,
    cursor: canvas::Cursor,
  ) -> (canvas::event::Status, Option<CanvasMessage>) {
    let cursor_position = if let Some(position) = cursor.position_in(&bounds) {
      position
    } else {
      return (canvas::event::Status::Ignored, None);
    };
    match event {
      canvas::Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
        let field_width = self.field.width();
        let field_height = self.field.height();
        let width = bounds
          .width
          .min(bounds.height / field_height as f32 * field_width as f32);
        let height = bounds
          .height
          .min(bounds.width / field_width as f32 * field_height as f32);
        let step_x = width / field_width as f32;
        let step_y = height / field_height as f32;
        let shift = Vector::new(
          ((bounds.width - width) / 2.0).round(),
          ((bounds.height - height) / 2.0).round(),
        );
        let cursor_shift = Vector::new(step_x / 2.0, step_y / 2.0);

        let point = cursor_position - shift;
        if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
          let point = point - cursor_shift;
          let x = (point.x / step_x).round() as u32;
          let y = (point.y / step_y).round() as u32;
          (
            canvas::event::Status::Captured,
            Some(CanvasMessage::PutPoint(self.field.to_pos(x, y))),
          )
        } else {
          (canvas::event::Status::Captured, None)
        }
      }
      canvas::Event::Keyboard(keyboard::Event::KeyPressed {
        key_code: keyboard::KeyCode::Backspace,
        ..
      }) => (canvas::event::Status::Captured, Some(CanvasMessage::Undo)),
      _ => (canvas::event::Status::Ignored, None),
    }
  }

  fn draw(&self, bounds: Rectangle, cursor: canvas::Cursor) -> Vec<canvas::Geometry> {
    fn color(player: Player) -> Color {
      match player {
        Player::Red => Color::from_rgb8(0xFF, 0x00, 0x00),
        Player::Black => Color::BLACK,
      }
    }

    let field_width = self.field.width();
    let field_height = self.field.height();
    let width = bounds
      .width
      .min(bounds.height / field_height as f32 * field_width as f32);
    let height = bounds
      .height
      .min(bounds.width / field_width as f32 * field_height as f32);
    let step_x = width / field_width as f32;
    let step_y = height / field_height as f32;
    let shift = Vector::new(
      ((bounds.width - width) / 2.0).round(),
      ((bounds.height - height) / 2.0).round(),
    );
    let cursor_shift = Vector::new(step_x / 2.0, step_y / 2.0);

    let xy_to_point = |x: u32, y: u32| {
      let offset_x = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
      let offset_y = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
      Point::new(offset_x, offset_y) + shift
    };
    let pos_to_point = |pos: Pos| {
      let x = self.field.to_x(pos);
      let y = self.field.to_y(pos);
      xy_to_point(x, y)
    };

    let point_radius = width / field_width as f32 / 6.0;

    let field = self.field_cache.draw(bounds.size(), |frame| {
      let grid = canvas::Path::new(|path| {
        for x in 0..field_width {
          let offset = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
          path.move_to(Point::new(offset, 0.0) + shift);
          path.line_to(Point::new(offset, height) + shift);
        }
        for y in 0..field_height {
          let offset = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
          path.move_to(Point::new(0.0, offset) + shift);
          path.line_to(Point::new(width, offset) + shift);
        }
      });

      frame.stroke(
        &grid,
        canvas::Stroke {
          width: 1.0,
          color: Color::BLACK,
          ..canvas::Stroke::default()
        },
      );

      for &player in &[Player::Red, Player::Black] {
        let points = canvas::Path::new(|path| {
          for &pos in self
            .field
            .points_seq()
            .iter()
            .filter(|&&pos| self.field.cell(pos).is_players_point(player))
          {
            path.circle(pos_to_point(pos), point_radius)
          }
        });

        frame.fill(&points, color(player));
      }

      for (chain, player, _) in &self.captures {
        let path = canvas::Path::new(|path| {
          path.move_to(pos_to_point(chain[0]));
          for &pos in chain.iter().skip(1) {
            path.line_to(pos_to_point(pos));
          }
        });

        let mut color = color(*player);
        color.a = 0.5;

        frame.fill(&path, color);
      }

      if let Some(&pos) = self.field.points_seq().last() {
        let last_point = canvas::Path::new(|path| path.circle(pos_to_point(pos), point_radius * 1.5));

        let color = color(self.field.cell(pos).get_player());

        frame.stroke(
          &last_point,
          canvas::Stroke {
            width: 2.0,
            color,
            ..canvas::Stroke::default()
          },
        );
      }
    });

    let mut frame = canvas::Frame::new(bounds.size());

    if let Some(point) = cursor.position().and_then(|cursor_position| {
      let point = cursor_position - shift;
      if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
        let point = point - cursor_shift;
        let x = (point.x / step_x).round() as u32;
        let y = (point.y / step_y).round() as u32;
        let pos = self.field.to_pos(x, y);
        if self.field.is_putting_allowed(pos) {
          Some(xy_to_point(x, y))
        } else {
          None
        }
      } else {
        None
      }
    }) {
      let cursor_point = canvas::Path::new(|path| path.circle(point, point_radius));

      let mut color = color(self.player);
      color.a = 0.5;

      frame.fill(&cursor_point, color);
    }

    vec![field, frame.into_geometry()]
  }
}
<|endoftext|>


<commit_before>use data_url;
use gio_sys;
use glib_sys;
use libc;

use gio::{
    self,
    BufferedInputStream,
    BufferedInputStreamExt,
    Cancellable,
    ConverterInputStream,
    File as GFile,
    FileExt,
    InputStream,
    MemoryInputStream,
    ZlibCompressorFormat,
    ZlibDecompressor,
};
use glib::{self, translate::*, Bytes as GBytes, Cast};
use std::ptr;

use allowed_url::AllowedUrl;
use error::{LoadingError, RsvgError};
use handle::BinaryData;

fn decode_data_uri(uri: &str) -> Result<BinaryData, LoadingError> {
    let data_url = data_url::DataUrl::process(uri).map_err(|_| LoadingError::BadDataUrl)?;

    let mime_type = data_url.mime_type().to_string();

    let (bytes, fragment_id) = data_url
        .decode_to_vec()
        .map_err(|_| LoadingError::BadDataUrl)?;

    // See issue #377 - per the data: URL spec
    // (https://fetch.spec.whatwg.org/#data-urls), those URLs cannot
    // have fragment identifiers.  So, just return an error if we find
    // one.  This probably indicates mis-quoted SVG data inside the
    // data: URL.
    if fragment_id.is_some() {
        return Err(LoadingError::BadDataUrl);
    }

    Ok(BinaryData {
        data: bytes,
        content_type: Some(mime_type),
    })
}

pub fn binary_data_to_glib(
    binary_data: &BinaryData,
    out_mime_type: *mut *mut libc::c_char,
    out_size: *mut usize,
) -> *mut libc::c_char {
    unsafe {
        if !out_mime_type.is_null() {
            *out_mime_type = binary_data.content_type.to_glib_full();
        }

        *out_size = binary_data.data.len();

        ToGlibContainerFromSlice::to_glib_full_from_slice(&binary_data.data) as *mut libc::c_char
    }
}

// Header of a gzip data stream
const GZ_MAGIC_0: u8 = 0x1f;
const GZ_MAGIC_1: u8 = 0x8b;

fn get_input_stream_for_loading(
    stream: InputStream,
    cancellable: Option<Cancellable>,
) -> Result<InputStream, glib::Error> {
    // detect gzipped streams (svgz)

    let buffered = BufferedInputStream::new(&stream);
    let num_read = buffered.fill(2, cancellable.as_ref())?;
    if num_read < 2 {
        // FIXME: this string was localized in the original; localize it
        return Err(glib::Error::new(RsvgError, "Input file is too short"));
    }

    let buf = buffered.peek_buffer();
    assert!(buf.len() >= 2);
    if buf[0] == GZ_MAGIC_0 && buf[1] == GZ_MAGIC_1 {
        let decomp = ZlibDecompressor::new(ZlibCompressorFormat::Gzip);
        let converter = ConverterInputStream::new(&buffered, &decomp);
        Ok(converter.upcast::<InputStream>())
    } else {
        Ok(buffered.upcast::<InputStream>())
    }
}

#[no_mangle]
pub unsafe fn rsvg_get_input_stream_for_loading(
    stream: *mut gio_sys::GInputStream,
    cancellable: *mut gio_sys::GCancellable,
    error: *mut *mut glib_sys::GError,
) -> *mut gio_sys::GInputStream {
    let stream = from_glib_borrow(stream);
    let cancellable = from_glib_borrow(cancellable);

    match get_input_stream_for_loading(stream, cancellable) {
        Ok(stream) => stream.to_glib_full(),

        Err(e) => {
            if !error.is_null() {
                *error = e.to_glib_full() as *mut _;
            }

            ptr::null_mut()
        }
    }
}

/// Returns an input stream.  The url can be a data: URL or a plain URI
pub fn acquire_stream(
    aurl: &AllowedUrl,
    cancellable: Option<&Cancellable>,
) -> Result<InputStream, LoadingError> {
    let uri = aurl.url().as_str();

    if uri.starts_with("data:") {
        let BinaryData { data, .. } = decode_data_uri(uri)?;

        let stream = MemoryInputStream::new_from_bytes(&GBytes::from_owned(data));
        Ok(stream.upcast::<InputStream>())
    } else {
        let file = GFile::new_for_uri(uri);
        let stream = file.read(cancellable)?;

        Ok(stream.upcast::<InputStream>())
    }
}

/// Returns a chunk of data.  The url can be a data: URL or a plain URI
pub fn acquire_data(
    aurl: &AllowedUrl,
    cancellable: Option<&Cancellable>,
) -> Result<BinaryData, LoadingError> {
    let uri = aurl.url().as_str();

    if uri.starts_with("data:") {
        Ok(decode_data_uri(uri)?)
    } else {
        let file = GFile::new_for_uri(uri);
        let (contents, _etag) = file.load_contents(cancellable)?;

        let (content_type, _uncertain) = gio::content_type_guess(uri, &contents);
        let mime_type = gio::content_type_get_mime_type(&content_type);

        Ok(BinaryData {
            data: contents,
            content_type: mime_type,
        })
    }
}
<commit_msg>Prettify an array comparison<commit_after>use data_url;
use gio_sys;
use glib_sys;
use libc;

use gio::{
    self,
    BufferedInputStream,
    BufferedInputStreamExt,
    Cancellable,
    ConverterInputStream,
    File as GFile,
    FileExt,
    InputStream,
    MemoryInputStream,
    ZlibCompressorFormat,
    ZlibDecompressor,
};
use glib::{self, translate::*, Bytes as GBytes, Cast};
use std::ptr;

use allowed_url::AllowedUrl;
use error::{LoadingError, RsvgError};
use handle::BinaryData;

fn decode_data_uri(uri: &str) -> Result<BinaryData, LoadingError> {
    let data_url = data_url::DataUrl::process(uri).map_err(|_| LoadingError::BadDataUrl)?;

    let mime_type = data_url.mime_type().to_string();

    let (bytes, fragment_id) = data_url
        .decode_to_vec()
        .map_err(|_| LoadingError::BadDataUrl)?;

    // See issue #377 - per the data: URL spec
    // (https://fetch.spec.whatwg.org/#data-urls), those URLs cannot
    // have fragment identifiers.  So, just return an error if we find
    // one.  This probably indicates mis-quoted SVG data inside the
    // data: URL.
    if fragment_id.is_some() {
        return Err(LoadingError::BadDataUrl);
    }

    Ok(BinaryData {
        data: bytes,
        content_type: Some(mime_type),
    })
}

pub fn binary_data_to_glib(
    binary_data: &BinaryData,
    out_mime_type: *mut *mut libc::c_char,
    out_size: *mut usize,
) -> *mut libc::c_char {
    unsafe {
        if !out_mime_type.is_null() {
            *out_mime_type = binary_data.content_type.to_glib_full();
        }

        *out_size = binary_data.data.len();

        ToGlibContainerFromSlice::to_glib_full_from_slice(&binary_data.data) as *mut libc::c_char
    }
}

// Header of a gzip data stream
const GZ_MAGIC_0: u8 = 0x1f;
const GZ_MAGIC_1: u8 = 0x8b;

fn get_input_stream_for_loading(
    stream: InputStream,
    cancellable: Option<Cancellable>,
) -> Result<InputStream, glib::Error> {
    // detect gzipped streams (svgz)

    let buffered = BufferedInputStream::new(&stream);
    let num_read = buffered.fill(2, cancellable.as_ref())?;
    if num_read < 2 {
        // FIXME: this string was localized in the original; localize it
        return Err(glib::Error::new(RsvgError, "Input file is too short"));
    }

    let buf = buffered.peek_buffer();
    assert!(buf.len() >= 2);
    if buf[0..2] == [GZ_MAGIC_0, GZ_MAGIC_1] {
        let decomp = ZlibDecompressor::new(ZlibCompressorFormat::Gzip);
        let converter = ConverterInputStream::new(&buffered, &decomp);
        Ok(converter.upcast::<InputStream>())
    } else {
        Ok(buffered.upcast::<InputStream>())
    }
}

#[no_mangle]
pub unsafe fn rsvg_get_input_stream_for_loading(
    stream: *mut gio_sys::GInputStream,
    cancellable: *mut gio_sys::GCancellable,
    error: *mut *mut glib_sys::GError,
) -> *mut gio_sys::GInputStream {
    let stream = from_glib_borrow(stream);
    let cancellable = from_glib_borrow(cancellable);

    match get_input_stream_for_loading(stream, cancellable) {
        Ok(stream) => stream.to_glib_full(),

        Err(e) => {
            if !error.is_null() {
                *error = e.to_glib_full() as *mut _;
            }

            ptr::null_mut()
        }
    }
}

/// Returns an input stream.  The url can be a data: URL or a plain URI
pub fn acquire_stream(
    aurl: &AllowedUrl,
    cancellable: Option<&Cancellable>,
) -> Result<InputStream, LoadingError> {
    let uri = aurl.url().as_str();

    if uri.starts_with("data:") {
        let BinaryData { data, .. } = decode_data_uri(uri)?;

        let stream = MemoryInputStream::new_from_bytes(&GBytes::from_owned(data));
        Ok(stream.upcast::<InputStream>())
    } else {
        let file = GFile::new_for_uri(uri);
        let stream = file.read(cancellable)?;

        Ok(stream.upcast::<InputStream>())
    }
}

/// Returns a chunk of data.  The url can be a data: URL or a plain URI
pub fn acquire_data(
    aurl: &AllowedUrl,
    cancellable: Option<&Cancellable>,
) -> Result<BinaryData, LoadingError> {
    let uri = aurl.url().as_str();

    if uri.starts_with("data:") {
        Ok(decode_data_uri(uri)?)
    } else {
        let file = GFile::new_for_uri(uri);
        let (contents, _etag) = file.load_contents(cancellable)?;

        let (content_type, _uncertain) = gio::content_type_guess(uri, &contents);
        let mime_type = gio::content_type_get_mime_type(&content_type);

        Ok(BinaryData {
            data: contents,
            content_type: mime_type,
        })
    }
}
<|endoftext|>