<commit_before>use std::collections::HashMap;

use library::*;
use nameutil;
use parser::is_empty_c_type;
use traits::MaybeRefAs;

impl Namespace {
    fn unresolved(&self) -> Vec<&str> {
        self.index
            .iter()
            .filter_map(|(name, &id)| if self.types[id as usize].is_none() {
                Some(&name[..])
            } else {
                None
            })
            .collect()
    }
}

type DetectedCTypes = HashMap<TypeId, String>;

impl Library {
    pub fn postprocessing(&mut self) {
        self.fix_gtype();
        self.check_resolved();
        self.fill_empty_signals_c_types();
        self.resolve_class_structs();
        self.correlate_class_structs();
        self.fix_fields();
        self.make_unrepresentable_types_opaque();
    }

    fn fix_gtype(&mut self) {
        if let Some(ns_id) = self.find_namespace("GObject") {
            // hide the `GType` type alias in `GObject`
            self.add_type(ns_id, "Type", Type::Fundamental(Fundamental::Unsupported));
        }
    }

    fn check_resolved(&self) {
        let list: Vec<_> = self.index
            .iter()
            .flat_map(|(name, &id)| {
                let name = name.clone();
                self.namespace(id)
                    .unresolved()
                    .into_iter()
                    .map(move |s| format!("{}.{}", name, s))
            })
            .collect();

        if !list.is_empty() {
            panic!("Incomplete library, unresolved: {:?}", list);
        }
    }

    fn fill_empty_signals_c_types(&mut self) {
        let mut tids = Vec::new();
        let mut c_types = DetectedCTypes::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(ref klass) => {
                        if self.detect_empty_signals_c_types(&klass.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    Type::Interface(ref iface) => {
                        if self.detect_empty_signals_c_types(&iface.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    _ => (),
                }
            }
        }

        fn update_empty_signals_c_types(signals: &mut [Signal], c_types: &DetectedCTypes) {
            for signal in signals {
                update_empty_signal_c_types(signal, c_types);
            }
        }

        fn update_empty_signal_c_types(signal: &mut Signal, c_types: &DetectedCTypes) {
            for par in &mut signal.parameters {
                update_empty_c_type(&mut par.c_type, par.typ, c_types);
            }
            update_empty_c_type(&mut signal.ret.c_type, signal.ret.typ, c_types);
        }

        fn update_empty_c_type(c_type: &mut String, tid: TypeId, c_types: &DetectedCTypes) {
            if !is_empty_c_type(c_type) {
                return;
            }
            if let Some(ref mut s) = c_types.get(&tid) {
                *c_type = s.clone();
            }
        }

        for tid in tids {
            match *self.type_mut(tid) {
                Type::Class(ref mut klass) => {
                    update_empty_signals_c_types(&mut klass.signals, &c_types)
                }
                Type::Interface(ref mut iface) => {
                    update_empty_signals_c_types(&mut iface.signals, &c_types)
                }
                _ => (),
            }
        }
    }

    fn detect_empty_signals_c_types(
        &self,
        signals: &[Signal],
        c_types: &mut DetectedCTypes,
    ) -> bool {
        let mut detected = false;
        for signal in signals {
            if self.detect_empty_signal_c_types(signal, c_types) {
                detected = true;
            }
        }
        detected
    }

    fn detect_empty_signal_c_types(&self, signal: &Signal, c_types: &mut DetectedCTypes) -> bool {
        let mut detected = false;
        for par in &signal.parameters {
            if self.detect_empty_c_type(&par.c_type, par.typ, c_types) {
                detected = true;
            }
        }
        if self.detect_empty_c_type(&signal.ret.c_type, signal.ret.typ, c_types) {
            detected = true;
        }
        detected
    }

    fn detect_empty_c_type(&self, c_type: &str, tid: TypeId, c_types: &mut DetectedCTypes) -> bool {
        if !is_empty_c_type(c_type) {
            return false;
        }
        if !c_types.contains_key(&tid) {
            if let Some(detected_c_type) = self.c_type_by_type_id(tid) {
                c_types.insert(tid, detected_c_type);
            }
        }
        true
    }

    fn c_type_by_type_id(&self, tid: TypeId) -> Option<String> {
        let type_ = self.type_(tid);
        type_
            .get_glib_name()
            .map(|glib_name| if self.is_referenced_type(type_) {
                format!("{}*", glib_name)
            } else {
                glib_name.to_string()
            })
    }

    fn is_referenced_type(&self, type_: &Type) -> bool {
        use library::Type::*;
        match *type_ {
            Alias(ref alias) => self.is_referenced_type(self.type_(alias.typ)),
            Record(..) | Union(..) | Class(..) | Interface(..) => true,
            _ => false,
        }
    }

    fn resolve_class_structs(&mut self) {
        // stores pairs of (gtype-struct-c-name, type-name)
        let mut structs_and_types = Vec::new();

        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in &ns.types {
                let type_ = type_.as_ref().unwrap(); //Always contains something

                if let Type::Record(ref record) = *type_ {
                    if let Some(ref struct_for) = record.gtype_struct_for {
                        if let Some(struct_for_tid) = self.find_type(ns_id as u16, struct_for) {
                            structs_and_types.push ((record.c_type.clone(), struct_for_tid));
                        }
                    }
                }
            }
        }

        for (gtype_struct_c_type, struct_for_tid) in structs_and_types {
            match *self.type_mut(struct_for_tid) {
                Type::Class(ref mut klass) => {
                    klass.c_class_type = Some(gtype_struct_c_type);
                },

                Type::Interface(ref mut iface) => {
                    iface.c_class_type = Some(gtype_struct_c_type);
                },

                ref x => unreachable!("Something other than a class or interface has a class struct: {:?}", x)
            }
        }
    }

    fn correlate_class_structs(&self) {
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in &ns.types {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let name;
                let type_struct;
                let c_class_type;

                match *type_ {
                    Type::Class(ref klass) => {
                        name         = &klass.name;
                        type_struct  = &klass.type_struct;
                        c_class_type = &klass.c_class_type;
                    },

                    Type::Interface(ref iface) => {
                        name         = &iface.name;
                        type_struct  = &iface.type_struct;
                        c_class_type = &iface.c_class_type;
                    },

                    _ => { continue; }
                }

                if let Some(ref type_struct) = *type_struct {
                    let type_struct_tid = self.find_type(ns_id as u16, type_struct);
                    if type_struct_tid.is_none() {
                        panic!("\"{}\" has glib:type-struct=\"{}\" but there is no such record",
                               name,
                               type_struct);
                    }

                    let type_struct_type = self.type_(type_struct_tid.unwrap());

                    if let Type::Record(ref r) = *type_struct_type {
                        if r.gtype_struct_for.as_ref() != Some(name) {
                            if let Some(ref gtype_struct_for) = r.gtype_struct_for {
                                panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has glib:is-gtype-struct-for={:?}",
                                       name,
                                       type_struct,
                                       r.name,
                                       gtype_struct_for);
                            } else {
                                panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has no glib:is-gtype-struct-for attribute",
                                       name,
                                       type_struct,
                                       r.name);
                            }
                        }
                    } else {
                        panic!("Element with name=\"{}\" should be a record but it isn't",
                               type_struct);
                    }
                } else if let Some(ref c) = *c_class_type {
                    panic!("\"{}\" has no glib:type-struct but there is an element with glib:is-gtype-struct-for=\"{}\"",
                           name,
                           c);
                }
                // else both type_struct and c_class_type are None,
                // and that's fine because they don't reference each
                // other.
            }
        }
    }

    fn fix_fields(&mut self) {
        enum Action {
            SetCType(String),
            SetName(String),
        }
        let mut actions: Vec<(TypeId, usize, Action)> = Vec::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(Class { ref name, ref fields, ..}) |
                    Type::Record(Record { ref name, ref fields, ..}) |
                    Type::Union(Union { ref name, ref fields, ..}) => {
                        for (fid, field) in fields.iter().enumerate() {
                            if nameutil::needs_mangling(&field.name) {
                                let new_name = nameutil::mangle_keywords(&*field.name).to_string();
                                actions.push((tid, fid, Action::SetName(new_name)));
                            }
                            if field.c_type.is_some() {
                                continue;
                            }
                            let field_type = self.type_(field.typ);
                            if let Some(_) = field_type.maybe_ref_as::<Function>() {
                                // Function pointers generally don't have c_type.
                                continue;
                            }
                            if let Some(c_type) = field_type.get_glib_name() {
                                actions.push((tid, fid, Action::SetCType(c_type.to_owned())));
                                continue;
                            }
                            if let Type::Fundamental(Fundamental::Pointer) = *field_type {
                                // For example SoupBuffer is missing c:type for data field.
                                actions.push((tid, fid, Action::SetCType("void*".to_owned())));
                                continue;
                            }
                            error!("Field `{}::{}` is missing c:type", name, &field.name);
                        }
                    },
                    _ => {},
                }
            }
        }
        for (tid, fid, action) in actions {
            match *self.type_mut(tid) {
                Type::Class(Class { ref name, ref mut fields, ..}) |
                Type::Record(Record { ref name, ref mut fields, ..}) |
                Type::Union(Union { ref name, ref mut fields, ..}) => {
                    match action {
                        Action::SetCType(c_type) => {
                            warn!("Field `{}::{}` missing c:type assumed to be `{}`",
                                  name, &fields[fid].name, c_type);
                            fields[fid].c_type = Some(c_type);
                        }
                        Action::SetName(name) => fields[fid].name = name,
                    }
                },
                _ => unreachable!("Expected class, record or union"),
            }
        }
    }

    fn make_unrepresentable_types_opaque(&mut self) {
        let mut unrepresentable: Vec<(TypeId, String)> = Vec::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap();
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(Class {ref fields, ..}) |
                    Type::Record(Record {ref fields, ..}) |
                    Type::Union(Union {ref fields, ..}) if !fields.is_empty() => {
                        if let Err(reason) = is_representable(self, tid) {
                            unrepresentable.push((tid, reason));
                        }
                    },
                    _ => {},
                }
            }
        }
        for (tid, reason) in unrepresentable {
            match *self.type_mut(tid) {
                Type::Class(Class {ref name, ref mut fields, ..}) |
                Type::Record(Record {ref name, ref mut fields, ..}) |
                Type::Union(Union {ref name, ref mut fields, ..}) => {
                    if name == "EventKey" || name == "EventScroll" {
                        // Make an exception for GdkEventKey and GdkEventScroll
                        // as we already have manual bindings that use those.
                        continue;
                    }
                    info!("Type `{}` is not representable: {}.", name, reason);
                    fields.clear();
                }
                _ => unreachable!("Expected class, record or union"),
            }
        }
    }
}

fn is_representable(lib: &Library, tid: TypeId) -> Result<(), String> {
    match *lib.type_(tid) {
        Type::Fundamental(Fundamental::None) => Err("void".to_owned()),
        Type::Fundamental(Fundamental::Unsupported) => Err("unsupported".to_owned()),
        Type::Fundamental(_) => Ok(()),
        Type::Alias(ref alias) => {
            if is_ptr(lib, &alias.target_c_type) {
                return Ok(())
            }
            is_representable(lib, alias.typ)
        },
        Type::Class(Class {ref fields, ..}) |
        Type::Record(Record {ref fields, ..}) |
        Type::Union(Union {ref fields, ..}) => {
            if fields.is_empty() {
                return Err("opaque type".to_owned())
            }
            for field in fields {
                if field.bits.is_some() {
                    return Err(format!("{} is bitfield", field.name));
                }
                if let Some(ref c_type) = field.c_type {
                    if !is_ptr(lib, c_type) {
                        if let Err(reason) = is_representable(lib, field.typ) {
                            return Err(format!("{}::{}", field.name, reason));
                        }
                    }
                }
            }
            Ok(())
        },
        Type::Interface(..) => Err("interface".to_owned()),
        Type::FixedArray(inner, ..) => {
            is_representable(lib, inner)
        },
        Type::Function(..) |
        Type::Enumeration(..) |
        Type::Bitfield(..) |
        Type::Array(..) |
        Type::CArray(..) |
        Type::PtrArray(..) |
        Type::HashTable(..) |
        Type::List(..) |
        Type::SList(..) => {
            Ok(())
        }
    }
}

fn is_ptr(_lib: &Library, c_type: &str) -> bool {
    c_type.contains("*")
}
<commit_msg>Restore support for truncated types.<commit_after>use std::collections::HashMap;

use library::*;
use nameutil;
use parser::is_empty_c_type;
use traits::MaybeRefAs;

impl Namespace {
    fn unresolved(&self) -> Vec<&str> {
        self.index
            .iter()
            .filter_map(|(name, &id)| if self.types[id as usize].is_none() {
                Some(&name[..])
            } else {
                None
            })
            .collect()
    }
}

type DetectedCTypes = HashMap<TypeId, String>;

impl Library {
    pub fn postprocessing(&mut self) {
        self.fix_gtype();
        self.check_resolved();
        self.fill_empty_signals_c_types();
        self.resolve_class_structs();
        self.correlate_class_structs();
        self.fix_fields();
        self.make_unrepresentable_types_opaque();
    }

    fn fix_gtype(&mut self) {
        if let Some(ns_id) = self.find_namespace("GObject") {
            // hide the `GType` type alias in `GObject`
            self.add_type(ns_id, "Type", Type::Fundamental(Fundamental::Unsupported));
        }
    }

    fn check_resolved(&self) {
        let list: Vec<_> = self.index
            .iter()
            .flat_map(|(name, &id)| {
                let name = name.clone();
                self.namespace(id)
                    .unresolved()
                    .into_iter()
                    .map(move |s| format!("{}.{}", name, s))
            })
            .collect();

        if !list.is_empty() {
            panic!("Incomplete library, unresolved: {:?}", list);
        }
    }

    fn fill_empty_signals_c_types(&mut self) {
        let mut tids = Vec::new();
        let mut c_types = DetectedCTypes::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(ref klass) => {
                        if self.detect_empty_signals_c_types(&klass.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    Type::Interface(ref iface) => {
                        if self.detect_empty_signals_c_types(&iface.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    _ => (),
                }
            }
        }

        fn update_empty_signals_c_types(signals: &mut [Signal], c_types: &DetectedCTypes) {
            for signal in signals {
                update_empty_signal_c_types(signal, c_types);
            }
        }

        fn update_empty_signal_c_types(signal: &mut Signal, c_types: &DetectedCTypes) {
            for par in &mut signal.parameters {
                update_empty_c_type(&mut par.c_type, par.typ, c_types);
            }
            update_empty_c_type(&mut signal.ret.c_type, signal.ret.typ, c_types);
        }

        fn update_empty_c_type(c_type: &mut String, tid: TypeId, c_types: &DetectedCTypes) {
            if !is_empty_c_type(c_type) {
                return;
            }
            if let Some(ref mut s) = c_types.get(&tid) {
                *c_type = s.clone();
            }
        }

        for tid in tids {
            match *self.type_mut(tid) {
                Type::Class(ref mut klass) => {
                    update_empty_signals_c_types(&mut klass.signals, &c_types)
                }
                Type::Interface(ref mut iface) => {
                    update_empty_signals_c_types(&mut iface.signals, &c_types)
                }
                _ => (),
            }
        }
    }

    fn detect_empty_signals_c_types(
        &self,
        signals: &[Signal],
        c_types: &mut DetectedCTypes,
    ) -> bool {
        let mut detected = false;
        for signal in signals {
            if self.detect_empty_signal_c_types(signal, c_types) {
                detected = true;
            }
        }
        detected
    }

    fn detect_empty_signal_c_types(&self, signal: &Signal, c_types: &mut DetectedCTypes) -> bool {
        let mut detected = false;
        for par in &signal.parameters {
            if self.detect_empty_c_type(&par.c_type, par.typ, c_types) {
                detected = true;
            }
        }
        if self.detect_empty_c_type(&signal.ret.c_type, signal.ret.typ, c_types) {
            detected = true;
        }
        detected
    }

    fn detect_empty_c_type(&self, c_type: &str, tid: TypeId, c_types: &mut DetectedCTypes) -> bool {
        if !is_empty_c_type(c_type) {
            return false;
        }
        if !c_types.contains_key(&tid) {
            if let Some(detected_c_type) = self.c_type_by_type_id(tid) {
                c_types.insert(tid, detected_c_type);
            }
        }
        true
    }

    fn c_type_by_type_id(&self, tid: TypeId) -> Option<String> {
        let type_ = self.type_(tid);
        type_
            .get_glib_name()
            .map(|glib_name| if self.is_referenced_type(type_) {
                format!("{}*", glib_name)
            } else {
                glib_name.to_string()
            })
    }

    fn is_referenced_type(&self, type_: &Type) -> bool {
        use library::Type::*;
        match *type_ {
            Alias(ref alias) => self.is_referenced_type(self.type_(alias.typ)),
            Record(..) | Union(..) | Class(..) | Interface(..) => true,
            _ => false,
        }
    }

    fn resolve_class_structs(&mut self) {
        // stores pairs of (gtype-struct-c-name, type-name)
        let mut structs_and_types = Vec::new();

        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in &ns.types {
                let type_ = type_.as_ref().unwrap(); //Always contains something

                if let Type::Record(ref record) = *type_ {
                    if let Some(ref struct_for) = record.gtype_struct_for {
                        if let Some(struct_for_tid) = self.find_type(ns_id as u16, struct_for) {
                            structs_and_types.push ((record.c_type.clone(), struct_for_tid));
                        }
                    }
                }
            }
        }

        for (gtype_struct_c_type, struct_for_tid) in structs_and_types {
            match *self.type_mut(struct_for_tid) {
                Type::Class(ref mut klass) => {
                    klass.c_class_type = Some(gtype_struct_c_type);
                },

                Type::Interface(ref mut iface) => {
                    iface.c_class_type = Some(gtype_struct_c_type);
                },

                ref x => unreachable!("Something other than a class or interface has a class struct: {:?}", x)
            }
        }
    }

    fn correlate_class_structs(&self) {
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in &ns.types {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let name;
                let type_struct;
                let c_class_type;

                match *type_ {
                    Type::Class(ref klass) => {
                        name         = &klass.name;
                        type_struct  = &klass.type_struct;
                        c_class_type = &klass.c_class_type;
                    },

                    Type::Interface(ref iface) => {
                        name         = &iface.name;
                        type_struct  = &iface.type_struct;
                        c_class_type = &iface.c_class_type;
                    },

                    _ => { continue; }
                }

                if let Some(ref type_struct) = *type_struct {
                    let type_struct_tid = self.find_type(ns_id as u16, type_struct);
                    if type_struct_tid.is_none() {
                        panic!("\"{}\" has glib:type-struct=\"{}\" but there is no such record",
                               name,
                               type_struct);
                    }

                    let type_struct_type = self.type_(type_struct_tid.unwrap());

                    if let Type::Record(ref r) = *type_struct_type {
                        if r.gtype_struct_for.as_ref() != Some(name) {
                            if let Some(ref gtype_struct_for) = r.gtype_struct_for {
                                panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has glib:is-gtype-struct-for={:?}",
                                       name,
                                       type_struct,
                                       r.name,
                                       gtype_struct_for);
                            } else {
                                panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has no glib:is-gtype-struct-for attribute",
                                       name,
                                       type_struct,
                                       r.name);
                            }
                        }
                    } else {
                        panic!("Element with name=\"{}\" should be a record but it isn't",
                               type_struct);
                    }
                } else if let Some(ref c) = *c_class_type {
                    panic!("\"{}\" has no glib:type-struct but there is an element with glib:is-gtype-struct-for=\"{}\"",
                           name,
                           c);
                }
                // else both type_struct and c_class_type are None,
                // and that's fine because they don't reference each
                // other.
            }
        }
    }

    fn fix_fields(&mut self) {
        enum Action {
            SetCType(String),
            SetName(String),
        }
        let mut actions: Vec<(TypeId, usize, Action)> = Vec::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(Class { ref name, ref fields, ..}) |
                    Type::Record(Record { ref name, ref fields, ..}) |
                    Type::Union(Union { ref name, ref fields, ..}) => {
                        for (fid, field) in fields.iter().enumerate() {
                            if nameutil::needs_mangling(&field.name) {
                                let new_name = nameutil::mangle_keywords(&*field.name).to_string();
                                actions.push((tid, fid, Action::SetName(new_name)));
                            }
                            if field.c_type.is_some() {
                                continue;
                            }
                            let field_type = self.type_(field.typ);
                            if let Some(_) = field_type.maybe_ref_as::<Function>() {
                                // Function pointers generally don't have c_type.
                                continue;
                            }
                            if let Some(c_type) = field_type.get_glib_name() {
                                actions.push((tid, fid, Action::SetCType(c_type.to_owned())));
                                continue;
                            }
                            if let Type::Fundamental(Fundamental::Pointer) = *field_type {
                                // For example SoupBuffer is missing c:type for data field.
                                actions.push((tid, fid, Action::SetCType("void*".to_owned())));
                                continue;
                            }
                            error!("Field `{}::{}` is missing c:type", name, &field.name);
                        }
                    },
                    _ => {},
                }
            }
        }
        for (tid, fid, action) in actions {
            match *self.type_mut(tid) {
                Type::Class(Class { ref name, ref mut fields, ..}) |
                Type::Record(Record { ref name, ref mut fields, ..}) |
                Type::Union(Union { ref name, ref mut fields, ..}) => {
                    match action {
                        Action::SetCType(c_type) => {
                            warn!("Field `{}::{}` missing c:type assumed to be `{}`",
                                  name, &fields[fid].name, c_type);
                            fields[fid].c_type = Some(c_type);
                        }
                        Action::SetName(name) => fields[fid].name = name,
                    }
                },
                _ => unreachable!("Expected class, record or union"),
            }
        }
    }

    fn make_unrepresentable_types_opaque(&mut self) {
        // Unions with non-`Copy` fields are unstable (see issue #32836).
        // It would seem that this shouldn't be cause for concern as one can
        // always make all types in the union copyable.
        //
        // Unfortunately, this is not that simple, as some types are currently
        // unrepresentable in Rust, and they do occur inside the unions.
        // Thus to avoid the problem, we mark all unions with such unrepresentable
        // types as opaque, and don't generate their definitions.
        let mut unrepresentable: Vec<(TypeId, String)> = Vec::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap();
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Union(Union {ref fields, ..}) if !fields.is_empty() => {
                        if let Err(reason) = is_representable(self, tid) {
                            unrepresentable.push((tid, reason));
                        }
                    },
                    _ => {},
                }
            }
        }
        for (tid, reason) in unrepresentable {
            match *self.type_mut(tid) {
                Type::Union(Union {ref name, ref mut fields, ..}) => {
                    info!("Type `{}` is not representable: {}.", name, reason);
                    fields.clear();
                }
                _ => unreachable!("Expected a union"),
            }
        }
    }
}

fn is_representable(lib: &Library, tid: TypeId) -> Result<(), String> {
    match *lib.type_(tid) {
        Type::Fundamental(Fundamental::None) => Err("void".to_owned()),
        Type::Fundamental(Fundamental::Unsupported) => Err("unsupported".to_owned()),
        Type::Fundamental(_) => Ok(()),
        Type::Alias(ref alias) => {
            if is_ptr(lib, &alias.target_c_type) {
                return Ok(())
            }
            is_representable(lib, alias.typ)
        },
        Type::Class(Class {ref fields, ..}) |
        Type::Record(Record {ref fields, ..}) |
        Type::Union(Union {ref fields, ..}) => {
            if fields.is_empty() {
                return Err("opaque type".to_owned())
            }
            for field in fields {
                if field.bits.is_some() {
                    return Err(format!("{} is bitfield", field.name));
                }
                if let Some(ref c_type) = field.c_type {
                    if !is_ptr(lib, c_type) {
                        if let Err(reason) = is_representable(lib, field.typ) {
                            return Err(format!("{}::{}", field.name, reason));
                        }
                    }
                }
            }
            Ok(())
        },
        Type::Interface(..) => Err("interface".to_owned()),
        Type::FixedArray(inner, ..) => {
            is_representable(lib, inner)
        },
        Type::Function(..) |
        Type::Enumeration(..) |
        Type::Bitfield(..) |
        Type::Array(..) |
        Type::CArray(..) |
        Type::PtrArray(..) |
        Type::HashTable(..) |
        Type::List(..) |
        Type::SList(..) => {
            Ok(())
        }
    }
}

fn is_ptr(_lib: &Library, c_type: &str) -> bool {
    c_type.contains("*")
}
<|endoftext|>


<commit_before>use std::num;
use std::num::{One, Zero};

use super::super::matrix::*;
use super::super::util::{alloc_dirty_vec};

pub struct CholeskyDecomposition<T> {
  l : Matrix<T>
}

// Ported from JAMA.
// Cholesky Decomposition.
//
// For a symmetric, positive definite matrix A, the Cholesky decomposition
// is an lower triangular matrix L so that A = L*L'.
//
// If the matrix is not symmetric or positive definite, None is returned.
impl<T : Add<T, T> + Sub<T, T> + Mul<T, T> + Div<T, T> + Neg<T> + Eq + Ord + ApproxEq<T> + One + Zero + Clone + Algebraic> CholeskyDecomposition<T> {
  fn new(m : &Matrix<T>) -> Option<CholeskyDecomposition<T>> {
    if(m.noRows != m.noCols) {
      return None
    }
    let n = m.noRows;
    let mut data : ~[T] = alloc_dirty_vec(n * n);

    for j in range(0u, n) {
      let rowjIdx = j * n;
      let mut d : T = Zero::zero();
      for k in range(0u, j) {
        let rowkIdx = k * n;
        let mut s : T = Zero::zero();
        for i in range(0u, k) {
          s = s + data[rowkIdx + i] * data[rowjIdx + i];
        }
        s = (m.data[rowjIdx + k] - s) / data[rowkIdx + k];
        data[rowjIdx + k] = s.clone();
        d = d + s * s;
        if(m.data[rowkIdx + j] != m.data[rowjIdx + k]) {
          return None
        }
      }

      d = m.data[rowjIdx + j] - d;
      if(d <= Zero::zero()) {
        return None
      }
      data[rowjIdx + j] = num::sqrt(if d > Zero::zero() { d } else { Zero::zero() });
      for k in range(j + 1, n) {
        data[rowjIdx + k] = Zero::zero();
      }
    }

    Some(CholeskyDecomposition { l : Matrix { noRows : n, noCols : n, data : data } })
  }

  #[inline]
  fn get_l<'lt>(&'lt self) -> &'lt Matrix<T> { &self.l }

  // Solve: Ax = b
  pub fn solve(&self, b : &Matrix<T>) -> Matrix<T> {
    let l = &self.l;
    assert!(l.noRows == b.noRows);
    let n = l.noRows;
    let mut xdata = b.data.clone();
    let nx = b.noCols;

    // Solve L*Y = B
    for k in range(0u, n) {
      for j in range(0u, nx) {
        for i in range(0u, k) {
          xdata[k * nx + j] = xdata[k * nx + j] - xdata[i * nx + j] * l.data[k * n + i];
        }
        xdata[k * nx + j] = xdata[k * nx + j] / l.data[k * n + k];
      }
    }

    // Solve L'*X = Y
    for k in range(0u, n).invert() {
      for j in range(0u, nx) {
        for i in range(k + 1, n) {
          xdata[k * nx + j] = xdata[k * nx + j] - xdata[i * nx + j] * l.data[i * n + k];
        }
        xdata[k * nx + j] = xdata[k * nx + j] / l.data[k * n + k];
      }
    }

    Matrix { noRows : n, noCols : nx, data : xdata }
  }
}

#[test]
fn cholesky_square_pos_def_test() {
  let a = matrix(3, 3, ~[4.0, 12.0, -16.0, 12.0, 37.0, -43.0, -16.0, -43.0, 98.0]);
  match(CholeskyDecomposition::new(&a)) {
    None => assert!(false),
    Some(c) => { assert!(c.get_l() * c.get_l().t() == a) }
  }
}

#[test]
fn cholesky_not_pos_def_test() {
  let a = matrix(3, 3, ~[4.0, 12.0, -16.0, 12.0, 37.0, 43.0, -16.0, 43.0, 98.0]);
  match(CholeskyDecomposition::new(&a)) {
    None => (),
    _ => assert!(false)
  }
}

#[test]
fn cholesky_not_square_test() {
  let a = matrix(2, 3, ~[4.0, 12.0, -16.0, 12.0, 37.0, 43.0]);
  match(CholeskyDecomposition::new(&a)) {
    None => (),
    _ => assert!(false)
  }
}
<commit_msg>Add test for Cholesky solve.<commit_after>use std::num;
use std::num::{One, Zero};

use super::super::matrix::*;
use super::super::util::{alloc_dirty_vec};

pub struct CholeskyDecomposition<T> {
  l : Matrix<T>
}

// Ported from JAMA.
// Cholesky Decomposition.
//
// For a symmetric, positive definite matrix A, the Cholesky decomposition
// is an lower triangular matrix L so that A = L*L'.
//
// If the matrix is not symmetric or positive definite, None is returned.
impl<T : Add<T, T> + Sub<T, T> + Mul<T, T> + Div<T, T> + Neg<T> + Eq + Ord + ApproxEq<T> + One + Zero + Clone + Algebraic> CholeskyDecomposition<T> {
  fn new(m : &Matrix<T>) -> Option<CholeskyDecomposition<T>> {
    if(m.noRows != m.noCols) {
      return None
    }
    let n = m.noRows;
    let mut data : ~[T] = alloc_dirty_vec(n * n);

    for j in range(0u, n) {
      let rowjIdx = j * n;
      let mut d : T = Zero::zero();
      for k in range(0u, j) {
        let rowkIdx = k * n;
        let mut s : T = Zero::zero();
        for i in range(0u, k) {
          s = s + data[rowkIdx + i] * data[rowjIdx + i];
        }
        s = (m.data[rowjIdx + k] - s) / data[rowkIdx + k];
        data[rowjIdx + k] = s.clone();
        d = d + s * s;
        if(m.data[rowkIdx + j] != m.data[rowjIdx + k]) {
          return None
        }
      }

      d = m.data[rowjIdx + j] - d;
      if(d <= Zero::zero()) {
        return None
      }
      data[rowjIdx + j] = num::sqrt(if d > Zero::zero() { d } else { Zero::zero() });
      for k in range(j + 1, n) {
        data[rowjIdx + k] = Zero::zero();
      }
    }

    Some(CholeskyDecomposition { l : Matrix { noRows : n, noCols : n, data : data } })
  }

  #[inline]
  fn get_l<'lt>(&'lt self) -> &'lt Matrix<T> { &self.l }

  // Solve: Ax = b
  pub fn solve(&self, b : &Matrix<T>) -> Matrix<T> {
    let l = &self.l;
    assert!(l.noRows == b.noRows);
    let n = l.noRows;
    let mut xdata = b.data.clone();
    let nx = b.noCols;

    // Solve L*Y = B
    for k in range(0u, n) {
      for j in range(0u, nx) {
        for i in range(0u, k) {
          xdata[k * nx + j] = xdata[k * nx + j] - xdata[i * nx + j] * l.data[k * n + i];
        }
        xdata[k * nx + j] = xdata[k * nx + j] / l.data[k * n + k];
      }
    }

    // Solve L'*X = Y
    for k in range(0u, n).invert() {
      for j in range(0u, nx) {
        for i in range(k + 1, n) {
          xdata[k * nx + j] = xdata[k * nx + j] - xdata[i * nx + j] * l.data[i * n + k];
        }
        xdata[k * nx + j] = xdata[k * nx + j] / l.data[k * n + k];
      }
    }

    Matrix { noRows : n, noCols : nx, data : xdata }
  }
}

#[test]
fn cholesky_square_pos_def_test() {
  let a = matrix(3, 3, ~[4.0, 12.0, -16.0, 12.0, 37.0, -43.0, -16.0, -43.0, 98.0]);
  match(CholeskyDecomposition::new(&a)) {
    None => assert!(false),
    Some(c) => { assert!(c.get_l() * c.get_l().t() == a) }
  }
}

#[test]
fn cholesky_not_pos_def_test() {
  let a = matrix(3, 3, ~[4.0, 12.0, -16.0, 12.0, 37.0, 43.0, -16.0, 43.0, 98.0]);
  match(CholeskyDecomposition::new(&a)) {
    None => (),
    _ => assert!(false)
  }
}

#[test]
fn cholesky_not_square_test() {
  let a = matrix(2, 3, ~[4.0, 12.0, -16.0, 12.0, 37.0, 43.0]);
  match(CholeskyDecomposition::new(&a)) {
    None => (),
    _ => assert!(false)
  }
}

#[test]
fn cholesky_solve_test() {
  let a = matrix(3, 3, ~[2.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0]);
  match(CholeskyDecomposition::new(&a)) {
    None => assert!(false),
    Some(c) => {
      let b = vector(~[1.0, 2.0, 3.0]);
      let x = c.solve(&b);
      assert!(x.approx_eq(&vector(~[-1.0, 3.0, 3.0])));
    }
  }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use libc;
use cell::UnsafeCell;
use sync::atomic::{AtomicUsize, Ordering};

pub struct RWLock {
    inner: UnsafeCell<libc::pthread_rwlock_t>,
    write_locked: UnsafeCell<bool>,
    num_readers: AtomicUsize,
}

unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}

impl RWLock {
    pub const fn new() -> RWLock {
        RWLock {
            inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER),
            write_locked: UnsafeCell::new(false),
            num_readers: AtomicUsize::new(0),
        }
    }
    #[inline]
    pub unsafe fn read(&self) {
        let r = libc::pthread_rwlock_rdlock(self.inner.get());

        // According to the pthread_rwlock_rdlock spec, this function **may**
        // fail with EDEADLK if a deadlock is detected. On the other hand
        // pthread mutexes will *never* return EDEADLK if they are initialized
        // as the "fast" kind (which ours always are). As a result, a deadlock
        // situation may actually return from the call to pthread_rwlock_rdlock
        // instead of blocking forever (as mutexes and Windows rwlocks do). Note
        // that not all unix implementations, however, will return EDEADLK for
        // their rwlocks.
        //
        // We roughly maintain the deadlocking behavior by panicking to ensure
        // that this lock acquisition does not succeed.
        //
        // We also check whether there this lock is already write locked. This
        // is only possible if it was write locked by the current thread and
        // the implementation allows recursive locking. The POSIX standard
        // doesn't require recursivly locking a rwlock to deadlock, but we can't
        // allow that because it could lead to aliasing issues.
        if r == libc::EAGAIN {
            panic!("rwlock maximum reader count exceeded");
        } else if r == libc::EDEADLK || *self.write_locked.get() {
            if r == 0 {
                self.raw_unlock();
            }
            panic!("rwlock read lock would result in deadlock");
        } else {
            debug_assert_eq!(r, 0);
            self.num_readers.fetch_add(1, Ordering::Relaxed);
        }
    }
    #[inline]
    pub unsafe fn try_read(&self) -> bool {
        let r = libc::pthread_rwlock_tryrdlock(self.inner.get());
        if r == 0 {
            if *self.write_locked.get() {
                self.raw_unlock();
                false
            } else {
                self.num_readers.fetch_add(1, Ordering::Relaxed);
                true
            }
        } else {
            false
        }
    }
    #[inline]
    pub unsafe fn write(&self) {
        let r = libc::pthread_rwlock_wrlock(self.inner.get());
        // See comments above for why we check for EDEADLK and write_locked. We
        // also need to check that num_readers is 0.
        if r == libc::EDEADLK || *self.write_locked.get() ||
           self.num_readers.load(Ordering::Relaxed) != 0 {
            if r == 0 {
                self.raw_unlock();
            }
            panic!("rwlock write lock would result in deadlock");
        } else {
            debug_assert_eq!(r, 0);
        }
        *self.write_locked.get() = true;
    }
    #[inline]
    pub unsafe fn try_write(&self) -> bool {
        let r = libc::pthread_rwlock_trywrlock(self.inner.get());
        if r == 0 {
            if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 {
                self.raw_unlock();
                false
            } else {
                *self.write_locked.get() = true;
                true
            }
        } else {
            false
        }
    }
    #[inline]
    unsafe fn raw_unlock(&self) {
        let r = libc::pthread_rwlock_unlock(self.inner.get());
        debug_assert_eq!(r, 0);
    }
    #[inline]
    pub unsafe fn read_unlock(&self) {
        debug_assert!(!*self.write_locked.get());
        self.num_readers.fetch_sub(1, Ordering::Relaxed);
        self.raw_unlock();
    }
    #[inline]
    pub unsafe fn write_unlock(&self) {
        debug_assert_eq!(self.num_readers.load(Ordering::Relaxed), 0);
        debug_assert!(*self.write_locked.get());
        *self.write_locked.get() = false;
        self.raw_unlock();
    }
    #[inline]
    pub unsafe fn destroy(&self) {
        let r = libc::pthread_rwlock_destroy(self.inner.get());
        // On DragonFly pthread_rwlock_destroy() returns EINVAL if called on a
        // rwlock that was just initialized with
        // libc::PTHREAD_RWLOCK_INITIALIZER. Once it is used (locked/unlocked)
        // or pthread_rwlock_init() is called, this behaviour no longer occurs.
        if cfg!(target_os = "dragonfly") {
            debug_assert!(r == 0 || r == libc::EINVAL);
        } else {
            debug_assert_eq!(r, 0);
        }
    }
}
<commit_msg>Rollup merge of #35842 - apasel422:typo, r=GuillaumeGomez<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use libc;
use cell::UnsafeCell;
use sync::atomic::{AtomicUsize, Ordering};

pub struct RWLock {
    inner: UnsafeCell<libc::pthread_rwlock_t>,
    write_locked: UnsafeCell<bool>,
    num_readers: AtomicUsize,
}

unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}

impl RWLock {
    pub const fn new() -> RWLock {
        RWLock {
            inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER),
            write_locked: UnsafeCell::new(false),
            num_readers: AtomicUsize::new(0),
        }
    }
    #[inline]
    pub unsafe fn read(&self) {
        let r = libc::pthread_rwlock_rdlock(self.inner.get());

        // According to the pthread_rwlock_rdlock spec, this function **may**
        // fail with EDEADLK if a deadlock is detected. On the other hand
        // pthread mutexes will *never* return EDEADLK if they are initialized
        // as the "fast" kind (which ours always are). As a result, a deadlock
        // situation may actually return from the call to pthread_rwlock_rdlock
        // instead of blocking forever (as mutexes and Windows rwlocks do). Note
        // that not all unix implementations, however, will return EDEADLK for
        // their rwlocks.
        //
        // We roughly maintain the deadlocking behavior by panicking to ensure
        // that this lock acquisition does not succeed.
        //
        // We also check whether this lock is already write locked. This
        // is only possible if it was write locked by the current thread and
        // the implementation allows recursive locking. The POSIX standard
        // doesn't require recursively locking a rwlock to deadlock, but we can't
        // allow that because it could lead to aliasing issues.
        if r == libc::EAGAIN {
            panic!("rwlock maximum reader count exceeded");
        } else if r == libc::EDEADLK || *self.write_locked.get() {
            if r == 0 {
                self.raw_unlock();
            }
            panic!("rwlock read lock would result in deadlock");
        } else {
            debug_assert_eq!(r, 0);
            self.num_readers.fetch_add(1, Ordering::Relaxed);
        }
    }
    #[inline]
    pub unsafe fn try_read(&self) -> bool {
        let r = libc::pthread_rwlock_tryrdlock(self.inner.get());
        if r == 0 {
            if *self.write_locked.get() {
                self.raw_unlock();
                false
            } else {
                self.num_readers.fetch_add(1, Ordering::Relaxed);
                true
            }
        } else {
            false
        }
    }
    #[inline]
    pub unsafe fn write(&self) {
        let r = libc::pthread_rwlock_wrlock(self.inner.get());
        // See comments above for why we check for EDEADLK and write_locked. We
        // also need to check that num_readers is 0.
        if r == libc::EDEADLK || *self.write_locked.get() ||
           self.num_readers.load(Ordering::Relaxed) != 0 {
            if r == 0 {
                self.raw_unlock();
            }
            panic!("rwlock write lock would result in deadlock");
        } else {
            debug_assert_eq!(r, 0);
        }
        *self.write_locked.get() = true;
    }
    #[inline]
    pub unsafe fn try_write(&self) -> bool {
        let r = libc::pthread_rwlock_trywrlock(self.inner.get());
        if r == 0 {
            if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 {
                self.raw_unlock();
                false
            } else {
                *self.write_locked.get() = true;
                true
            }
        } else {
            false
        }
    }
    #[inline]
    unsafe fn raw_unlock(&self) {
        let r = libc::pthread_rwlock_unlock(self.inner.get());
        debug_assert_eq!(r, 0);
    }
    #[inline]
    pub unsafe fn read_unlock(&self) {
        debug_assert!(!*self.write_locked.get());
        self.num_readers.fetch_sub(1, Ordering::Relaxed);
        self.raw_unlock();
    }
    #[inline]
    pub unsafe fn write_unlock(&self) {
        debug_assert_eq!(self.num_readers.load(Ordering::Relaxed), 0);
        debug_assert!(*self.write_locked.get());
        *self.write_locked.get() = false;
        self.raw_unlock();
    }
    #[inline]
    pub unsafe fn destroy(&self) {
        let r = libc::pthread_rwlock_destroy(self.inner.get());
        // On DragonFly pthread_rwlock_destroy() returns EINVAL if called on a
        // rwlock that was just initialized with
        // libc::PTHREAD_RWLOCK_INITIALIZER. Once it is used (locked/unlocked)
        // or pthread_rwlock_init() is called, this behaviour no longer occurs.
        if cfg!(target_os = "dragonfly") {
            debug_assert!(r == 0 || r == libc::EINVAL);
        } else {
            debug_assert_eq!(r, 0);
        }
    }
}
<|endoftext|>


<commit_before>use std::num::Float;
use std::f64::consts::PI;

use sdl2::event::Event;
use sdl2::mouse;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::render::RenderDrawer;

static PADDLE_COLOR: Color = Color::RGB(255, 255, 255);
static PADDLE_WIDTH: i32 = 12;
static PADDLE_HEIGHT: i32 = 64;
static PADDLE_WALL_PADDING: i32 = 10;

static BALL_COLOR: Color = Color::RGB(175, 175, 175);
static BALL_BREADTH: i32 = 8;
static BALL_VELOCITY: f64 = 10.0;
static BALL_INITIAL_ANGLE_DEGREES: i32 = 45;

pub struct GameController {
    ball_position: (i32, i32),
    ball_angle: f64,
    player_paddle_y: i32,
    opponent_paddle_y: i32
}

impl GameController {
    pub fn new() -> GameController {
        return GameController{
            ball_position: (800 / 2 - BALL_BREADTH / 2, 600 / 2 - BALL_BREADTH / 2),
            ball_angle: (BALL_INITIAL_ANGLE_DEGREES as f64).to_radians(),
            player_paddle_y: 280,
            opponent_paddle_y: 10,
        }
    }

    pub fn tick(&mut self, _: &Event, drawer: &mut RenderDrawer) {
        self.move_player_paddle();
        self.move_ball();
        self.draw_player(drawer);
        self.draw_opponent(drawer);
        self.draw_ball(drawer);
    }

    fn move_player_paddle(&mut self) {
        let (_, _, y) = mouse::get_mouse_state();
        self.player_paddle_y = y;
    }

    // TODO this shouldn't be framerate/vsync dependent.
    // Thanks StackOverflow!
    // http://stackoverflow.com/questions/5830791/find-radians-reflection-angle
    fn move_ball(&mut self) {
        let x_change = (self.ball_angle.cos() * BALL_VELOCITY) as i32;
        let y_change = (self.ball_angle.sin() * BALL_VELOCITY) as i32;

        let (mut x, mut y) = self.ball_position;
        x += x_change;
        y += y_change;

        // Wall collision
        let upper_y_limit = 600 - BALL_BREADTH;
        if y > upper_y_limit || y < 0 { self.ball_angle *= -1.0 }
        if y > upper_y_limit { y = upper_y_limit; }
        else if y < 0 { y = 0; }

        // Paddle collision
        // TODO ball dimensions aren't respected. Left side of ball hits on the left, right side of
        // ball hits on the right. Also need to reset ball x on impact.
        let player_paddle_x = PADDLE_WALL_PADDING + PADDLE_WIDTH;
        let player_paddle_impacted = x <= player_paddle_x && y >= self.player_paddle_y && y <= self.player_paddle_y + PADDLE_HEIGHT;
        let opponent_paddle_x = 800 - PADDLE_WALL_PADDING - PADDLE_WIDTH - BALL_BREADTH;
        //let opponent_paddle_impacted = x >= opponent_paddle_x && y >= self.opponent_paddle_y && y <= self.opponent_paddle_y + PADDLE_HEIGHT;
        let opponent_paddle_impacted = x >= opponent_paddle_x; // Invincible opponent until AI.
        if player_paddle_impacted || opponent_paddle_impacted {
            self.ball_angle = 0.0 - PI - self.ball_angle;
        }

        self.ball_position = (x, y);
    }

    fn draw_player(&self, d: &mut RenderDrawer) {
        self.draw_box(d, PADDLE_WALL_PADDING, self.player_paddle_y);
    }

    fn draw_opponent(&self, d: &mut RenderDrawer) {
        self.draw_box(d, 800 - PADDLE_WIDTH - PADDLE_WALL_PADDING, self.opponent_paddle_y);
    }

    fn draw_box(&self, d: &mut RenderDrawer, x: i32, y: i32) {
        d.set_draw_color(PADDLE_COLOR);
        let r = Rect{x: x, y: y, w: PADDLE_WIDTH, h: PADDLE_HEIGHT};
        d.fill_rect(r);
     }

    fn draw_ball(&self, d: &mut RenderDrawer) {
        d.set_draw_color(BALL_COLOR);
        let (x, y) = self.ball_position;
        let r = Rect{x: x, y: y, w: BALL_BREADTH, h: BALL_BREADTH};
        d.fill_rect(r);
    }
}
<commit_msg>Impossible to defeat player AI. Not much I, very A.<commit_after>use std::num::Float;
use std::f64::consts::PI;

use sdl2::event::Event;
use sdl2::mouse;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::render::RenderDrawer;

static PADDLE_COLOR: Color = Color::RGB(255, 255, 255);
static PADDLE_WIDTH: i32 = 12;
static PADDLE_HEIGHT: i32 = 64;
static PADDLE_WALL_PADDING: i32 = 10;

static BALL_COLOR: Color = Color::RGB(175, 175, 175);
static BALL_BREADTH: i32 = 8;
static BALL_VELOCITY: f64 = 10.0;
static BALL_INITIAL_ANGLE_DEGREES: i32 = 45;

pub struct GameController {
    ball_position: (i32, i32),
    ball_angle: f64,
    player_paddle_y: i32,
    opponent_paddle_y: i32
}

impl GameController {
    pub fn new() -> GameController {
        return GameController{
            ball_position: (800 / 2 - BALL_BREADTH / 2, 600 / 2 - BALL_BREADTH / 2),
            ball_angle: (BALL_INITIAL_ANGLE_DEGREES as f64).to_radians(),
            player_paddle_y: 280,
            opponent_paddle_y: 10,
        }
    }

    pub fn tick(&mut self, _: &Event, drawer: &mut RenderDrawer) {
        self.move_player_paddle();
        self.move_opponent_paddle();
        self.move_ball();
        self.draw_player(drawer);
        self.draw_opponent(drawer);
        self.draw_ball(drawer);
    }

    fn move_player_paddle(&mut self) {
        let (_, _, y) = mouse::get_mouse_state();
        self.player_paddle_y = y;
    }

    fn move_opponent_paddle(&mut self) {
        let (_, y) = self.ball_position;
        self.opponent_paddle_y = y - PADDLE_HEIGHT / 2;
    }

    // TODO this shouldn't be framerate/vsync dependent.
    // Thanks StackOverflow!
    // http://stackoverflow.com/questions/5830791/find-radians-reflection-angle
    fn move_ball(&mut self) {
        let x_change = (self.ball_angle.cos() * BALL_VELOCITY) as i32;
        let y_change = (self.ball_angle.sin() * BALL_VELOCITY) as i32;

        let (mut x, mut y) = self.ball_position;
        x += x_change;
        y += y_change;

        // Wall collision
        let upper_y_limit = 600 - BALL_BREADTH;
        if y > upper_y_limit || y < 0 { self.ball_angle *= -1.0 }
        if y > upper_y_limit { y = upper_y_limit; }
        else if y < 0 { y = 0; }

        // Paddle collision
        // TODO ball dimensions aren't respected. Left side of ball hits on the left, right side of
        // ball hits on the right. Also need to reset ball x on impact.
        let player_paddle_x = PADDLE_WALL_PADDING + PADDLE_WIDTH;
        let player_paddle_impacted = x <= player_paddle_x && y >= self.player_paddle_y && y <= self.player_paddle_y + PADDLE_HEIGHT;
        let opponent_paddle_x = 800 - PADDLE_WALL_PADDING - PADDLE_WIDTH - BALL_BREADTH;
        let opponent_paddle_impacted = x >= opponent_paddle_x && y >= self.opponent_paddle_y && y <= self.opponent_paddle_y + PADDLE_HEIGHT;
        if player_paddle_impacted || opponent_paddle_impacted {
            self.ball_angle = 0.0 - PI - self.ball_angle;
        }

        self.ball_position = (x, y);
    }

    fn draw_player(&self, d: &mut RenderDrawer) {
        self.draw_box(d, PADDLE_WALL_PADDING, self.player_paddle_y);
    }

    fn draw_opponent(&self, d: &mut RenderDrawer) {
        self.draw_box(d, 800 - PADDLE_WIDTH - PADDLE_WALL_PADDING, self.opponent_paddle_y);
    }

    fn draw_box(&self, d: &mut RenderDrawer, x: i32, y: i32) {
        d.set_draw_color(PADDLE_COLOR);
        let r = Rect{x: x, y: y, w: PADDLE_WIDTH, h: PADDLE_HEIGHT};
        d.fill_rect(r);
     }

    fn draw_ball(&self, d: &mut RenderDrawer) {
        d.set_draw_color(BALL_COLOR);
        let (x, y) = self.ball_position;
        let r = Rect{x: x, y: y, w: BALL_BREADTH, h: BALL_BREADTH};
        d.fill_rect(r);
    }
}
<|endoftext|>


<commit_before>extern crate startuppong;
extern crate regex;

use std::io::Write;
use std::str;

use regex::Regex;

pub use startuppong::account_from_env;

use handler::MessageHandler;
use handler::HandlerResult;
use handler::HandlerError;
use message::IncomingMessage;

pub type Account = startuppong::Account;

/// Startuppong.com get_players handler
///
/// Messages requesting to "show ping pong" or "list ping pong" will result in a dump
/// of the ladder, 1 line per player, to the requester.
pub struct PrintLadder {
    account: Account,
    regex: Regex,
    max_entries: usize
}

impl PrintLadder {
    /// Create the PrintLadder handler.
    ///
    /// Requires a startuppong::Account. You will need to register on startuppong.com if you wish to
    /// use this handler.
    pub fn new(account: Account, max_entries: usize) -> PrintLadder {
        PrintLadder {
            account: account,
            regex: regex!(r"(print|list|show).+ping ?pong"),
            max_entries: max_entries
        }
    }
}

impl MessageHandler for PrintLadder {
    fn name(&self) -> &str {
        "PrintLadder"
    }

    fn re(&self) -> &Regex {
        &self.regex
    }

    fn handle(&self, incoming: &IncomingMessage) -> HandlerResult {
        let res = try!(startuppong::get_players(&self.account));
        let players = res.players();
        let mut reply = Vec::new();

        let len = if players.len() < self.max_entries {
            players.len()
        } else {
            self.max_entries
        };

        for i in 0..len {
            try!(write!(&mut reply, "{} - {}\n", players[i].rank, players[i].name));
        }

        Ok(try!(incoming.reply(str::from_utf8(&reply).unwrap().to_string())))
    }
}

impl From<startuppong::error::ApiError> for HandlerError {
    fn from(err: startuppong::error::ApiError) -> HandlerError {
        HandlerError::Other(Box::new(err))
    }
}

#[cfg(test)]
mod tests {
    use startuppong::Account;

    use handler::MessageHandler;
    use super::PrintLadder;

    #[test]
    fn check_valid_messages() {
        let acc = Account::new("a".to_string(), "b".to_string());
        let handler = PrintLadder::new(&acc);

        assert!(handler.can_handle("print the pingpong ladder"));
        assert!(handler.can_handle("list the pingpong ladder"));
        assert!(handler.can_handle("show the pingpong ladder"));
        assert!(handler.can_handle("print the ping pong ladder"));
        assert!(handler.can_handle("list the ping pong ladder"));
        assert!(handler.can_handle("show the ping pong ladder"));
    }

    #[test]
    fn check_invalid_messages() {
        let acc = Account::new("a".to_string(), "b".to_string());
        let handler = PrintLadder::new(&acc);

        assert!(!handler.can_handle("who's on top of ping pong ladder?"));
    }
}
<commit_msg>fix tests<commit_after>extern crate startuppong;
extern crate regex;

use std::io::Write;
use std::str;

use regex::Regex;

pub use startuppong::account_from_env;

use handler::MessageHandler;
use handler::HandlerResult;
use handler::HandlerError;
use message::IncomingMessage;

pub type Account = startuppong::Account;

/// Startuppong.com get_players handler
///
/// Messages requesting to "show ping pong" or "list ping pong" will result in a dump
/// of the ladder, 1 line per player, to the requester.
pub struct PrintLadder {
    account: Account,
    regex: Regex,
    max_entries: usize
}

impl PrintLadder {
    /// Create the PrintLadder handler.
    ///
    /// Requires a startuppong::Account. You will need to register on startuppong.com if you wish to
    /// use this handler.
    pub fn new(account: Account, max_entries: usize) -> PrintLadder {
        PrintLadder {
            account: account,
            regex: regex!(r"(print|list|show).+ping ?pong"),
            max_entries: max_entries
        }
    }
}

impl MessageHandler for PrintLadder {
    fn name(&self) -> &str {
        "PrintLadder"
    }

    fn re(&self) -> &Regex {
        &self.regex
    }

    fn handle(&self, incoming: &IncomingMessage) -> HandlerResult {
        let res = try!(startuppong::get_players(&self.account));
        let players = res.players();
        let mut reply = Vec::new();

        let len = if players.len() < self.max_entries {
            players.len()
        } else {
            self.max_entries
        };

        for i in 0..len {
            try!(write!(&mut reply, "{} - {}\n", players[i].rank, players[i].name));
        }

        Ok(try!(incoming.reply(str::from_utf8(&reply).unwrap().to_string())))
    }
}

impl From<startuppong::error::ApiError> for HandlerError {
    fn from(err: startuppong::error::ApiError) -> HandlerError {
        HandlerError::Other(Box::new(err))
    }
}

#[cfg(test)]
mod tests {
    use startuppong::Account;

    use handler::MessageHandler;
    use super::PrintLadder;

    #[test]
    fn check_valid_messages() {
        let acc = Account::new("a".to_string(), "b".to_string());
        let handler = PrintLadder::new(acc, 10);

        assert!(handler.can_handle("print the pingpong ladder"));
        assert!(handler.can_handle("list the pingpong ladder"));
        assert!(handler.can_handle("show the pingpong ladder"));
        assert!(handler.can_handle("print the ping pong ladder"));
        assert!(handler.can_handle("list the ping pong ladder"));
        assert!(handler.can_handle("show the ping pong ladder"));
    }

    #[test]
    fn check_invalid_messages() {
        let acc = Account::new("a".to_string(), "b".to_string());
        let handler = PrintLadder::new(acc, 10);

        assert!(!handler.can_handle("who's on top of ping pong ladder?"));
    }
}
<|endoftext|>


<commit_before>use super::connect::DEFAULT_DB;
use crate::cmd::{Durability, ReadMode};
use crate::proto::Payload;
use crate::{err, Connection, Query, Result};
use async_stream::try_stream;
use futures::channel::mpsc::{self, UnboundedReceiver};
use futures::io::{AsyncReadExt, AsyncWriteExt};
use futures::join;
use futures::stream::{Stream, StreamExt};
use log::trace;
use ql2::query::QueryType;
use ql2::response::{ErrorType, ResponseType};
use ql2::Frame;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::str;
use std::sync::atomic::Ordering;

const DATA_SIZE: usize = 4;
const TOKEN_SIZE: usize = 8;
const HEADER_SIZE: usize = DATA_SIZE + TOKEN_SIZE;

#[derive(Deserialize, Debug)]
pub(crate) struct Response {
    t: i32,
    e: Option<i32>,
    r: Value,
    b: Option<Vec<Frame>>,
    p: Option<Value>,
    n: Option<Vec<i32>>,
}

#[derive(Debug, Clone, Copy, Serialize, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[non_exhaustive]
pub struct Options<'a> {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub read_mode: Option<ReadMode>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub time_format: Option<Format>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub durability: Option<Durability>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub group_format: Option<Format>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub db: Option<Db<'a>>,
}

impl<'a> Options<'a> {
    pub fn new() -> Self {
        Default::default()
    }

    pub const fn db(mut self, db: &'a str) -> Self {
        self.db = Some(Db(db));
        self
    }
}

#[derive(Debug, Clone, Copy, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[non_exhaustive]
#[serde(rename_all = "lowercase")]
pub enum Format {
    Native,
    Raw,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Db<'a>(pub &'a str);

pub trait Arg<'a> {
    fn into(self) -> (&'a Connection<'a>, Options<'a>);
}

impl<'a> Arg<'a> for &'a Connection<'a> {
    fn into(self) -> (&'a Connection<'a>, Options<'a>) {
        let opts = if self.db == DEFAULT_DB {
            Options::new()
        } else {
            Options::new().db(self.db.as_ref())
        };
        (self, opts)
    }
}

impl<'a> Arg<'a> for (&'a Connection<'a>, Options<'a>) {
    fn into(self) -> (&'a Connection<'a>, Options<'a>) {
        let (conn, options) = self;
        let conn_db = conn.db.as_ref();
        let opts = if options.db.is_none() && conn_db != DEFAULT_DB {
            options.db(conn_db)
        } else {
            options
        };
        (conn, opts)
    }
}

pub(crate) fn new<'a, A, T>(query: Query, arg: A) -> impl Stream<Item = Result<T>>
where
    A: Arg<'a>,
    T: Unpin + DeserializeOwned,
{
    try_stream! {
        let (conn, opts) = arg.into();
        conn.broken()?;
        conn.change_feed()?;
        if query.change_feed() {
            conn.mark_change_feed();
        }
        let token = conn.token();
        let (tx, mut rx) = mpsc::unbounded();
        conn.channels.insert(token, tx);
        let mut payload = Payload(QueryType::Start, Some(query), opts);
        loop {
            let (response_type, resp) = conn.request(token, &payload, &mut rx).await?;
            trace!("yielding response; token: {}, response: {}", token, resp.r);
            match response_type {
                ResponseType::SuccessAtom | ResponseType::SuccessSequence | ResponseType::ServerInfo => {
                    for val in serde_json::from_value::<Vec<T>>(resp.r)? {
                        yield val;
                    }
                    break;
                }
                ResponseType::SuccessPartial => {
                    payload = Payload(QueryType::Continue, None, Default::default());
                    for val in serde_json::from_value::<Vec<T>>(resp.r)? {
                        yield val;
                    }
                    continue;
                }
                // TODO what whould we yield here?
                ResponseType::WaitComplete => { break; }
                typ => {
                    Err(response_error(typ, resp.e, resp))?;
                    break;
                }
            }
        }
        rx.close();
        conn.channels.remove(&token);
        conn.unmark_change_feed();
    }
}

impl<'a> Connection<'a> {
    fn token(&self) -> u64 {
        let token = self
            .token
            .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1))
            .unwrap();
        if token == u64::MAX {
            self.mark_broken();
        }
        token
    }

    fn send_response(&self, db_token: u64, resp: Result<(ResponseType, Response)>) {
        if let Some(tx) = self.channels.get(&db_token) {
            if let Err(error) = tx.unbounded_send(resp) {
                if error.is_disconnected() {
                    self.channels.remove(&db_token);
                }
            }
        }
    }

    async fn request(
        &'a self,
        token: u64,
        query: &Payload<'_>,
        rx: &mut UnboundedReceiver<Result<(ResponseType, Response)>>,
    ) -> Result<(ResponseType, Response)> {
        let (_, result) = join!(self.submit(token, query), rx.next());
        match result {
            Some(resp) => resp,
            None => {
                Err(err::Client::Other("sender stream terminated prematurely".to_owned()).into())
            }
        }
    }

    async fn submit(&'a self, token: u64, query: &Payload<'_>) {
        let mut db_token = token;
        let result = self.exec(token, query, &mut db_token).await;
        self.send_response(db_token, result);
    }

    async fn exec(
        &'a self,
        token: u64,
        query: &Payload<'_>,
        db_token: &mut u64,
    ) -> Result<(ResponseType, Response)> {
        let bytes = query.to_bytes()?;
        let data_len = bytes.len();
        let mut buf = Vec::with_capacity(HEADER_SIZE + data_len);
        buf.extend_from_slice(&token.to_le_bytes());
        buf.extend_from_slice(&(data_len as u32).to_le_bytes());
        buf.extend_from_slice(&bytes);

        let mut stream = self.stream.access().await.clone();

        trace!("sending query; token: {}, payload: {}", token, query);
        stream.write_all(&buf).await?;
        trace!("query sent; token: {}", token);

        trace!("reading header; token: {}", token);
        let mut header = [0u8; HEADER_SIZE];
        stream.read_exact(&mut header).await?;

        let mut buf = [0u8; TOKEN_SIZE];
        buf.copy_from_slice(&header[..TOKEN_SIZE]);
        *db_token = u64::from_le_bytes(buf);

        let mut buf = [0u8; DATA_SIZE];
        buf.copy_from_slice(&header[TOKEN_SIZE..]);
        let len = u32::from_le_bytes(buf) as usize;
        trace!(
            "header read; token: {}, db_token: {}, response_len: {}",
            token,
            db_token,
            len
        );

        trace!("reading body; token: {}", token);
        let mut buf = vec![0u8; len];
        stream.read_exact(&mut buf).await?;

        trace!(
            "body read; token: {}, db_token: {}, body: {}",
            token,
            db_token,
            super::debug(&buf),
        );

        let resp = serde_json::from_slice::<Response>(&buf)?;
        trace!(
            "response successfully parsed; token: {}, response: {}",
            token,
            resp.r
        );

        let response_type = ResponseType::from_i32(resp.t)
            .ok_or_else(|| err::Client::Other(format!("uknown response type `{}`", resp.t)))?;

        if let Some(error_type) = resp.e {
            return Err(response_error(response_type, Some(error_type), resp));
        }

        Ok((response_type, resp))
    }
}

fn response_error(
    response_type: ResponseType,
    error_type: Option<i32>,
    resp: Response,
) -> err::Error {
    let msg = match serde_json::from_value::<Vec<String>>(resp.r) {
        Ok(messages) => messages.join(" "),
        Err(error) => {
            return error.into();
        }
    };
    match response_type {
        ResponseType::ClientError => err::Client::Other(msg).into(),
        ResponseType::CompileError => err::Error::Compile(msg),
        ResponseType::RuntimeError => match error_type
            .map(ErrorType::from_i32)
            .ok_or_else(|| err::Client::Other(format!("unexpected runtime error: {}", msg)))
        {
            Ok(Some(ErrorType::Internal)) => err::Runtime::Internal(msg).into(),
            Ok(Some(ErrorType::ResourceLimit)) => err::Runtime::ResourceLimit(msg).into(),
            Ok(Some(ErrorType::QueryLogic)) => err::Runtime::QueryLogic(msg).into(),
            Ok(Some(ErrorType::NonExistence)) => err::Runtime::NonExistence(msg).into(),
            Ok(Some(ErrorType::OpFailed)) => err::Availability::OpFailed(msg).into(),
            Ok(Some(ErrorType::OpIndeterminate)) => err::Availability::OpIndeterminate(msg).into(),
            Ok(Some(ErrorType::User)) => err::Runtime::User(msg).into(),
            Ok(Some(ErrorType::PermissionError)) => err::Runtime::Permission(msg).into(),
            Err(error) => error.into(),
            _ => err::Client::Other(format!("unexpected runtime error: {}", msg)).into(),
        },
        _ => err::Client::Other(format!("unexpected response: {}", msg)).into(),
    }
}
<commit_msg>validate token from database<commit_after>use super::connect::DEFAULT_DB;
use crate::cmd::{Durability, ReadMode};
use crate::proto::Payload;
use crate::{err, Connection, Query, Result};
use async_stream::try_stream;
use futures::channel::mpsc::{self, UnboundedReceiver};
use futures::io::{AsyncReadExt, AsyncWriteExt};
use futures::join;
use futures::stream::{Stream, StreamExt};
use log::trace;
use ql2::query::QueryType;
use ql2::response::{ErrorType, ResponseType};
use ql2::Frame;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::str;
use std::sync::atomic::Ordering;

const DATA_SIZE: usize = 4;
const TOKEN_SIZE: usize = 8;
const HEADER_SIZE: usize = DATA_SIZE + TOKEN_SIZE;

#[derive(Deserialize, Debug)]
pub(crate) struct Response {
    t: i32,
    e: Option<i32>,
    r: Value,
    b: Option<Vec<Frame>>,
    p: Option<Value>,
    n: Option<Vec<i32>>,
}

#[derive(Debug, Clone, Copy, Serialize, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[non_exhaustive]
pub struct Options<'a> {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub read_mode: Option<ReadMode>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub time_format: Option<Format>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub durability: Option<Durability>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub group_format: Option<Format>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub db: Option<Db<'a>>,
}

impl<'a> Options<'a> {
    pub fn new() -> Self {
        Default::default()
    }

    pub const fn db(mut self, db: &'a str) -> Self {
        self.db = Some(Db(db));
        self
    }
}

#[derive(Debug, Clone, Copy, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[non_exhaustive]
#[serde(rename_all = "lowercase")]
pub enum Format {
    Native,
    Raw,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Db<'a>(pub &'a str);

pub trait Arg<'a> {
    fn into(self) -> (&'a Connection<'a>, Options<'a>);
}

impl<'a> Arg<'a> for &'a Connection<'a> {
    fn into(self) -> (&'a Connection<'a>, Options<'a>) {
        let opts = if self.db == DEFAULT_DB {
            Options::new()
        } else {
            Options::new().db(self.db.as_ref())
        };
        (self, opts)
    }
}

impl<'a> Arg<'a> for (&'a Connection<'a>, Options<'a>) {
    fn into(self) -> (&'a Connection<'a>, Options<'a>) {
        let (conn, options) = self;
        let conn_db = conn.db.as_ref();
        let opts = if options.db.is_none() && conn_db != DEFAULT_DB {
            options.db(conn_db)
        } else {
            options
        };
        (conn, opts)
    }
}

pub(crate) fn new<'a, A, T>(query: Query, arg: A) -> impl Stream<Item = Result<T>>
where
    A: Arg<'a>,
    T: Unpin + DeserializeOwned,
{
    try_stream! {
        let (conn, opts) = arg.into();
        conn.broken()?;
        conn.change_feed()?;
        if query.change_feed() {
            conn.mark_change_feed();
        }
        let token = conn.token();
        let (tx, mut rx) = mpsc::unbounded();
        conn.channels.insert(token, tx);
        let mut payload = Payload(QueryType::Start, Some(query), opts);
        loop {
            let (response_type, resp) = conn.request(token, &payload, &mut rx).await?;
            trace!("yielding response; token: {}, response: {}", token, resp.r);
            match response_type {
                ResponseType::SuccessAtom | ResponseType::SuccessSequence | ResponseType::ServerInfo => {
                    for val in serde_json::from_value::<Vec<T>>(resp.r)? {
                        yield val;
                    }
                    break;
                }
                ResponseType::SuccessPartial => {
                    payload = Payload(QueryType::Continue, None, Default::default());
                    for val in serde_json::from_value::<Vec<T>>(resp.r)? {
                        yield val;
                    }
                    continue;
                }
                // TODO what whould we yield here?
                ResponseType::WaitComplete => { break; }
                typ => {
                    Err(response_error(typ, resp.e, resp))?;
                    break;
                }
            }
        }
        rx.close();
        conn.channels.remove(&token);
        conn.unmark_change_feed();
    }
}

impl<'a> Connection<'a> {
    fn token(&self) -> u64 {
        let token = self
            .token
            .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1))
            .unwrap();
        if token == u64::MAX {
            self.mark_broken();
        }
        token
    }

    fn send_response(&self, db_token: u64, resp: Result<(ResponseType, Response)>) {
        if let Some(tx) = self.channels.get(&db_token) {
            if let Err(error) = tx.unbounded_send(resp) {
                if error.is_disconnected() {
                    self.channels.remove(&db_token);
                }
            }
        }
    }

    async fn request(
        &'a self,
        token: u64,
        query: &Payload<'_>,
        rx: &mut UnboundedReceiver<Result<(ResponseType, Response)>>,
    ) -> Result<(ResponseType, Response)> {
        let (_, result) = join!(self.submit(token, query), rx.next());
        match result {
            Some(resp) => resp,
            None => {
                Err(err::Client::Other("sender stream terminated prematurely".to_owned()).into())
            }
        }
    }

    async fn submit(&'a self, token: u64, query: &Payload<'_>) {
        let mut db_token = token;
        let result = self.exec(token, query, &mut db_token).await;
        self.send_response(db_token, result);
    }

    async fn exec(
        &'a self,
        token: u64,
        query: &Payload<'_>,
        db_token: &mut u64,
    ) -> Result<(ResponseType, Response)> {
        let bytes = query.to_bytes()?;
        let data_len = bytes.len();
        let mut buf = Vec::with_capacity(HEADER_SIZE + data_len);
        buf.extend_from_slice(&token.to_le_bytes());
        buf.extend_from_slice(&(data_len as u32).to_le_bytes());
        buf.extend_from_slice(&bytes);

        let mut stream = self.stream.access().await.clone();

        trace!("sending query; token: {}, payload: {}", token, query);
        stream.write_all(&buf).await?;
        trace!("query sent; token: {}", token);

        trace!("reading header; token: {}", token);
        let mut header = [0u8; HEADER_SIZE];
        stream.read_exact(&mut header).await?;

        let mut buf = [0u8; TOKEN_SIZE];
        buf.copy_from_slice(&header[..TOKEN_SIZE]);
        *db_token = {
            let token = u64::from_le_bytes(buf);
            trace!("db_token: {}", token);
            if token > self.token.load(Ordering::SeqCst) {
                self.mark_broken();
                return Err(err::Client::ConnectionBroken.into());
            }
            token
        };

        let mut buf = [0u8; DATA_SIZE];
        buf.copy_from_slice(&header[TOKEN_SIZE..]);
        let len = u32::from_le_bytes(buf) as usize;
        trace!(
            "header read; token: {}, db_token: {}, response_len: {}",
            token,
            db_token,
            len
        );

        trace!("reading body; token: {}", token);
        let mut buf = vec![0u8; len];
        stream.read_exact(&mut buf).await?;

        trace!(
            "body read; token: {}, db_token: {}, body: {}",
            token,
            db_token,
            super::debug(&buf),
        );

        let resp = serde_json::from_slice::<Response>(&buf)?;
        trace!(
            "response successfully parsed; token: {}, response: {}",
            token,
            resp.r
        );

        let response_type = ResponseType::from_i32(resp.t)
            .ok_or_else(|| err::Client::Other(format!("uknown response type `{}`", resp.t)))?;

        if let Some(error_type) = resp.e {
            return Err(response_error(response_type, Some(error_type), resp));
        }

        Ok((response_type, resp))
    }
}

fn response_error(
    response_type: ResponseType,
    error_type: Option<i32>,
    resp: Response,
) -> err::Error {
    let msg = match serde_json::from_value::<Vec<String>>(resp.r) {
        Ok(messages) => messages.join(" "),
        Err(error) => {
            return error.into();
        }
    };
    match response_type {
        ResponseType::ClientError => err::Client::Other(msg).into(),
        ResponseType::CompileError => err::Error::Compile(msg),
        ResponseType::RuntimeError => match error_type
            .map(ErrorType::from_i32)
            .ok_or_else(|| err::Client::Other(format!("unexpected runtime error: {}", msg)))
        {
            Ok(Some(ErrorType::Internal)) => err::Runtime::Internal(msg).into(),
            Ok(Some(ErrorType::ResourceLimit)) => err::Runtime::ResourceLimit(msg).into(),
            Ok(Some(ErrorType::QueryLogic)) => err::Runtime::QueryLogic(msg).into(),
            Ok(Some(ErrorType::NonExistence)) => err::Runtime::NonExistence(msg).into(),
            Ok(Some(ErrorType::OpFailed)) => err::Availability::OpFailed(msg).into(),
            Ok(Some(ErrorType::OpIndeterminate)) => err::Availability::OpIndeterminate(msg).into(),
            Ok(Some(ErrorType::User)) => err::Runtime::User(msg).into(),
            Ok(Some(ErrorType::PermissionError)) => err::Runtime::Permission(msg).into(),
            Err(error) => error.into(),
            _ => err::Client::Other(format!("unexpected runtime error: {}", msg)).into(),
        },
        _ => err::Client::Other(format!("unexpected response: {}", msg)).into(),
    }
}
<|endoftext|>


<commit_before>use std::hash::{Hash, Hasher, SipHasher};
use std::borrow::Borrow;
use std::mem;

pub mod linear_probing;

struct Node<K, V> {
    key: K,
    val: V,
    next: Option<Box<Node<K, V>>>
}

fn delete<K: PartialEq, V>(x: Option<Box<Node<K, V>>> , key: &K) -> Option<Box<Node<K, V>>> {
    let mut x = x;
    if x.is_none() {
        None
    } else if x.as_ref().unwrap().key.eq(key) {
        let next = x.as_mut().unwrap().next.take();
        mem::replace(&mut x, None);
        next
    } else {
        let next = x.as_mut().unwrap().next.take();
        x.as_mut().unwrap().next = delete(next, key);
        x
    }
}

pub struct SeparateChainingHashST<K, V> {
    st: Vec<Option<Box<Node<K, V>>>>
}

const M: usize = 97;

impl<K: Hash + PartialEq, V> SeparateChainingHashST<K, V> {
    pub fn new() -> SeparateChainingHashST<K, V> {
        let mut st = Vec::with_capacity(M);
        for _ in 0 .. M {
            st.push(None);
        }
        SeparateChainingHashST {
            st: st
        }
    }

    fn hash(key: &K) -> usize {
        let mut hasher = SipHasher::new();
        key.hash(&mut hasher);
        hasher.finish() as usize % M
    }

    pub fn get<T: Borrow<K>>(&self, key: T) -> Option<&V> {
        let key = key.borrow();
        let i = Self::hash(key);
        let mut x = self.st[i].as_ref();
        while x.is_some() {
            if *key == x.unwrap().key {
                return Some(&x.unwrap().val)
            }
            x = x.unwrap().next.as_ref();
        }
        None
    }

    pub fn put(&mut self, key: K, val: V) {
        let i = Self::hash(&key);
        {
            let mut x = self.st[i].as_mut();
            while x.is_some() {
                if key.eq(&x.as_ref().unwrap().key) {
                    x.unwrap().val = val;
                    return;
                } else {
                    x = x.unwrap().next.as_mut();
                }
            }
        }
        let old = self.st[i].take();
        self.st[i] = Some(Box::new(Node { key: key, val: val, next: old }))
    }

    pub fn delete(&mut self, key: &K) {
        let i = Self::hash(&key);
        let next = self.st[i].take();
        self.st[i] = delete(next, key);
    }
}

#[test]
fn test_separate_chaining_st() {
    let mut m = SeparateChainingHashST::new();
    m.put("Name", "Feather");
    m.put("Age", "25");
    m.put("Address", "Beijing");

    assert_eq!(m.get("Age"), Some(&"25"));
    assert_eq!(m.get("Gender"), None);

    m.delete(&"Age");
    assert_eq!(m.get("Age"), None);
}
<commit_msg>hash_tables: implement size() for SeparateChainingHashST<commit_after>use std::hash::{Hash, Hasher, SipHasher};
use std::borrow::Borrow;
use std::mem;

pub mod linear_probing;

struct Node<K, V> {
    key: K,
    val: V,
    next: Option<Box<Node<K, V>>>
}

impl<K, V> Node<K, V> {
    pub fn size(&self) -> usize {
        if self.next.is_none() {
            1
        } else {
            1 + self.next.as_ref().unwrap().size()
        }
    }
}

fn delete<K: PartialEq, V>(x: Option<Box<Node<K, V>>> , key: &K) -> Option<Box<Node<K, V>>> {
    let mut x = x;
    if x.is_none() {
        None
    } else if x.as_ref().unwrap().key.eq(key) {
        let next = x.as_mut().unwrap().next.take();
        mem::replace(&mut x, None);
        next
    } else {
        let next = x.as_mut().unwrap().next.take();
        x.as_mut().unwrap().next = delete(next, key);
        x
    }
}

pub struct SeparateChainingHashST<K, V> {
    st: Vec<Option<Box<Node<K, V>>>>
}

const M: usize = 97;

impl<K: Hash + PartialEq, V> SeparateChainingHashST<K, V> {
    pub fn new() -> SeparateChainingHashST<K, V> {
        let mut st = Vec::with_capacity(M);
        for _ in 0 .. M {
            st.push(None);
        }
        SeparateChainingHashST {
            st: st
        }
    }

    fn hash(key: &K) -> usize {
        let mut hasher = SipHasher::new();
        key.hash(&mut hasher);
        hasher.finish() as usize % M
    }

    pub fn get<T: Borrow<K>>(&self, key: T) -> Option<&V> {
        let key = key.borrow();
        let i = Self::hash(key);
        let mut x = self.st[i].as_ref();
        while x.is_some() {
            if *key == x.unwrap().key {
                return Some(&x.unwrap().val)
            }
            x = x.unwrap().next.as_ref();
        }
        None
    }

    pub fn put(&mut self, key: K, val: V) {
        let i = Self::hash(&key);
        {
            let mut x = self.st[i].as_mut();
            while x.is_some() {
                if key.eq(&x.as_ref().unwrap().key) {
                    x.unwrap().val = val;
                    return;
                } else {
                    x = x.unwrap().next.as_mut();
                }
            }
        }
        let old = self.st[i].take();
        self.st[i] = Some(Box::new(Node { key: key, val: val, next: old }))
    }

    pub fn delete(&mut self, key: &K) {
        let i = Self::hash(&key);
        let next = self.st[i].take();
        self.st[i] = delete(next, key);
    }

    pub fn size(&self) -> usize {
        self.st.iter().filter(|n| n.is_some()).map(|h| h.as_ref().unwrap().size()).sum()
    }
}

#[test]
fn test_separate_chaining_st() {
    let mut m = SeparateChainingHashST::new();
    assert_eq!(m.size(), 0);
    m.put("Name", "Feather");
    m.put("Age", "25");
    m.put("Address", "Beijing");

    assert_eq!(m.size(), 3);
    assert_eq!(m.get("Age"), Some(&"25"));
    assert_eq!(m.get("Gender"), None);

    m.delete(&"Age");
    assert_eq!(m.size(), 2);
    assert_eq!(m.get("Age"), None);
}
<|endoftext|>


<commit_before>//! The module contains the implementation of an HTTP/2 connection.
//!
//! This provides an API to read and write raw HTTP/2 frames.
<commit_msg>Add an `HttpConnection` struct<commit_after>//! The module contains the implementation of an HTTP/2 connection.
//!
//! This provides an API to read and write raw HTTP/2 frames.

use super::transport::TransportStream;
use super::frame::{
    Frame,
    DataFrame,
    HeadersFrame,
    SettingsFrame,
};

/// An enum representing all frame variants that can be returned by an
/// `HttpConnection`.
///
/// The variants wrap the appropriate `Frame` implementation.
#[derive(PartialEq)]
#[derive(Debug)]
pub enum HttpFrame {
    DataFrame(DataFrame),
    HeadersFrame(HeadersFrame),
    SettingsFrame(SettingsFrame),
}

/// The struct implements the HTTP/2 connection level logic.
///
/// It provides an API for writing and reading HTTP/2 frames. It also takes
/// care to validate the received frames.
pub struct HttpConnection<S> where S: TransportStream {
    stream: S,
}

impl<S> HttpConnection<S> where S: TransportStream {
    /// Creates a new `HttpConnection` that will use the given stream as its
    /// underlying transport layer.
    pub fn with_stream(stream: S) -> HttpConnection<S> {
        HttpConnection {
            stream: stream,
        }
    }
 }
<|endoftext|>