<commit_before>use crate::util;
use proc_macro::TokenStream;
use quote::quote;

/// Generate code for the juniper::object macro.
pub fn build_object(args: TokenStream, body: TokenStream, is_internal: bool) -> TokenStream {
    let impl_attrs = match syn::parse::<util::ObjectAttributes>(args) {
        Ok(attrs) => attrs,
        Err(e) => {
            panic!("Invalid attributes:\n{}", e);
        }
    };

    let item = match syn::parse::<syn::Item>(body) {
        Ok(item) => item,
        Err(err) => {
            panic!("Parsing error:\n{}", err);
        }
    };
    let mut _impl = match item {
        syn::Item::Impl(_impl) => _impl,
        _ => {
            panic!("#[juniper::object] can only be applied to impl blocks");
        }
    };

    match _impl.trait_ {
        Some((_, ref path, _)) => {
            let name = path
                .segments
                .iter()
                .map(|segment| segment.ident.to_string())
                .collect::<Vec<_>>()
                .join(".");
            if !(name == "GraphQLObject" || name == "juniper.GraphQLObject") {
                panic!("The impl block must implement the 'GraphQLObject' trait");
            }
        }
        None => {
            // panic!("The impl block must implement the 'GraphQLObject' trait");
        }
    }

    let name = if let Some(ident) = util::name_of_type(&*_impl.self_ty) {
        ident
    } else {
        panic!("Could not determine a name for the object type: specify one with #[juniper::object(name = \"SomeName\")");
    };

    let target_type = *_impl.self_ty.clone();

    let description = impl_attrs
        .description
        .or(util::get_doc_comment(&_impl.attrs));

    let mut definition = util::GraphQLTypeDefiniton {
        name: name.to_string(),
        _type: target_type.clone(),
        context: impl_attrs.context,
        scalar: impl_attrs.scalar,
        description,
        fields: Vec::new(),
        generics: _impl.generics.clone(),
        interfaces: if impl_attrs.interfaces.len() > 0 {
            Some(impl_attrs.interfaces)
        } else {
            None
        },
        include_type_generics: false,
        generic_scalar: false,
        no_async: impl_attrs.no_async,
    };

    for item in _impl.items {
        match item {
            syn::ImplItem::Method(method) => {
                let _type = match &method.sig.output {
                    syn::ReturnType::Type(_, ref t) => (**t).clone(),
                    syn::ReturnType::Default => {
                        panic!(
                            "Invalid field method {}: must return a value",
                            method.sig.ident
                        );
                    }
                };

                let is_async = method.sig.asyncness.is_some();

                let attrs = match util::FieldAttributes::from_attrs(
                    method.attrs,
                    util::FieldAttributeParseMode::Impl,
                ) {
                    Ok(attrs) => attrs,
                    Err(err) => panic!(
                        "Invalid #[graphql(...)] attribute on field {}:\n{}",
                        method.sig.ident, err
                    ),
                };

                let mut args = Vec::new();
                let mut resolve_parts = Vec::new();

                for arg in method.sig.inputs {
                    match arg {
                        syn::FnArg::Receiver(rec) => {
                            if rec.reference.is_none() || rec.mutability.is_some() {
                                panic!(
                                    "Invalid method receiver {}(self, ...): did you mean '&self'?",
                                    method.sig.ident
                                );
                            }
                        }
                        syn::FnArg::Typed(ref captured) => {
                            let (arg_ident, is_mut) = match &*captured.pat {
                                syn::Pat::Ident(ref pat_ident) => {
                                    (&pat_ident.ident, pat_ident.mutability.is_some())
                                }
                                _ => {
                                    panic!("Invalid token for function argument");
                                }
                            };
                            let arg_name = arg_ident.to_string();

                            let context_type = definition.context.as_ref();

                            // Check for executor arguments.
                            if util::type_is_identifier_ref(&captured.ty, "Executor") {
                                resolve_parts.push(quote!(let #arg_ident = executor;));
                            }
                            // Make sure executor is specified as a reference.
                            else if util::type_is_identifier(&captured.ty, "Executor") {
                                panic!("Invalid executor argument: to access the Executor, you need to specify the type as a reference.\nDid you mean &Executor?");
                            }
                            // Check for context arg.
                            else if context_type
                                .clone()
                                .map(|ctx| util::type_is_ref_of(&captured.ty, ctx))
                                .unwrap_or(false)
                            {
                                resolve_parts.push(quote!( let #arg_ident = executor.context(); ));
                            }
                            // Make sure the user does not specify the Context
                            //  without a reference. (&Context)
                            else if context_type
                                .clone()
                                .map(|ctx| ctx == &*captured.ty)
                                .unwrap_or(false)
                            {
                                panic!(
                                    "Invalid context argument: to access the context, you need to specify the type as a reference.\nDid you mean &{}?",
                                    quote!(captured.ty),
                                );
                            } else {
                                // Regular argument.

                                let ty = &captured.ty;
                                // TODO: respect graphql attribute overwrite.
                                let final_name = util::to_camel_case(&arg_name);
                                let expect_text = format!("Internal error: missing argument {} - validation must have failed", &final_name);
                                let mut_modifier = if is_mut { quote!(mut) } else { quote!() };
                                resolve_parts.push(quote!(
                                    let #mut_modifier #arg_ident = args
                                        .get::<#ty>(#final_name)
                                        .expect(#expect_text);
                                ));
                                args.push(util::GraphQLTypeDefinitionFieldArg {
                                    description: attrs.argument(&arg_name).and_then(|arg| {
                                        arg.description.as_ref().map(|d| d.value())
                                    }),
                                    default: attrs
                                        .argument(&arg_name)
                                        .and_then(|arg| arg.default.clone()),
                                    _type: ty.clone(),
                                    name: final_name,
                                })
                            }
                        }
                    }
                }

                let body = &method.block;
                let resolver_code = quote!(
                    #( #resolve_parts )*
                    #body
                );

                let ident = &method.sig.ident;
                let name = attrs
                    .name
                    .unwrap_or_else(|| util::to_camel_case(&ident.to_string()));

                definition.fields.push(util::GraphQLTypeDefinitionField {
                    name,
                    _type,
                    args,
                    description: attrs.description,
                    deprecation: attrs.deprecation,
                    resolver_code,
                    is_type_inferred: false,
                    is_async,
                });
            }
            _ => {
                panic!("Invalid item for GraphQL Object: only type declarations and methods are allowed");
            }
        }
    }
    let juniper_crate_name = if is_internal { "crate" } else { "juniper" };
    definition.into_tokens(juniper_crate_name).into()
}
<commit_msg>Revert `juniper::object` name detection back to master [skip ci]<commit_after>use crate::util;
use proc_macro::TokenStream;
use quote::quote;

/// Generate code for the juniper::object macro.
pub fn build_object(args: TokenStream, body: TokenStream, is_internal: bool) -> TokenStream {
    let impl_attrs = match syn::parse::<util::ObjectAttributes>(args) {
        Ok(attrs) => attrs,
        Err(e) => {
            panic!("Invalid attributes:\n{}", e);
        }
    };

    let item = match syn::parse::<syn::Item>(body) {
        Ok(item) => item,
        Err(err) => {
            panic!("Parsing error:\n{}", err);
        }
    };
    let mut _impl = match item {
        syn::Item::Impl(_impl) => _impl,
        _ => {
            panic!("#[juniper::object] can only be applied to impl blocks");
        }
    };

    match _impl.trait_ {
        Some((_, ref path, _)) => {
            let name = path
                .segments
                .iter()
                .map(|segment| segment.ident.to_string())
                .collect::<Vec<_>>()
                .join(".");
            if !(name == "GraphQLObject" || name == "juniper.GraphQLObject") {
                panic!("The impl block must implement the 'GraphQLObject' trait");
            }
        }
        None => {
            // panic!("The impl block must implement the 'GraphQLObject' trait");
        }
    }

    let name = match impl_attrs.name.as_ref() {
        Some(type_name) => type_name.clone(),
        None => {
            let error_msg = "Could not determine a name for the object type: specify one with #[juniper::object(name = \"SomeName\")";

            let path = match &*_impl.self_ty {
                syn::Type::Path(ref type_path) => &type_path.path,
                syn::Type::Reference(ref reference) => match &*reference.elem {
                    syn::Type::Path(ref type_path) => &type_path.path,
                    syn::Type::TraitObject(ref trait_obj) => {
                        match trait_obj.bounds.iter().nth(0).unwrap() {
                            syn::TypeParamBound::Trait(ref trait_bound) => &trait_bound.path,
                            _ => panic!(error_msg),
                        }
                    }
                    _ => panic!(error_msg),
                },
                _ => panic!(error_msg),
            };

            path.segments.iter().last().unwrap().ident.to_string()
        }
    };

    let target_type = *_impl.self_ty.clone();

    let description = impl_attrs
        .description
        .or(util::get_doc_comment(&_impl.attrs));

    let mut definition = util::GraphQLTypeDefiniton {
        name: name.to_string(),
        _type: target_type.clone(),
        context: impl_attrs.context,
        scalar: impl_attrs.scalar,
        description,
        fields: Vec::new(),
        generics: _impl.generics.clone(),
        interfaces: if impl_attrs.interfaces.len() > 0 {
            Some(impl_attrs.interfaces)
        } else {
            None
        },
        include_type_generics: false,
        generic_scalar: false,
        no_async: impl_attrs.no_async,
    };

    for item in _impl.items {
        match item {
            syn::ImplItem::Method(method) => {
                let _type = match &method.sig.output {
                    syn::ReturnType::Type(_, ref t) => (**t).clone(),
                    syn::ReturnType::Default => {
                        panic!(
                            "Invalid field method {}: must return a value",
                            method.sig.ident
                        );
                    }
                };

                let is_async = method.sig.asyncness.is_some();

                let attrs = match util::FieldAttributes::from_attrs(
                    method.attrs,
                    util::FieldAttributeParseMode::Impl,
                ) {
                    Ok(attrs) => attrs,
                    Err(err) => panic!(
                        "Invalid #[graphql(...)] attribute on field {}:\n{}",
                        method.sig.ident, err
                    ),
                };

                let mut args = Vec::new();
                let mut resolve_parts = Vec::new();

                for arg in method.sig.inputs {
                    match arg {
                        syn::FnArg::Receiver(rec) => {
                            if rec.reference.is_none() || rec.mutability.is_some() {
                                panic!(
                                    "Invalid method receiver {}(self, ...): did you mean '&self'?",
                                    method.sig.ident
                                );
                            }
                        }
                        syn::FnArg::Typed(ref captured) => {
                            let (arg_ident, is_mut) = match &*captured.pat {
                                syn::Pat::Ident(ref pat_ident) => {
                                    (&pat_ident.ident, pat_ident.mutability.is_some())
                                }
                                _ => {
                                    panic!("Invalid token for function argument");
                                }
                            };
                            let arg_name = arg_ident.to_string();

                            let context_type = definition.context.as_ref();

                            // Check for executor arguments.
                            if util::type_is_identifier_ref(&captured.ty, "Executor") {
                                resolve_parts.push(quote!(let #arg_ident = executor;));
                            }
                            // Make sure executor is specified as a reference.
                            else if util::type_is_identifier(&captured.ty, "Executor") {
                                panic!("Invalid executor argument: to access the Executor, you need to specify the type as a reference.\nDid you mean &Executor?");
                            }
                            // Check for context arg.
                            else if context_type
                                .clone()
                                .map(|ctx| util::type_is_ref_of(&captured.ty, ctx))
                                .unwrap_or(false)
                            {
                                resolve_parts.push(quote!( let #arg_ident = executor.context(); ));
                            }
                            // Make sure the user does not specify the Context
                            //  without a reference. (&Context)
                            else if context_type
                                .clone()
                                .map(|ctx| ctx == &*captured.ty)
                                .unwrap_or(false)
                            {
                                panic!(
                                    "Invalid context argument: to access the context, you need to specify the type as a reference.\nDid you mean &{}?",
                                    quote!(captured.ty),
                                );
                            } else {
                                // Regular argument.

                                let ty = &captured.ty;
                                // TODO: respect graphql attribute overwrite.
                                let final_name = util::to_camel_case(&arg_name);
                                let expect_text = format!("Internal error: missing argument {} - validation must have failed", &final_name);
                                let mut_modifier = if is_mut { quote!(mut) } else { quote!() };
                                resolve_parts.push(quote!(
                                    let #mut_modifier #arg_ident = args
                                        .get::<#ty>(#final_name)
                                        .expect(#expect_text);
                                ));
                                args.push(util::GraphQLTypeDefinitionFieldArg {
                                    description: attrs.argument(&arg_name).and_then(|arg| {
                                        arg.description.as_ref().map(|d| d.value())
                                    }),
                                    default: attrs
                                        .argument(&arg_name)
                                        .and_then(|arg| arg.default.clone()),
                                    _type: ty.clone(),
                                    name: final_name,
                                })
                            }
                        }
                    }
                }

                let body = &method.block;
                let resolver_code = quote!(
                    #( #resolve_parts )*
                    #body
                );

                let ident = &method.sig.ident;
                let name = attrs
                    .name
                    .unwrap_or_else(|| util::to_camel_case(&ident.to_string()));

                definition.fields.push(util::GraphQLTypeDefinitionField {
                    name,
                    _type,
                    args,
                    description: attrs.description,
                    deprecation: attrs.deprecation,
                    resolver_code,
                    is_type_inferred: false,
                    is_async,
                });
            }
            _ => {
                panic!("Invalid item for GraphQL Object: only type declarations and methods are allowed");
            }
        }
    }
    let juniper_crate_name = if is_internal { "crate" } else { "juniper" };
    definition.into_tokens(juniper_crate_name).into()
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use collections::hashmap::HashMap;
use cgmath::vector::Vector2;
use core::types::{Size2, MInt, UnitId, PlayerId, MapPos};
use core::conf::Config;

pub enum Command {
    CommandMove(UnitId, Vec<MapPos>),
    CommandEndTurn,
    CommandCreateUnit(MapPos),
    CommandAttackUnit(UnitId, UnitId),
}

pub enum Event {
    EventMove(UnitId, Vec<MapPos>),
    EventEndTurn(PlayerId, PlayerId), // old_id, new_id
    EventCreateUnit(UnitId, MapPos, PlayerId),
    EventAttackUnit(UnitId, UnitId),
}

pub struct Player {
    pub id: PlayerId,
}

pub struct Unit {
    pub id: UnitId,
    pub pos: MapPos,
    pub player_id: PlayerId,
}

pub struct Core {
    units: HashMap<UnitId, Unit>,
    players: Vec<Player>,
    current_player_id: PlayerId,
    core_event_list: Vec<~CoreEvent>,
    event_lists: HashMap<PlayerId, Vec<Event>>,
    map_size: Size2<MInt>,
}

fn get_event_lists() -> HashMap<PlayerId, Vec<Event>> {
    let mut map = HashMap::new();
    map.insert(PlayerId{id: 0}, Vec::new());
    map.insert(PlayerId{id: 1}, Vec::new());
    map
}

impl Core {
    pub fn new() -> ~Core {
        let config = Config::new(&Path::new("conf_core.json"));
        let map_size = config.get("map_size");
        let mut core = ~Core {
            units: HashMap::new(),
            players: vec!(
                Player{id: PlayerId{id: 0}},
                Player{id: PlayerId{id: 1}},
            ),
            current_player_id: PlayerId{id: 0},
            core_event_list: Vec::new(),
            event_lists: get_event_lists(),
            map_size: map_size,
        };
        core.add_unit(Vector2{x: 0, y: 0}, PlayerId{id: 0});
        core.add_unit(Vector2{x: 0, y: 1}, PlayerId{id: 0});
        core.add_unit(Vector2{x: 2, y: 0}, PlayerId{id: 1});
        core.add_unit(Vector2{x: 2, y: 2}, PlayerId{id: 1});
        core
    }

    fn add_unit(&mut self, pos: MapPos, player_id: PlayerId) {
        let core_event = CoreEventCreateUnit::new(
            self, pos, player_id);
        self.do_core_event(core_event);
    }

    pub fn map_size(&self) -> Size2<MInt> {
        self.map_size
    }

    pub fn player_id(&self) -> PlayerId {
        self.current_player_id
    }

    pub fn get_event(&mut self) -> Option<Event> {
        let list = self.event_lists.get_mut(&self.current_player_id);
        list.shift()
    }

    fn command_to_core_event(&self, command: Command) -> ~CoreEvent {
        match command {
            CommandEndTurn => {
                CoreEventEndTurn::new(self) as ~CoreEvent
            },
            CommandCreateUnit(pos) => {
                CoreEventCreateUnit::new(
                    self,
                    pos,
                    self.current_player_id,
                ) as ~CoreEvent
            },
            CommandMove(unit_id, path) => {
                CoreEventMove::new(self, unit_id, path) as ~CoreEvent
            },
            CommandAttackUnit(attacker_id, defender_id) => {
                CoreEventAttackUnit::new(
                    self,
                    attacker_id,
                    defender_id,
                ) as ~CoreEvent
            },
        }
    }

    pub fn do_command(&mut self, command: Command) {
        let core_event = self.command_to_core_event(command);
        self.do_core_event(core_event);
    }

    fn do_core_event(&mut self, core_event: ~CoreEvent) {
        self.core_event_list.push(core_event);
        self.make_events();
    }

    fn make_events(&mut self) {
        while self.core_event_list.len() != 0 {
            let event = self.core_event_list.pop().unwrap();
            event.apply(self);
            for player in self.players.iter() {
                let event_list = self.event_lists.get_mut(&player.id);
                event_list.push(event.to_event());
            }
        }
    }
}

trait CoreEvent {
    fn apply(&self, core: &mut Core);
    fn to_event(&self) -> Event;
    // TODO: fn is_visible(&self) -> MBool;
}

struct CoreEventMove {
    unit_id: UnitId,
    path: Vec<MapPos>,
}

impl CoreEventMove {
    fn new(_: &Core, unit_id: UnitId, path: Vec<MapPos>) -> ~CoreEventMove {
        ~CoreEventMove {
            path: path,
            unit_id: unit_id,
        }
    }
}

impl CoreEvent for CoreEventMove {
    fn to_event(&self) -> Event {
        EventMove(self.unit_id, self.path.clone())
    }

    fn apply(&self, core: &mut Core) {
        let unit = core.units.get_mut(&self.unit_id);
        unit.pos = *self.path.last().unwrap();
    }
}

struct CoreEventEndTurn {
    old_id: PlayerId,
    new_id: PlayerId,
}

impl CoreEventEndTurn {
    fn new(core: &Core) -> ~CoreEventEndTurn {
        let old_id = core.current_player_id.id;
        let max_id = core.players.len() as MInt;
        let new_id = if old_id + 1 == max_id { 0 } else { old_id + 1 };
        ~CoreEventEndTurn {
            old_id: PlayerId{id: old_id},
            new_id: PlayerId{id: new_id},
        }
    }
}

impl CoreEvent for CoreEventEndTurn {
    fn to_event(&self) -> Event {
        EventEndTurn(self.old_id, self.new_id)
    }

    fn apply(&self, core: &mut Core) {
        // core.deselected_any_units();
        for player in core.players.iter() {
            if player.id == self.new_id {
                if core.current_player_id == self.old_id {
                    core.current_player_id = player.id;
                }
                return;
            }
        }
    }
}

struct CoreEventCreateUnit {
    pos: MapPos,
    id: UnitId,
    player_id: PlayerId,
}

impl CoreEventCreateUnit {
    fn new(
        core: &Core,
        pos: MapPos,
        player_id: PlayerId
    ) -> ~CoreEventCreateUnit {
        let new_id = match core.units.keys().max_by(|&n| n) {
            Some(n) => n.id + 1,
            None => 0,
        };
        ~CoreEventCreateUnit {
            id: UnitId{id: new_id},
            pos: pos,
            player_id: player_id,
        }
    }
}

impl CoreEvent for CoreEventCreateUnit {
    fn to_event(&self) -> Event {
        EventCreateUnit(self.id, self.pos, self.player_id)
    }

    fn apply(&self, core: &mut Core) {
        assert!(core.units.find(&self.id).is_none());
        core.units.insert(self.id, Unit {
            id: self.id,
            pos: self.pos,
            player_id: core.current_player_id,
        });
    }
}

struct CoreEventAttackUnit {
    attacker_id: UnitId,
    defender_id: UnitId,
}

impl CoreEventAttackUnit {
    fn new(
        _: &Core,
        attacker_id: UnitId,
        defender_id: UnitId
    ) -> ~CoreEventAttackUnit {
        ~CoreEventAttackUnit {
            attacker_id: attacker_id,
            defender_id: defender_id,
        }
    }
}

impl CoreEvent for CoreEventAttackUnit {
    fn to_event(&self) -> Event {
        EventAttackUnit(self.attacker_id, self.defender_id)
    }

    fn apply(&self, core: &mut Core) {
        assert!(core.units.find(&self.defender_id).is_some());
        core.units.remove(&self.defender_id);
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>core.rs: Added get_player_list() func<commit_after>// See LICENSE file for copyright and license details.

use collections::hashmap::HashMap;
use cgmath::vector::Vector2;
use core::types::{Size2, MInt, UnitId, PlayerId, MapPos};
use core::conf::Config;

pub enum Command {
    CommandMove(UnitId, Vec<MapPos>),
    CommandEndTurn,
    CommandCreateUnit(MapPos),
    CommandAttackUnit(UnitId, UnitId),
}

pub enum Event {
    EventMove(UnitId, Vec<MapPos>),
    EventEndTurn(PlayerId, PlayerId), // old_id, new_id
    EventCreateUnit(UnitId, MapPos, PlayerId),
    EventAttackUnit(UnitId, UnitId),
}

pub struct Player {
    pub id: PlayerId,
}

pub struct Unit {
    pub id: UnitId,
    pub pos: MapPos,
    pub player_id: PlayerId,
}

pub struct Core {
    units: HashMap<UnitId, Unit>,
    players: Vec<Player>,
    current_player_id: PlayerId,
    core_event_list: Vec<~CoreEvent>,
    event_lists: HashMap<PlayerId, Vec<Event>>,
    map_size: Size2<MInt>,
}

fn get_event_lists() -> HashMap<PlayerId, Vec<Event>> {
    let mut map = HashMap::new();
    map.insert(PlayerId{id: 0}, Vec::new());
    map.insert(PlayerId{id: 1}, Vec::new());
    map
}

fn get_players_list() -> Vec<Player> {
    vec!(
        Player{id: PlayerId{id: 0}},
        Player{id: PlayerId{id: 1}},
    )
}

impl Core {
    pub fn new() -> ~Core {
        let config = Config::new(&Path::new("conf_core.json"));
        let map_size = config.get("map_size");
        let mut core = ~Core {
            units: HashMap::new(),
            players: get_players_list(),
            current_player_id: PlayerId{id: 0},
            core_event_list: Vec::new(),
            event_lists: get_event_lists(),
            map_size: map_size,
        };
        core.add_unit(Vector2{x: 0, y: 0}, PlayerId{id: 0});
        core.add_unit(Vector2{x: 0, y: 1}, PlayerId{id: 0});
        core.add_unit(Vector2{x: 2, y: 0}, PlayerId{id: 1});
        core.add_unit(Vector2{x: 2, y: 2}, PlayerId{id: 1});
        core
    }

    fn add_unit(&mut self, pos: MapPos, player_id: PlayerId) {
        let core_event = CoreEventCreateUnit::new(
            self, pos, player_id);
        self.do_core_event(core_event);
    }

    pub fn map_size(&self) -> Size2<MInt> {
        self.map_size
    }

    pub fn player_id(&self) -> PlayerId {
        self.current_player_id
    }

    pub fn get_event(&mut self) -> Option<Event> {
        let list = self.event_lists.get_mut(&self.current_player_id);
        list.shift()
    }

    fn command_to_core_event(&self, command: Command) -> ~CoreEvent {
        match command {
            CommandEndTurn => {
                CoreEventEndTurn::new(self) as ~CoreEvent
            },
            CommandCreateUnit(pos) => {
                CoreEventCreateUnit::new(
                    self,
                    pos,
                    self.current_player_id,
                ) as ~CoreEvent
            },
            CommandMove(unit_id, path) => {
                CoreEventMove::new(self, unit_id, path) as ~CoreEvent
            },
            CommandAttackUnit(attacker_id, defender_id) => {
                CoreEventAttackUnit::new(
                    self,
                    attacker_id,
                    defender_id,
                ) as ~CoreEvent
            },
        }
    }

    pub fn do_command(&mut self, command: Command) {
        let core_event = self.command_to_core_event(command);
        self.do_core_event(core_event);
    }

    fn do_core_event(&mut self, core_event: ~CoreEvent) {
        self.core_event_list.push(core_event);
        self.make_events();
    }

    fn make_events(&mut self) {
        while self.core_event_list.len() != 0 {
            let event = self.core_event_list.pop().unwrap();
            event.apply(self);
            for player in self.players.iter() {
                let event_list = self.event_lists.get_mut(&player.id);
                event_list.push(event.to_event());
            }
        }
    }
}

trait CoreEvent {
    fn apply(&self, core: &mut Core);
    fn to_event(&self) -> Event;
    // TODO: fn is_visible(&self) -> MBool;
}

struct CoreEventMove {
    unit_id: UnitId,
    path: Vec<MapPos>,
}

impl CoreEventMove {
    fn new(_: &Core, unit_id: UnitId, path: Vec<MapPos>) -> ~CoreEventMove {
        ~CoreEventMove {
            path: path,
            unit_id: unit_id,
        }
    }
}

impl CoreEvent for CoreEventMove {
    fn to_event(&self) -> Event {
        EventMove(self.unit_id, self.path.clone())
    }

    fn apply(&self, core: &mut Core) {
        let unit = core.units.get_mut(&self.unit_id);
        unit.pos = *self.path.last().unwrap();
    }
}

struct CoreEventEndTurn {
    old_id: PlayerId,
    new_id: PlayerId,
}

impl CoreEventEndTurn {
    fn new(core: &Core) -> ~CoreEventEndTurn {
        let old_id = core.current_player_id.id;
        let max_id = core.players.len() as MInt;
        let new_id = if old_id + 1 == max_id { 0 } else { old_id + 1 };
        ~CoreEventEndTurn {
            old_id: PlayerId{id: old_id},
            new_id: PlayerId{id: new_id},
        }
    }
}

impl CoreEvent for CoreEventEndTurn {
    fn to_event(&self) -> Event {
        EventEndTurn(self.old_id, self.new_id)
    }

    fn apply(&self, core: &mut Core) {
        // core.deselected_any_units();
        for player in core.players.iter() {
            if player.id == self.new_id {
                if core.current_player_id == self.old_id {
                    core.current_player_id = player.id;
                }
                return;
            }
        }
    }
}

struct CoreEventCreateUnit {
    pos: MapPos,
    id: UnitId,
    player_id: PlayerId,
}

impl CoreEventCreateUnit {
    fn new(
        core: &Core,
        pos: MapPos,
        player_id: PlayerId
    ) -> ~CoreEventCreateUnit {
        let new_id = match core.units.keys().max_by(|&n| n) {
            Some(n) => n.id + 1,
            None => 0,
        };
        ~CoreEventCreateUnit {
            id: UnitId{id: new_id},
            pos: pos,
            player_id: player_id,
        }
    }
}

impl CoreEvent for CoreEventCreateUnit {
    fn to_event(&self) -> Event {
        EventCreateUnit(self.id, self.pos, self.player_id)
    }

    fn apply(&self, core: &mut Core) {
        assert!(core.units.find(&self.id).is_none());
        core.units.insert(self.id, Unit {
            id: self.id,
            pos: self.pos,
            player_id: core.current_player_id,
        });
    }
}

struct CoreEventAttackUnit {
    attacker_id: UnitId,
    defender_id: UnitId,
}

impl CoreEventAttackUnit {
    fn new(
        _: &Core,
        attacker_id: UnitId,
        defender_id: UnitId
    ) -> ~CoreEventAttackUnit {
        ~CoreEventAttackUnit {
            attacker_id: attacker_id,
            defender_id: defender_id,
        }
    }
}

impl CoreEvent for CoreEventAttackUnit {
    fn to_event(&self) -> Event {
        EventAttackUnit(self.attacker_id, self.defender_id)
    }

    fn apply(&self, core: &mut Core) {
        assert!(core.units.find(&self.defender_id).is_some());
        core.units.remove(&self.defender_id);
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use rustc::mir::visit::Visitor;
use rustc::mir::{self, Local, Location};
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::bit_set::BitSet;
use syntax_pos::DUMMY_SP;

use crate::dataflow::{self, GenKillSet};

/// Whether a borrow to a `Local` has been created that could allow that `Local` to be mutated
/// indirectly. This could either be a mutable reference (`&mut`) or a shared borrow if the type of
/// that `Local` allows interior mutability.
///
/// If this returns `false` for a `Local` at a given `Location`, the user can assume that `Local`
/// has not been mutated as a result of an indirect assignment (`*p = x`) or as a side-effect of a
/// function call or drop terminator.
#[derive(Copy, Clone)]
pub struct IndirectlyMutableLocals<'mir, 'tcx> {
    body: &'mir mir::Body<'tcx>,
    tcx: TyCtxt<'tcx>,
    param_env: ty::ParamEnv<'tcx>,
}

impl<'mir, 'tcx> IndirectlyMutableLocals<'mir, 'tcx> {
    pub fn new(
        tcx: TyCtxt<'tcx>,
        body: &'mir mir::Body<'tcx>,
        param_env: ty::ParamEnv<'tcx>,
    ) -> Self {
        IndirectlyMutableLocals { body, tcx, param_env }
    }

    fn transfer_function<'a>(
        &self,
        trans: &'a mut GenKillSet<Local>,
    ) -> TransferFunction<'a, 'mir, 'tcx> {
        TransferFunction {
            body: self.body,
            tcx: self.tcx,
            param_env: self.param_env,
            trans
        }
    }
}

impl<'mir, 'tcx> dataflow::BitDenotation<'tcx> for IndirectlyMutableLocals<'mir, 'tcx> {
    type Idx = Local;

    fn name() -> &'static str { "mut_borrowed_locals" }

    fn bits_per_block(&self) -> usize {
        self.body.local_decls.len()
    }

    fn start_block_effect(&self, _entry_set: &mut BitSet<Local>) {
        // Nothing is borrowed on function entry
    }

    fn statement_effect(
        &self,
        trans: &mut GenKillSet<Local>,
        loc: Location,
    ) {
        let stmt = &self.body[loc.block].statements[loc.statement_index];
        self.transfer_function(trans).visit_statement(stmt, loc);
    }

    fn terminator_effect(
        &self,
        trans: &mut GenKillSet<Local>,
        loc: Location,
    ) {
        let terminator = self.body[loc.block].terminator();
        self.transfer_function(trans).visit_terminator(terminator, loc);
    }

    fn propagate_call_return(
        &self,
        _in_out: &mut BitSet<Local>,
        _call_bb: mir::BasicBlock,
        _dest_bb: mir::BasicBlock,
        _dest_place: &mir::Place<'tcx>,
    ) {
        // Nothing to do when a call returns successfully
    }
}

impl<'mir, 'tcx> dataflow::BottomValue for IndirectlyMutableLocals<'mir, 'tcx> {
    // bottom = unborrowed
    const BOTTOM_VALUE: bool = false;
}

/// A `Visitor` that defines the transfer function for `IndirectlyMutableLocals`.
struct TransferFunction<'a, 'mir, 'tcx> {
    trans: &'a mut GenKillSet<Local>,
    body: &'mir mir::Body<'tcx>,
    tcx: TyCtxt<'tcx>,
    param_env: ty::ParamEnv<'tcx>,
}

impl<'tcx> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx> {
    fn visit_rvalue(
        &mut self,
        rvalue: &mir::Rvalue<'tcx>,
        location: Location,
    ) {
        if let mir::Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue {
            let is_mut = match kind {
                mir::BorrowKind::Mut { .. } => true,

                | mir::BorrowKind::Shared
                | mir::BorrowKind::Shallow
                | mir::BorrowKind::Unique
                => {
                    !borrowed_place
                        .ty(self.body, self.tcx)
                        .ty
                        .is_freeze(self.tcx, self.param_env, DUMMY_SP)
                }
            };

            if is_mut {
                match borrowed_place.base {
                    mir::PlaceBase::Local(borrowed_local) if !borrowed_place.is_indirect()
                        => self.trans.gen(borrowed_local),

                    _ => (),
                }
            }
        }

        self.super_rvalue(rvalue, location);
    }

    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
        self.super_terminator(terminator, location);

        match &terminator.kind {
            // Drop terminators borrow the location
            mir::TerminatorKind::Drop { location: dropped_place, .. } |
            mir::TerminatorKind::DropAndReplace { location: dropped_place, .. } => {
                match dropped_place.base {
                    mir::PlaceBase::Local(dropped_local) if !dropped_place.is_indirect()
                        => self.trans.gen(dropped_local),

                    _ => (),
                }
            }
            _ => (),
        }
    }
}
<commit_msg>Don't treat locals as mutably borrowed after they're dropped<commit_after>use rustc::mir::visit::Visitor;
use rustc::mir::{self, Local, Location};
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::bit_set::BitSet;
use syntax_pos::DUMMY_SP;

use crate::dataflow::{self, GenKillSet};

/// Whether a borrow to a `Local` has been created that could allow that `Local` to be mutated
/// indirectly. This could either be a mutable reference (`&mut`) or a shared borrow if the type of
/// that `Local` allows interior mutability.
///
/// If this returns `false` for a `Local` at a given `Location`, the user can assume that `Local`
/// has not been mutated as a result of an indirect assignment (`*p = x`) or as a side-effect of a
/// function call or drop terminator.
#[derive(Copy, Clone)]
pub struct IndirectlyMutableLocals<'mir, 'tcx> {
    body: &'mir mir::Body<'tcx>,
    tcx: TyCtxt<'tcx>,
    param_env: ty::ParamEnv<'tcx>,
}

impl<'mir, 'tcx> IndirectlyMutableLocals<'mir, 'tcx> {
    pub fn new(
        tcx: TyCtxt<'tcx>,
        body: &'mir mir::Body<'tcx>,
        param_env: ty::ParamEnv<'tcx>,
    ) -> Self {
        IndirectlyMutableLocals { body, tcx, param_env }
    }

    fn transfer_function<'a>(
        &self,
        trans: &'a mut GenKillSet<Local>,
    ) -> TransferFunction<'a, 'mir, 'tcx> {
        TransferFunction {
            body: self.body,
            tcx: self.tcx,
            param_env: self.param_env,
            trans
        }
    }
}

impl<'mir, 'tcx> dataflow::BitDenotation<'tcx> for IndirectlyMutableLocals<'mir, 'tcx> {
    type Idx = Local;

    fn name() -> &'static str { "mut_borrowed_locals" }

    fn bits_per_block(&self) -> usize {
        self.body.local_decls.len()
    }

    fn start_block_effect(&self, _entry_set: &mut BitSet<Local>) {
        // Nothing is borrowed on function entry
    }

    fn statement_effect(
        &self,
        trans: &mut GenKillSet<Local>,
        loc: Location,
    ) {
        let stmt = &self.body[loc.block].statements[loc.statement_index];
        self.transfer_function(trans).visit_statement(stmt, loc);
    }

    fn terminator_effect(
        &self,
        trans: &mut GenKillSet<Local>,
        loc: Location,
    ) {
        let terminator = self.body[loc.block].terminator();
        self.transfer_function(trans).visit_terminator(terminator, loc);
    }

    fn propagate_call_return(
        &self,
        _in_out: &mut BitSet<Local>,
        _call_bb: mir::BasicBlock,
        _dest_bb: mir::BasicBlock,
        _dest_place: &mir::Place<'tcx>,
    ) {
        // Nothing to do when a call returns successfully
    }
}

impl<'mir, 'tcx> dataflow::BottomValue for IndirectlyMutableLocals<'mir, 'tcx> {
    // bottom = unborrowed
    const BOTTOM_VALUE: bool = false;
}

/// A `Visitor` that defines the transfer function for `IndirectlyMutableLocals`.
struct TransferFunction<'a, 'mir, 'tcx> {
    trans: &'a mut GenKillSet<Local>,
    body: &'mir mir::Body<'tcx>,
    tcx: TyCtxt<'tcx>,
    param_env: ty::ParamEnv<'tcx>,
}

impl<'tcx> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx> {
    fn visit_rvalue(
        &mut self,
        rvalue: &mir::Rvalue<'tcx>,
        location: Location,
    ) {
        if let mir::Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue {
            let is_mut = match kind {
                mir::BorrowKind::Mut { .. } => true,

                | mir::BorrowKind::Shared
                | mir::BorrowKind::Shallow
                | mir::BorrowKind::Unique
                => {
                    !borrowed_place
                        .ty(self.body, self.tcx)
                        .ty
                        .is_freeze(self.tcx, self.param_env, DUMMY_SP)
                }
            };

            if is_mut {
                match borrowed_place.base {
                    mir::PlaceBase::Local(borrowed_local) if !borrowed_place.is_indirect()
                        => self.trans.gen(borrowed_local),

                    _ => (),
                }
            }
        }

        self.super_rvalue(rvalue, location);
    }

    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
        self.super_terminator(terminator, location);

        if let mir::TerminatorKind::Drop { location: _, .. }
             | mir::TerminatorKind::DropAndReplace { location: _, .. } = &terminator.kind
        {
            // Although drop terminators mutably borrow the location being dropped, that borrow
            // cannot live beyond the drop terminator because the dropped location is invalidated.
        }
    }
}
<|endoftext|>


<commit_before>//! A channel for sending a single message between asynchronous tasks.

use futures_core::future::Future;
use futures_core::task::{self, Poll, Waker};
use std::marker::Unpin;
use std::mem::PinMut;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::SeqCst;
use std::error::Error;
use std::fmt;

use crate::lock::Lock;

/// A future for a value that will be provided by another asynchronous task.
///
/// This is created by the [`channel`](channel) function.
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct Receiver<T> {
    inner: Arc<Inner<T>>,
}

/// A means of transmitting a single value to another task.
///
/// This is created by the [`channel`](channel) function.
#[derive(Debug)]
pub struct Sender<T> {
    inner: Arc<Inner<T>>,
}

// The channels do not ever project PinMut to the inner T
impl<T> Unpin for Receiver<T> {}
impl<T> Unpin for Sender<T> {}

/// Internal state of the `Receiver`/`Sender` pair above. This is all used as
/// the internal synchronization between the two for send/recv operations.
#[derive(Debug)]
struct Inner<T> {
    /// Indicates whether this oneshot is complete yet. This is filled in both
    /// by `Sender::drop` and by `Receiver::drop`, and both sides interpret it
    /// appropriately.
    ///
    /// For `Receiver`, if this is `true`, then it's guaranteed that `data` is
    /// unlocked and ready to be inspected.
    ///
    /// For `Sender` if this is `true` then the oneshot has gone away and it
    /// can return ready from `poll_cancel`.
    complete: AtomicBool,

    /// The actual data being transferred as part of this `Receiver`. This is
    /// filled in by `Sender::complete` and read by `Receiver::poll`.
    ///
    /// Note that this is protected by `Lock`, but it is in theory safe to
    /// replace with an `UnsafeCell` as it's actually protected by `complete`
    /// above. I wouldn't recommend doing this, however, unless someone is
    /// supremely confident in the various atomic orderings here and there.
    data: Lock<Option<T>>,

    /// Field to store the task which is blocked in `Receiver::poll`.
    ///
    /// This is filled in when a oneshot is polled but not ready yet. Note that
    /// the `Lock` here, unlike in `data` above, is important to resolve races.
    /// Both the `Receiver` and the `Sender` halves understand that if they
    /// can't acquire the lock then some important interference is happening.
    rx_task: Lock<Option<Waker>>,

    /// Like `rx_task` above, except for the task blocked in
    /// `Sender::poll_cancel`. Additionally, `Lock` cannot be `UnsafeCell`.
    tx_task: Lock<Option<Waker>>,
}

/// Creates a new one-shot channel for sending values across asynchronous tasks.
///
/// This function is similar to Rust's channel constructor found in the standard
/// library. Two halves are returned, the first of which is a `Sender` handle,
/// used to signal the end of a computation and provide its value. The second
/// half is a `Receiver` which implements the `Future` trait, resolving to the
/// value that was given to the `Sender` handle.
///
/// Each half can be separately owned and sent across tasks.
///
/// # Examples
///
/// ```
/// use futures::channel::oneshot;
/// use futures::prelude::*;
/// use std::thread;
///
/// fn main() {
///     let (sender, receiver) = oneshot::channel::<i32>();
///
/// # let t =
///     thread::spawn(|| {
///         let future = receiver.map(|i| {
///             println!("got: {:?}", i);
///         });
///         // ...
/// # return future;
///     });
///
///     sender.send(3).unwrap();
/// # futures::executor::block_on(t.join().unwrap());
/// }
/// ```
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
    let inner = Arc::new(Inner::new());
    let receiver = Receiver {
        inner: inner.clone(),
    };
    let sender = Sender {
        inner,
    };
    (sender, receiver)
}

impl<T> Inner<T> {
    fn new() -> Inner<T> {
        Inner {
            complete: AtomicBool::new(false),
            data: Lock::new(None),
            rx_task: Lock::new(None),
            tx_task: Lock::new(None),
        }
    }

    fn send(&self, t: T) -> Result<(), T> {
        if self.complete.load(SeqCst) {
            return Err(t)
        }

        // Note that this lock acquisition may fail if the receiver
        // is closed and sets the `complete` flag to true, whereupon
        // the receiver may call `poll()`.
        if let Some(mut slot) = self.data.try_lock() {
            assert!(slot.is_none());
            *slot = Some(t);
            drop(slot);

            // If the receiver called `close()` between the check at the
            // start of the function, and the lock being released, then
            // the receiver may not be around to receive it, so try to
            // pull it back out.
            if self.complete.load(SeqCst) {
                // If lock acquisition fails, then receiver is actually
                // receiving it, so we're good.
                if let Some(mut slot) = self.data.try_lock() {
                    if let Some(t) = slot.take() {
                        return Err(t);
                    }
                }
            }
            Ok(())
        } else {
            // Must have been closed
            Err(t)
        }
    }

    fn poll_cancel(&self, cx: &mut task::Context) -> Poll<()> {
        // Fast path up first, just read the flag and see if our other half is
        // gone. This flag is set both in our destructor and the oneshot
        // destructor, but our destructor hasn't run yet so if it's set then the
        // oneshot is gone.
        if self.complete.load(SeqCst) {
            return Poll::Ready(())
        }

        // If our other half is not gone then we need to park our current task
        // and move it into the `notify_cancel` slot to get notified when it's
        // actually gone.
        //
        // If `try_lock` fails, then the `Receiver` is in the process of using
        // it, so we can deduce that it's now in the process of going away and
        // hence we're canceled. If it succeeds then we just store our handle.
        //
        // Crucially we then check `oneshot_gone` *again* before we return.
        // While we were storing our handle inside `notify_cancel` the
        // `Receiver` may have been dropped. The first thing it does is set the
        // flag, and if it fails to acquire the lock it assumes that we'll see
        // the flag later on. So... we then try to see the flag later on!
        let handle = cx.waker().clone();
        match self.tx_task.try_lock() {
            Some(mut p) => *p = Some(handle),
            None => return Poll::Ready(()),
        }
        if self.complete.load(SeqCst) {
            Poll::Ready(())
        } else {
            Poll::Pending
        }
    }

    fn is_canceled(&self) -> bool {
        self.complete.load(SeqCst)
    }

    fn drop_tx(&self) {
        // Flag that we're a completed `Sender` and try to wake up a receiver.
        // Whether or not we actually stored any data will get picked up and
        // translated to either an item or cancellation.
        //
        // Note that if we fail to acquire the `rx_task` lock then that means
        // we're in one of two situations:
        //
        // 1. The receiver is trying to block in `poll`
        // 2. The receiver is being dropped
        //
        // In the first case it'll check the `complete` flag after it's done
        // blocking to see if it succeeded. In the latter case we don't need to
        // wake up anyone anyway. So in both cases it's ok to ignore the `None`
        // case of `try_lock` and bail out.
        //
        // The first case crucially depends on `Lock` using `SeqCst` ordering
        // under the hood. If it instead used `Release` / `Acquire` ordering,
        // then it would not necessarily synchronize with `inner.complete`
        // and deadlock might be possible, as was observed in
        // https://github.com/rust-lang-nursery/futures-rs/pull/219.
        self.complete.store(true, SeqCst);
        if let Some(mut slot) = self.rx_task.try_lock() {
            if let Some(task) = slot.take() {
                drop(slot);
                task.wake();
            }
        }
    }

    fn close_rx(&self) {
        // Flag our completion and then attempt to wake up the sender if it's
        // blocked. See comments in `drop` below for more info
        self.complete.store(true, SeqCst);
        if let Some(mut handle) = self.tx_task.try_lock() {
            if let Some(task) = handle.take() {
                drop(handle);
                task.wake()
            }
        }
    }

    fn try_recv(&self) -> Result<Option<T>, Canceled> {
        // If we're complete, either `::close_rx` or `::drop_tx` was called.
        // We can assume a successful send if data is present.
        if self.complete.load(SeqCst) {
            if let Some(mut slot) = self.data.try_lock() {
                if let Some(data) = slot.take() {
                    return Ok(Some(data));
                }
            }
            Err(Canceled)
        } else {
            Ok(None)
        }
    }

    fn recv(&self, cx: &mut task::Context) -> Poll<Result<T, Canceled>> {
        // Check to see if some data has arrived. If it hasn't then we need to
        // block our task.
        //
        // Note that the acquisition of the `rx_task` lock might fail below, but
        // the only situation where this can happen is during `Sender::drop`
        // when we are indeed completed already. If that's happening then we
        // know we're completed so keep going.
        let done = if self.complete.load(SeqCst) {
            true
        } else {
            let task = cx.waker().clone();
            match self.rx_task.try_lock() {
                Some(mut slot) => { *slot = Some(task); false },
                None => true,
            }
        };

        // If we're `done` via one of the paths above, then look at the data and
        // figure out what the answer is. If, however, we stored `rx_task`
        // successfully above we need to check again if we're completed in case
        // a message was sent while `rx_task` was locked and couldn't notify us
        // otherwise.
        //
        // If we're not done, and we're not complete, though, then we've
        // successfully blocked our task and we return `Pending`.
        if done || self.complete.load(SeqCst) {
            // If taking the lock fails, the sender will realise that the we're
            // `done` when it checks the `complete` flag on the way out, and
            // will treat the send as a failure.
            if let Some(mut slot) = self.data.try_lock() {
                if let Some(data) = slot.take() {
                    return Poll::Ready(Ok(data));
                }
            }
            Poll::Ready(Err(Canceled))
        } else {
            Poll::Pending
        }
    }

    fn drop_rx(&self) {
        // Indicate to the `Sender` that we're done, so any future calls to
        // `poll_cancel` are weeded out.
        self.complete.store(true, SeqCst);

        // If we've blocked a task then there's no need for it to stick around,
        // so we need to drop it. If this lock acquisition fails, though, then
        // it's just because our `Sender` is trying to take the task, so we
        // let them take care of that.
        if let Some(mut slot) = self.rx_task.try_lock() {
            let task = slot.take();
            drop(slot);
            drop(task);
        }

        // Finally, if our `Sender` wants to get notified of us going away, it
        // would have stored something in `tx_task`. Here we try to peel that
        // out and unpark it.
        //
        // Note that the `try_lock` here may fail, but only if the `Sender` is
        // in the process of filling in the task. If that happens then we
        // already flagged `complete` and they'll pick that up above.
        if let Some(mut handle) = self.tx_task.try_lock() {
            if let Some(task) = handle.take() {
                drop(handle);
                task.wake()
            }
        }
    }
}

impl<T> Sender<T> {
    /// Completes this oneshot with a successful result.
    ///
    /// This function will consume `self` and indicate to the other end, the
    /// [`Receiver`](Receiver), that the value provided is the result of the
    /// computation this represents.
    ///
    /// If the value is successfully enqueued for the remote end to receive,
    /// then `Ok(())` is returned. If the receiving end was dropped before
    /// this function was called, however, then `Err` is returned with the value
    /// provided.
    pub fn send(self, t: T) -> Result<(), T> {
        self.inner.send(t)
    }

    /// Polls this `Sender` half to detect whether its associated
    /// [`Receiver`](Receiver) with has been dropped.
    ///
    /// # Return values
    ///
    /// If `Ok(Ready)` is returned then the associated `Receiver` has been
    /// dropped, which means any work required for sending should be canceled.
    ///
    /// If `Ok(Pending)` is returned then the associated `Receiver` is still
    /// alive and may be able to receive a message if sent. The current task,
    /// however, is scheduled to receive a notification if the corresponding
    /// `Receiver` goes away.
    pub fn poll_cancel(&mut self, cx: &mut task::Context) -> Poll<()> {
        self.inner.poll_cancel(cx)
    }

    /// Tests to see whether this `Sender`'s corresponding `Receiver`
    /// has been dropped.
    ///
    /// Unlike [`poll_cancel`](Sender::poll_cancel), this function does not
    /// enqueue a task for wakeup upon cancellation, but merely reports the
    /// current state, which may be subject to concurrent modification.
    pub fn is_canceled(&self) -> bool {
        self.inner.is_canceled()
    }
}

impl<T> Drop for Sender<T> {
    fn drop(&mut self) {
        self.inner.drop_tx()
    }
}

/// Error returned from a [`Receiver`](Receiver) when the corresponding
/// [`Sender`](Sender) is dropped.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Canceled;

impl fmt::Display for Canceled {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "oneshot canceled")
    }
}

impl Error for Canceled {
    fn description(&self) -> &str {
        "oneshot canceled"
    }
}

impl<T> Receiver<T> {
    /// Gracefully close this receiver, preventing any subsequent attempts to
    /// send to it.
    ///
    /// Any `send` operation which happens after this method returns is
    /// guaranteed to fail. After calling this method, you can use
    /// [`Receiver::poll`](Future::poll) to determine whether a
    /// message had previously been sent.
    pub fn close(&mut self) {
        self.inner.close_rx()
    }

    /// Attempts to receive a message outside of the context of a task.
    ///
    /// Useful when a [`Context`](Context) is not available
    /// such as within a `Drop` impl.
    ///
    /// Does not schedule a task wakeup or have any other side effects.
    ///
    /// A return value of `None` must be considered immediately stale (out of
    /// date) unless [`close`](Receiver::close) has been called first.
    ///
    /// Returns an error if the sender was dropped.
    pub fn try_recv(&mut self) -> Result<Option<T>, Canceled> {
        self.inner.try_recv()
    }
}

impl<T> Future for Receiver<T> {
    type Output = Result<T, Canceled>;

    fn poll(
        self: PinMut<Self>,
        cx: &mut task::Context,
    ) -> Poll<Result<T, Canceled>> {
        self.inner.recv(cx)
    }
}

impl<T> Drop for Receiver<T> {
    fn drop(&mut self) {
        self.inner.drop_rx()
    }
}
<commit_msg>Change to `task::Context` in docs for `oneshot`<commit_after>//! A channel for sending a single message between asynchronous tasks.

use futures_core::future::Future;
use futures_core::task::{self, Poll, Waker};
use std::marker::Unpin;
use std::mem::PinMut;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::SeqCst;
use std::error::Error;
use std::fmt;

use crate::lock::Lock;

/// A future for a value that will be provided by another asynchronous task.
///
/// This is created by the [`channel`](channel) function.
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct Receiver<T> {
    inner: Arc<Inner<T>>,
}

/// A means of transmitting a single value to another task.
///
/// This is created by the [`channel`](channel) function.
#[derive(Debug)]
pub struct Sender<T> {
    inner: Arc<Inner<T>>,
}

// The channels do not ever project PinMut to the inner T
impl<T> Unpin for Receiver<T> {}
impl<T> Unpin for Sender<T> {}

/// Internal state of the `Receiver`/`Sender` pair above. This is all used as
/// the internal synchronization between the two for send/recv operations.
#[derive(Debug)]
struct Inner<T> {
    /// Indicates whether this oneshot is complete yet. This is filled in both
    /// by `Sender::drop` and by `Receiver::drop`, and both sides interpret it
    /// appropriately.
    ///
    /// For `Receiver`, if this is `true`, then it's guaranteed that `data` is
    /// unlocked and ready to be inspected.
    ///
    /// For `Sender` if this is `true` then the oneshot has gone away and it
    /// can return ready from `poll_cancel`.
    complete: AtomicBool,

    /// The actual data being transferred as part of this `Receiver`. This is
    /// filled in by `Sender::complete` and read by `Receiver::poll`.
    ///
    /// Note that this is protected by `Lock`, but it is in theory safe to
    /// replace with an `UnsafeCell` as it's actually protected by `complete`
    /// above. I wouldn't recommend doing this, however, unless someone is
    /// supremely confident in the various atomic orderings here and there.
    data: Lock<Option<T>>,

    /// Field to store the task which is blocked in `Receiver::poll`.
    ///
    /// This is filled in when a oneshot is polled but not ready yet. Note that
    /// the `Lock` here, unlike in `data` above, is important to resolve races.
    /// Both the `Receiver` and the `Sender` halves understand that if they
    /// can't acquire the lock then some important interference is happening.
    rx_task: Lock<Option<Waker>>,

    /// Like `rx_task` above, except for the task blocked in
    /// `Sender::poll_cancel`. Additionally, `Lock` cannot be `UnsafeCell`.
    tx_task: Lock<Option<Waker>>,
}

/// Creates a new one-shot channel for sending values across asynchronous tasks.
///
/// This function is similar to Rust's channel constructor found in the standard
/// library. Two halves are returned, the first of which is a `Sender` handle,
/// used to signal the end of a computation and provide its value. The second
/// half is a `Receiver` which implements the `Future` trait, resolving to the
/// value that was given to the `Sender` handle.
///
/// Each half can be separately owned and sent across tasks.
///
/// # Examples
///
/// ```
/// use futures::channel::oneshot;
/// use futures::prelude::*;
/// use std::thread;
///
/// fn main() {
///     let (sender, receiver) = oneshot::channel::<i32>();
///
/// # let t =
///     thread::spawn(|| {
///         let future = receiver.map(|i| {
///             println!("got: {:?}", i);
///         });
///         // ...
/// # return future;
///     });
///
///     sender.send(3).unwrap();
/// # futures::executor::block_on(t.join().unwrap());
/// }
/// ```
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
    let inner = Arc::new(Inner::new());
    let receiver = Receiver {
        inner: inner.clone(),
    };
    let sender = Sender {
        inner,
    };
    (sender, receiver)
}

impl<T> Inner<T> {
    fn new() -> Inner<T> {
        Inner {
            complete: AtomicBool::new(false),
            data: Lock::new(None),
            rx_task: Lock::new(None),
            tx_task: Lock::new(None),
        }
    }

    fn send(&self, t: T) -> Result<(), T> {
        if self.complete.load(SeqCst) {
            return Err(t)
        }

        // Note that this lock acquisition may fail if the receiver
        // is closed and sets the `complete` flag to true, whereupon
        // the receiver may call `poll()`.
        if let Some(mut slot) = self.data.try_lock() {
            assert!(slot.is_none());
            *slot = Some(t);
            drop(slot);

            // If the receiver called `close()` between the check at the
            // start of the function, and the lock being released, then
            // the receiver may not be around to receive it, so try to
            // pull it back out.
            if self.complete.load(SeqCst) {
                // If lock acquisition fails, then receiver is actually
                // receiving it, so we're good.
                if let Some(mut slot) = self.data.try_lock() {
                    if let Some(t) = slot.take() {
                        return Err(t);
                    }
                }
            }
            Ok(())
        } else {
            // Must have been closed
            Err(t)
        }
    }

    fn poll_cancel(&self, cx: &mut task::Context) -> Poll<()> {
        // Fast path up first, just read the flag and see if our other half is
        // gone. This flag is set both in our destructor and the oneshot
        // destructor, but our destructor hasn't run yet so if it's set then the
        // oneshot is gone.
        if self.complete.load(SeqCst) {
            return Poll::Ready(())
        }

        // If our other half is not gone then we need to park our current task
        // and move it into the `notify_cancel` slot to get notified when it's
        // actually gone.
        //
        // If `try_lock` fails, then the `Receiver` is in the process of using
        // it, so we can deduce that it's now in the process of going away and
        // hence we're canceled. If it succeeds then we just store our handle.
        //
        // Crucially we then check `oneshot_gone` *again* before we return.
        // While we were storing our handle inside `notify_cancel` the
        // `Receiver` may have been dropped. The first thing it does is set the
        // flag, and if it fails to acquire the lock it assumes that we'll see
        // the flag later on. So... we then try to see the flag later on!
        let handle = cx.waker().clone();
        match self.tx_task.try_lock() {
            Some(mut p) => *p = Some(handle),
            None => return Poll::Ready(()),
        }
        if self.complete.load(SeqCst) {
            Poll::Ready(())
        } else {
            Poll::Pending
        }
    }

    fn is_canceled(&self) -> bool {
        self.complete.load(SeqCst)
    }

    fn drop_tx(&self) {
        // Flag that we're a completed `Sender` and try to wake up a receiver.
        // Whether or not we actually stored any data will get picked up and
        // translated to either an item or cancellation.
        //
        // Note that if we fail to acquire the `rx_task` lock then that means
        // we're in one of two situations:
        //
        // 1. The receiver is trying to block in `poll`
        // 2. The receiver is being dropped
        //
        // In the first case it'll check the `complete` flag after it's done
        // blocking to see if it succeeded. In the latter case we don't need to
        // wake up anyone anyway. So in both cases it's ok to ignore the `None`
        // case of `try_lock` and bail out.
        //
        // The first case crucially depends on `Lock` using `SeqCst` ordering
        // under the hood. If it instead used `Release` / `Acquire` ordering,
        // then it would not necessarily synchronize with `inner.complete`
        // and deadlock might be possible, as was observed in
        // https://github.com/rust-lang-nursery/futures-rs/pull/219.
        self.complete.store(true, SeqCst);
        if let Some(mut slot) = self.rx_task.try_lock() {
            if let Some(task) = slot.take() {
                drop(slot);
                task.wake();
            }
        }
    }

    fn close_rx(&self) {
        // Flag our completion and then attempt to wake up the sender if it's
        // blocked. See comments in `drop` below for more info
        self.complete.store(true, SeqCst);
        if let Some(mut handle) = self.tx_task.try_lock() {
            if let Some(task) = handle.take() {
                drop(handle);
                task.wake()
            }
        }
    }

    fn try_recv(&self) -> Result<Option<T>, Canceled> {
        // If we're complete, either `::close_rx` or `::drop_tx` was called.
        // We can assume a successful send if data is present.
        if self.complete.load(SeqCst) {
            if let Some(mut slot) = self.data.try_lock() {
                if let Some(data) = slot.take() {
                    return Ok(Some(data));
                }
            }
            Err(Canceled)
        } else {
            Ok(None)
        }
    }

    fn recv(&self, cx: &mut task::Context) -> Poll<Result<T, Canceled>> {
        // Check to see if some data has arrived. If it hasn't then we need to
        // block our task.
        //
        // Note that the acquisition of the `rx_task` lock might fail below, but
        // the only situation where this can happen is during `Sender::drop`
        // when we are indeed completed already. If that's happening then we
        // know we're completed so keep going.
        let done = if self.complete.load(SeqCst) {
            true
        } else {
            let task = cx.waker().clone();
            match self.rx_task.try_lock() {
                Some(mut slot) => { *slot = Some(task); false },
                None => true,
            }
        };

        // If we're `done` via one of the paths above, then look at the data and
        // figure out what the answer is. If, however, we stored `rx_task`
        // successfully above we need to check again if we're completed in case
        // a message was sent while `rx_task` was locked and couldn't notify us
        // otherwise.
        //
        // If we're not done, and we're not complete, though, then we've
        // successfully blocked our task and we return `Pending`.
        if done || self.complete.load(SeqCst) {
            // If taking the lock fails, the sender will realise that the we're
            // `done` when it checks the `complete` flag on the way out, and
            // will treat the send as a failure.
            if let Some(mut slot) = self.data.try_lock() {
                if let Some(data) = slot.take() {
                    return Poll::Ready(Ok(data));
                }
            }
            Poll::Ready(Err(Canceled))
        } else {
            Poll::Pending
        }
    }

    fn drop_rx(&self) {
        // Indicate to the `Sender` that we're done, so any future calls to
        // `poll_cancel` are weeded out.
        self.complete.store(true, SeqCst);

        // If we've blocked a task then there's no need for it to stick around,
        // so we need to drop it. If this lock acquisition fails, though, then
        // it's just because our `Sender` is trying to take the task, so we
        // let them take care of that.
        if let Some(mut slot) = self.rx_task.try_lock() {
            let task = slot.take();
            drop(slot);
            drop(task);
        }

        // Finally, if our `Sender` wants to get notified of us going away, it
        // would have stored something in `tx_task`. Here we try to peel that
        // out and unpark it.
        //
        // Note that the `try_lock` here may fail, but only if the `Sender` is
        // in the process of filling in the task. If that happens then we
        // already flagged `complete` and they'll pick that up above.
        if let Some(mut handle) = self.tx_task.try_lock() {
            if let Some(task) = handle.take() {
                drop(handle);
                task.wake()
            }
        }
    }
}

impl<T> Sender<T> {
    /// Completes this oneshot with a successful result.
    ///
    /// This function will consume `self` and indicate to the other end, the
    /// [`Receiver`](Receiver), that the value provided is the result of the
    /// computation this represents.
    ///
    /// If the value is successfully enqueued for the remote end to receive,
    /// then `Ok(())` is returned. If the receiving end was dropped before
    /// this function was called, however, then `Err` is returned with the value
    /// provided.
    pub fn send(self, t: T) -> Result<(), T> {
        self.inner.send(t)
    }

    /// Polls this `Sender` half to detect whether its associated
    /// [`Receiver`](Receiver) with has been dropped.
    ///
    /// # Return values
    ///
    /// If `Ok(Ready)` is returned then the associated `Receiver` has been
    /// dropped, which means any work required for sending should be canceled.
    ///
    /// If `Ok(Pending)` is returned then the associated `Receiver` is still
    /// alive and may be able to receive a message if sent. The current task,
    /// however, is scheduled to receive a notification if the corresponding
    /// `Receiver` goes away.
    pub fn poll_cancel(&mut self, cx: &mut task::Context) -> Poll<()> {
        self.inner.poll_cancel(cx)
    }

    /// Tests to see whether this `Sender`'s corresponding `Receiver`
    /// has been dropped.
    ///
    /// Unlike [`poll_cancel`](Sender::poll_cancel), this function does not
    /// enqueue a task for wakeup upon cancellation, but merely reports the
    /// current state, which may be subject to concurrent modification.
    pub fn is_canceled(&self) -> bool {
        self.inner.is_canceled()
    }
}

impl<T> Drop for Sender<T> {
    fn drop(&mut self) {
        self.inner.drop_tx()
    }
}

/// Error returned from a [`Receiver`](Receiver) when the corresponding
/// [`Sender`](Sender) is dropped.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Canceled;

impl fmt::Display for Canceled {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "oneshot canceled")
    }
}

impl Error for Canceled {
    fn description(&self) -> &str {
        "oneshot canceled"
    }
}

impl<T> Receiver<T> {
    /// Gracefully close this receiver, preventing any subsequent attempts to
    /// send to it.
    ///
    /// Any `send` operation which happens after this method returns is
    /// guaranteed to fail. After calling this method, you can use
    /// [`Receiver::poll`](Future::poll) to determine whether a
    /// message had previously been sent.
    pub fn close(&mut self) {
        self.inner.close_rx()
    }

    /// Attempts to receive a message outside of the context of a task.
    ///
    /// Useful when a [`Context`](task::Context) is not available
    /// such as within a `Drop` impl.
    ///
    /// Does not schedule a task wakeup or have any other side effects.
    ///
    /// A return value of `None` must be considered immediately stale (out of
    /// date) unless [`close`](Receiver::close) has been called first.
    ///
    /// Returns an error if the sender was dropped.
    pub fn try_recv(&mut self) -> Result<Option<T>, Canceled> {
        self.inner.try_recv()
    }
}

impl<T> Future for Receiver<T> {
    type Output = Result<T, Canceled>;

    fn poll(
        self: PinMut<Self>,
        cx: &mut task::Context,
    ) -> Poll<Result<T, Canceled>> {
        self.inner.recv(cx)
    }
}

impl<T> Drop for Receiver<T> {
    fn drop(&mut self) {
        self.inner.drop_rx()
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Ilkka Rauta
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod ffi;

use std::path::Path;

use libc::{c_ulong};

pub struct Demux {
    device: DeviceFileDescriptor
}

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult,DeviceError};

impl Demux {
    pub fn open(file: &Path, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Demux> {
        let device = try!(DeviceFileDescriptor::open(file, rw_mode, block_mode));
        Ok(Demux { device: device })
    }

    pub fn read(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    // Should this even exist here?
    pub fn write(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn start(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_START as c_ulong)
    }

    pub fn stop(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_STOP as c_ulong)
    }

    pub fn set_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_pes_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_buffer_size(&self, buffer_size: u32) -> DeviceResult<()> {
        let mut ffi_size = buffer_size as c_ulong;
        self.device.ioctl_pointer(ffi::DMX_SET_BUFFER_SIZE as c_ulong, &mut ffi_size)
    }

    pub fn get_system_time_counter(&self) -> DeviceResult<SystemTimeCounter> {
        unimplemented!();
    }

    pub fn get_pes_pids(&self) -> DeviceResult<[u16; 5]> {
        unimplemented!();
    }

    /// This function is undocumented in the official, and doesn't seem to be actually in use.
    /// It is still nevertheless included here, if it is used by out-of-tree DVB drivers.
    pub fn get_caps(&self) -> DeviceResult<DemuxCaps> {
        let mut ffi_caps = ffi::Struct_dmx_caps { caps: 0, num_decoders: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_CAPS as c_ulong, &mut ffi_caps));
        Ok(DemuxCaps { caps: ffi_caps.caps, num_decoders: ffi_caps.num_decoders as i32 })
    }

    pub fn set_source(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn add_pid(&self, pid: u16) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn remove_pid(&self, pid: u16) -> DeviceResult<()> {
        unimplemented!();
    }
}

pub struct DemuxCaps {
    pub caps: u32,
    pub num_decoders: i32
}

pub struct SystemTimeCounter;
<commit_msg>Remove unnecessary import.<commit_after>// Copyright 2015 Ilkka Rauta
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod ffi;

use std::path::Path;

use libc::{c_ulong};

pub struct Demux {
    device: DeviceFileDescriptor
}

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult};

impl Demux {
    pub fn open(file: &Path, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Demux> {
        let device = try!(DeviceFileDescriptor::open(file, rw_mode, block_mode));
        Ok(Demux { device: device })
    }

    pub fn read(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    // Should this even exist here?
    pub fn write(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn start(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_START as c_ulong)
    }

    pub fn stop(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_STOP as c_ulong)
    }

    pub fn set_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_pes_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_buffer_size(&self, buffer_size: u32) -> DeviceResult<()> {
        let mut ffi_size = buffer_size as c_ulong;
        self.device.ioctl_pointer(ffi::DMX_SET_BUFFER_SIZE as c_ulong, &mut ffi_size)
    }

    pub fn get_system_time_counter(&self) -> DeviceResult<SystemTimeCounter> {
        unimplemented!();
    }

    pub fn get_pes_pids(&self) -> DeviceResult<[u16; 5]> {
        unimplemented!();
    }

    /// This function is undocumented in the official, and doesn't seem to be actually in use.
    /// It is still nevertheless included here, if it is used by out-of-tree DVB drivers.
    pub fn get_caps(&self) -> DeviceResult<DemuxCaps> {
        let mut ffi_caps = ffi::Struct_dmx_caps { caps: 0, num_decoders: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_CAPS as c_ulong, &mut ffi_caps));
        Ok(DemuxCaps { caps: ffi_caps.caps, num_decoders: ffi_caps.num_decoders as i32 })
    }

    pub fn set_source(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn add_pid(&self, pid: u16) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn remove_pid(&self, pid: u16) -> DeviceResult<()> {
        unimplemented!();
    }
}

pub struct DemuxCaps {
    pub caps: u32,
    pub num_decoders: i32
}

pub struct SystemTimeCounter;
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate sdl2_ttf;
use sdl2::render::{Renderer, BlendMode};
use sdl2::pixels::Color;
use std::env;
use font::*;
use display::{self, Display};
use subtitles::Subtitles;
use utils::*;

pub struct Displayer<'a> {
    fonts: FontList,
    renderer: Renderer<'a>,
    #[allow(dead_code)]
    ttf_context: sdl2_ttf::Sdl2TtfContext,
    subtitles: Option<Subtitles>,
}

mod subtitles_display {
    use sdl2::pixels::Color;
    pub const DEFAULT_SUB_COLORS : (Color,Color,Color) = (Color::RGB(0, 0xFF, 0xFF),
                                              Color::RGB(0xFF, 0, 0),
                                              Color::RGB(0xFF, 0xFF, 0));
    pub const DEFAULT_FADE_INTERVAL: u32 = 10;
    pub const DEFAULT_TRANSITION_INTERVAL: u32 = DEFAULT_FADE_INTERVAL + 5;

    #[derive(Copy,Clone)]
    pub struct Options {
        pub fade_interval:u32,
        pub transition_interval:u32,
        pub sub_colors:(Color,Color,Color)
    }

    impl Options {
        pub fn new() -> Options {
            Options {
                fade_interval:DEFAULT_FADE_INTERVAL,
                transition_interval:DEFAULT_TRANSITION_INTERVAL,
                sub_colors:DEFAULT_SUB_COLORS
            }
        }

        pub fn with_transition_interval(mut self,value:u32) -> Options {
            self.transition_interval = value;
            self
        }

        pub fn with_fade_interval(mut self,value:u32) -> Options {
            self.fade_interval =value;
            self
        }

        /// alive : not yet displayed;
        /// active: being displayed;
        /// dead: finished being displayed
        pub fn with_sub_colors(mut self,alive:Color,active:Color,dead:Color) -> Options {
            self.sub_colors = (alive,active,dead);
            self
        }
    }
}

impl<'a> Displayer<'a> {
    pub fn new(mut renderer: Renderer<'a>,
               subtitles: Option<Subtitles>)
               -> Result<Displayer<'a>, ()> {
        renderer.set_blend_mode(BlendMode::Blend);
        let ttf_context = sdl2_ttf::init().unwrap();
        let font_list = FontList::new(&ttf_context).unwrap();
        let displayer = Displayer {
            fonts: font_list,
            ttf_context: ttf_context,
            renderer: renderer,
            subtitles: subtitles,
        };
        Ok(displayer)
    }

    fn add_syllabus(mut text_elts : &mut Vec<display::TextElement>,
                    syllabus:&str,
                    current_frame:u32,
                    frame_begin:u32,
                    frame_end:u32,
                    alpha:f32,
                    sub_options:subtitles_display::Options) {
        if (current_frame < frame_begin) {
            // not yet

            let text_2d = display::TextElement {
                text: String::from(syllabus),
                color: fade_color(sub_options.sub_colors.2, alpha),
                outline: Some(Color::RGB(0, 0, 0)),
                shadow: None,
            };
            text_elts.push(text_2d);

        } else if (frame_begin <= current_frame) && (current_frame <= frame_end) {
            let percent = (current_frame - frame_begin) as f32 /
                          (frame_end - frame_begin) as f32;
            // lets ease the percent a lil bits
            let percent = 1.0 - (1.0 - percent).sqrt();
            // let percent = (percent * consts::PI / 2.0).sin();
            let transition_color = mix_colors(sub_options.sub_colors.1, sub_options.sub_colors.0, percent);
            let text_2d = display::TextElement {
                text: String::from(syllabus),
                color: transition_color,
                outline: Some(Color::RGB(0, 0, 0)),
                shadow: None,
            };
            text_elts.push(text_2d);
        } else {
            if (text_elts.is_empty()) {
                let text_2d = display::TextElement {
                    text: String::from(syllabus),
                    color: fade_color(sub_options.sub_colors.0, alpha),
                    outline: Some(Color::RGB(0, 0, 0)),
                    shadow: None,
                };
                text_elts.push(text_2d);
            } else {
                let mut text_2d = text_elts.last_mut().unwrap();
                text_2d.text.push_str(&syllabus);
            }
        }
    }

    pub fn render_subtitles(&mut self, frame_number: u32) {
        let sub_colors = (Color::RGB(0, 0xFF, 0xFF),
                          Color::RGB(0xFF, 0, 0),
                          Color::RGB(0xFF, 0xFF, 0));
        let mut text2d_vec = vec![];
        let sub_options = subtitles_display::Options::new();
        let finished_fade_interval = sub_options.transition_interval - sub_options.fade_interval;
        match self.subtitles {
            Some(ref subtitles) => {
                let subtitles = subtitles.get_subtitles();
                let iter = subtitles.iter().enumerate().filter(|&(_, line)| {
                    match (line.first(), line.last()) {
                        (Some(&(_, (frame_begin, _))), Some(&(_, (_, frame_end)))) => {
                            frame_begin.saturating_sub(sub_options.transition_interval) < frame_number &&
                            frame_end.saturating_add(sub_options.transition_interval) > frame_number
                        }
                        _ => false,
                    }
                });
                for (i, line) in iter {
                    let text_pos_y = match i % 2 {
                        0 => display::PosY::FromTopPercent(0.02),
                        1 => display::PosY::FromTopPercent(0.12),
                        _ => unreachable!(),
                    };
                    let alpha: f32 = match (line.first(), line.last()) {
                        (Some(&(_, (frame_begin, _))), Some(&(_, (_, frame_end)))) => {

                            let begin_first_fade_frame =
                                frame_begin.saturating_sub(sub_options.transition_interval);
                            let end_first_fade_frame =
                                frame_begin.saturating_sub(finished_fade_interval);
                            let begin_second_fade_frame =
                                frame_end.saturating_add(finished_fade_interval);
                            let end_second_fade_frame =
                                frame_end.saturating_add(sub_options.transition_interval);
                            debug_assert_eq!(end_second_fade_frame - begin_second_fade_frame,
                                             sub_options.fade_interval);
                            if (end_first_fade_frame < frame_number &&
                                begin_second_fade_frame > frame_number) {
                                1.0
                            } else if begin_first_fade_frame <= frame_number &&
                               end_first_fade_frame >= frame_number {
                                (frame_number - begin_first_fade_frame) as f32 /
                                (end_first_fade_frame - begin_first_fade_frame) as f32
                            } else if begin_second_fade_frame <= frame_number &&
                               end_second_fade_frame >= frame_number {
                                1.0 -
                                ((frame_number - begin_second_fade_frame) as f32 /
                                 (end_second_fade_frame - begin_second_fade_frame) as f32)
                            } else {
                                0.0
                            }
                        }
                        _ => 0.0,
                    };
                    let mut text_elts = Vec::new();
                    for &(ref syllabus,(frame_begin,frame_end)) in line.iter() {
                        Self::add_syllabus(&mut text_elts,syllabus,frame_number,frame_begin,frame_end,alpha,sub_options);
                    }
                    let text_2d = display::Text2D {
                        text: text_elts,
                        size: display::Size::FitPercent(Some(0.95), Some(0.1)),
                        pos: (display::PosX::Centered, text_pos_y),
                        anchor: (0.5, 0.0),
                    };
                    text2d_vec.push(text_2d);
                }
            }
            None => {}
        };
        for text_2d in text2d_vec.into_iter() {
            text_2d.draw(self);
        }
    }

    // width and height must be between 0 and 1
    pub fn sub_screen_dims(&self,
                           width: Option<f32>,
                           height: Option<f32>)
                           -> (Option<u32>, Option<u32>) {
        let dims: (u32, u32) = self.renderer.window().unwrap().size();
        (width.and_then(|width| Some((width * (dims.0 as f32)) as u32)),
         height.and_then(|height| Some((height * (dims.1 as f32)) as u32)))
    }

    pub fn render(&mut self) {
        self.sdl_renderer_mut().window().unwrap().gl_swap_window();
    }

    pub fn sdl_renderer_mut(&mut self) -> &mut Renderer<'a> {
        &mut self.renderer
    }

    pub fn sdl_renderer(&self) -> &Renderer<'a> {
        &self.renderer
    }

    pub fn fonts(&self) -> &FontList {
        &self.fonts
    }
}
<commit_msg>Texture renderer part 1<commit_after>extern crate sdl2;
extern crate sdl2_ttf;
use sdl2::render::{Renderer, BlendMode};
use sdl2::pixels::Color;
use std::env;
use font::*;
use display::{self, Display};
use subtitles::Subtitles;
use utils::*;

pub struct Displayer<'a> {
    fonts: FontList,
    renderer: Renderer<'a>,
    #[allow(dead_code)]
    ttf_context: sdl2_ttf::Sdl2TtfContext,
    subtitles: Option<Subtitles>,
}

mod subtitles_display {
    use sdl2::pixels::Color;
    pub const DEFAULT_SUB_COLORS : (Color,Color,Color) = (Color::RGB(0, 0xFF, 0xFF),
                                              Color::RGB(0xFF, 0, 0),
                                              Color::RGB(0xFF, 0xFF, 0));
    pub const DEFAULT_FADE_INTERVAL: u32 = 10;
    pub const DEFAULT_TRANSITION_INTERVAL: u32 = DEFAULT_FADE_INTERVAL + 5;

    #[derive(Copy,Clone)]
    pub struct Options {
        pub fade_interval:u32,
        pub transition_interval:u32,
        pub sub_colors:(Color,Color,Color)
    }

    impl Options {
        pub fn new() -> Options {
            Options {
                fade_interval:DEFAULT_FADE_INTERVAL,
                transition_interval:DEFAULT_TRANSITION_INTERVAL,
                sub_colors:DEFAULT_SUB_COLORS
            }
        }

        pub fn with_transition_interval(mut self,value:u32) -> Options {
            self.transition_interval = value;
            self
        }

        pub fn with_fade_interval(mut self,value:u32) -> Options {
            self.fade_interval =value;
            self
        }

        /// alive : not yet displayed;
        /// active: being displayed;
        /// dead: finished being displayed
        pub fn with_sub_colors(mut self,alive:Color,active:Color,dead:Color) -> Options {
            self.sub_colors = (alive,active,dead);
            self
        }
    }
}

impl<'a> Displayer<'a> {
    pub fn new(mut renderer: Renderer<'a>,
               subtitles: Option<Subtitles>)
               -> Result<Displayer<'a>, ()> {
        renderer.set_blend_mode(BlendMode::Blend);
        let ttf_context = sdl2_ttf::init().unwrap();
        let font_list = FontList::new(&ttf_context).unwrap();
        let displayer = Displayer {
            fonts: font_list,
            ttf_context: ttf_context,
            renderer: renderer,
            subtitles: subtitles,
        };
        Ok(displayer)
    }

    fn add_syllabus(mut text_elts : &mut Vec<display::TextElement>,
                    syllabus:&str,
                    current_frame:u32,
                    frame_begin:u32,
                    frame_end:u32,
                    alpha:f32,
                    sub_options:subtitles_display::Options) {
        if (current_frame < frame_begin) {
            // not yet

            let text_2d = display::TextElement {
                text: String::from(syllabus),
                color: fade_color(sub_options.sub_colors.2, alpha),
                outline: Some(Color::RGB(0, 0, 0)),
                shadow: None,
            };
            text_elts.push(text_2d);

        } else if (frame_begin <= current_frame) && (current_frame <= frame_end) {
            let percent = (current_frame - frame_begin) as f32 /
                          (frame_end - frame_begin) as f32;
            // lets ease the percent a lil bits
            let percent = 1.0 - (1.0 - percent).sqrt();
            // let percent = (percent * consts::PI / 2.0).sin();
            let transition_color = mix_colors(sub_options.sub_colors.1, sub_options.sub_colors.0, percent);
            let text_2d = display::TextElement {
                text: String::from(syllabus),
                color: transition_color,
                outline: Some(Color::RGB(0, 0, 0)),
                shadow: None,
            };
            text_elts.push(text_2d);
        } else {
            if (text_elts.is_empty()) {
                let text_2d = display::TextElement {
                    text: String::from(syllabus),
                    color: fade_color(sub_options.sub_colors.0, alpha),
                    outline: Some(Color::RGB(0, 0, 0)),
                    shadow: None,
                };
                text_elts.push(text_2d);
            } else {
                let mut text_2d = text_elts.last_mut().unwrap();
                text_2d.text.push_str(&syllabus);
            }
        }
    }

    pub fn error_message(&self,title:&str,info:&str) {
        ::sdl2::messagebox::show_simple_message_box(::sdl2::messagebox::MESSAGEBOX_ERROR,
                                                    title,
                                                    info,
                                                    self.sdl_renderer().window());
    }

    pub fn render_subtitles(&mut self, frame_number: u32) {
        let (w,h) = self.renderer.output_size().expect("unable to get renderer size");
        let mut target_texture = self.renderer.create_texture_target(sdl2::pixels::PixelFormatEnum::ARGB8888,
                                                                 w,
                                                                 h).expect("Unable to create texture");
        target_texture.set_blend_mode(BlendMode::Blend);
        let original_texture : Option<_> = self.renderer.render_target()
                                                        .expect("Unsupported graphic card")
                                                        .set(target_texture)
                                                        .unwrap();
        let sub_colors = (Color::RGB(0, 0xFF, 0xFF),
                          Color::RGB(0xFF, 0, 0),
                          Color::RGB(0xFF, 0xFF, 0));
        let mut text2d_vec = vec![];
        let sub_options = subtitles_display::Options::new();
        let finished_fade_interval = sub_options.transition_interval - sub_options.fade_interval;
        match self.subtitles {
            Some(ref subtitles) => {
                let subtitles = subtitles.get_subtitles();
                let iter = subtitles.iter().enumerate().filter(|&(_, line)| {
                    match (line.first(), line.last()) {
                        (Some(&(_, (frame_begin, _))), Some(&(_, (_, frame_end)))) => {
                            frame_begin.saturating_sub(sub_options.transition_interval) < frame_number &&
                            frame_end.saturating_add(sub_options.transition_interval) > frame_number
                        }
                        _ => false,
                    }
                });
                for (i, line) in iter {
                    let text_pos_y = match i % 2 {
                        0 => display::PosY::FromTopPercent(0.02),
                        1 => display::PosY::FromTopPercent(0.12),
                        _ => unreachable!(),
                    };
                    let alpha: f32 = match (line.first(), line.last()) {
                        (Some(&(_, (frame_begin, _))), Some(&(_, (_, frame_end)))) => {

                            let begin_first_fade_frame =
                                frame_begin.saturating_sub(sub_options.transition_interval);
                            let end_first_fade_frame =
                                frame_begin.saturating_sub(finished_fade_interval);
                            let begin_second_fade_frame =
                                frame_end.saturating_add(finished_fade_interval);
                            let end_second_fade_frame =
                                frame_end.saturating_add(sub_options.transition_interval);
                            debug_assert_eq!(end_second_fade_frame - begin_second_fade_frame,
                                             sub_options.fade_interval);
                            if (end_first_fade_frame < frame_number &&
                                begin_second_fade_frame > frame_number) {
                                1.0
                            } else if begin_first_fade_frame <= frame_number &&
                               end_first_fade_frame >= frame_number {
                                (frame_number - begin_first_fade_frame) as f32 /
                                (end_first_fade_frame - begin_first_fade_frame) as f32
                            } else if begin_second_fade_frame <= frame_number &&
                               end_second_fade_frame >= frame_number {
                                1.0 -
                                ((frame_number - begin_second_fade_frame) as f32 /
                                 (end_second_fade_frame - begin_second_fade_frame) as f32)
                            } else {
                                0.0
                            }
                        }
                        _ => 0.0,
                    };
                    let mut text_elts = Vec::new();
                    for &(ref syllabus,(frame_begin,frame_end)) in line.iter() {
                        Self::add_syllabus(&mut text_elts,syllabus,frame_number,frame_begin,frame_end,alpha,sub_options);
                    }
                    let text_2d = display::Text2D {
                        text: text_elts,
                        size: display::Size::FitPercent(Some(0.95), Some(0.1)),
                        pos: (display::PosX::Centered, text_pos_y),
                        anchor: (0.5, 0.0),
                    };
                    text2d_vec.push(text_2d);
                }
            }
            None => {}
        };
        for text_2d in text2d_vec.into_iter() {
            text_2d.draw(self);
        };
        // TODO : restore first texture instead of asssuming it's window every time
        let target_texture = self.renderer.render_target().unwrap().reset().unwrap().unwrap();
        self.renderer.copy(&target_texture,None,None);
    }

    // width and height must be between 0 and 1
    pub fn sub_screen_dims(&self,
                           width: Option<f32>,
                           height: Option<f32>)
                           -> (Option<u32>, Option<u32>) {
        let dims: (u32, u32) = self.renderer.window().unwrap().size();
        (width.and_then(|width| Some((width * (dims.0 as f32)) as u32)),
         height.and_then(|height| Some((height * (dims.1 as f32)) as u32)))
    }

    pub fn render(&mut self) {
        self.sdl_renderer_mut().window().unwrap().gl_swap_window();
    }

    pub fn sdl_renderer_mut(&mut self) -> &mut Renderer<'a> {
        &mut self.renderer
    }

    pub fn sdl_renderer(&self) -> &Renderer<'a> {
        &self.renderer
    }

    pub fn fonts(&self) -> &FontList {
        &self.fonts
    }
}
<|endoftext|>