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

use protobuf;
use protobuf::compiler_plugin;
use protobuf::descriptor::*;
use protobuf::descriptorx::*;
use protobuf_codegen::code_writer::CodeWriter;

/// Adjust method name to follow the rust's style.
fn snake_name(name: &str) -> String {
    let mut snake_method_name = String::with_capacity(name.len());
    let mut chars = name.chars();
    // initial char can be any char except '_'.
    let mut last_char = '.';
    'outer: while let Some(c) = chars.next() {
        // Please note that '_' is neither uppercase nor lowercase.
        if !c.is_uppercase() {
            last_char = c;
            snake_method_name.push(c);
            continue;
        }
        let mut can_append_underscore = false;
        // check if it's the first char.
        if !snake_method_name.is_empty() && last_char != '_' {
            snake_method_name.push('_');
        }
        last_char = c;
        // find all continous upper case char and append an underscore before
        // last upper case char if neccessary.
        while let Some(c) = chars.next() {
            if !c.is_uppercase() {
                if can_append_underscore && c != '_' {
                    snake_method_name.push('_');
                }
                snake_method_name.extend(last_char.to_lowercase());
                snake_method_name.push(c);
                last_char = c;
                continue 'outer;
            }
            snake_method_name.extend(last_char.to_lowercase());
            last_char = c;
            can_append_underscore = true;
        }
        snake_method_name.extend(last_char.to_lowercase());
    }
    snake_method_name
}

struct MethodGen<'a> {
    proto: &'a MethodDescriptorProto,
    service_path: String,
    root_scope: &'a RootScope<'a>,
}

impl<'a> MethodGen<'a> {
    fn new(
        proto: &'a MethodDescriptorProto,
        service_path: String,
        root_scope: &'a RootScope<'a>,
    ) -> MethodGen<'a> {
        MethodGen {
            proto: proto,
            service_path: service_path,
            root_scope: root_scope,
        }
    }

    fn snake_name(&self) -> String {
        snake_name(self.proto.get_name())
    }

    fn input_message(&self) -> String {
        format!(
            "super::{}",
            self.root_scope
                .find_message(self.proto.get_input_type())
                .rust_fq_name()
        )
    }

    fn output_message(&self) -> String {
        format!(
            "super::{}",
            self.root_scope
                .find_message(self.proto.get_output_type())
                .rust_fq_name()
        )
    }

    fn client_resp_type(&self) -> String {
        match self.proto.get_server_streaming() {
            false => format!("::grpc::SingleResponse<{}>", self.output_message()),
            true => format!("::grpc::StreamingResponse<{}>", self.output_message()),
        }
    }

    fn client_sig(&self) -> String {
        let req_param = match self.proto.get_client_streaming() {
            false => format!(", req: {}", self.input_message()),
            true => format!(""),
        };
        let resp_type = self.client_resp_type();
        let return_type = match self.proto.get_client_streaming() {
            false => resp_type,
            true => format!(
                "impl ::futures::future::Future<Item=(::grpc::ClientRequestSink<{}>, {}), Error=::grpc::Error>",
                self.input_message(),
                resp_type
            ),
        };
        format!(
            "{}(&self, o: ::grpc::RequestOptions{}) -> {}",
            self.snake_name(),
            req_param,
            return_type,
        )
    }

    fn server_req_type(&self) -> String {
        match self.proto.get_client_streaming() {
            false => format!("::grpc::ServerRequestSingle<{}>", self.input_message()),
            true => format!("::grpc::ServerRequest<{}>", self.input_message()),
        }
    }

    fn server_resp_type(&self) -> String {
        match self.proto.get_server_streaming() {
            false => format!("::grpc::ServerResponseUnarySink<{}>", self.output_message()),
            true => format!("::grpc::ServerResponseSink<{}>", self.output_message()),
        }
    }

    fn server_sig(&self) -> String {
        format!(
            "{}(&self, o: ::grpc::ServerHandlerContext, req: {}, resp: {}) -> ::grpc::Result<()>",
            self.snake_name(),
            self.server_req_type(),
            self.server_resp_type(),
        )
    }

    fn write_server_intf(&self, w: &mut CodeWriter) {
        w.fn_def(&self.server_sig())
    }

    fn descriptor_field_name(&self) -> String {
        format!("method_{}", self.proto.get_name())
    }

    fn descriptor_type(&self) -> String {
        format!(
            "::grpc::rt::MethodDescriptor<{}, {}>",
            self.input_message(),
            self.output_message()
        )
    }

    fn streaming_upper(&self) -> &'static str {
        match (
            self.proto.get_client_streaming(),
            self.proto.get_server_streaming(),
        ) {
            (false, false) => "Unary",
            (false, true) => "ServerStreaming",
            (true, false) => "ClientStreaming",
            (true, true) => "Bidi",
        }
    }

    fn streaming_lower(&self) -> &'static str {
        match (
            self.proto.get_client_streaming(),
            self.proto.get_server_streaming(),
        ) {
            (false, false) => "unary",
            (false, true) => "server_streaming",
            (true, false) => "client_streaming",
            (true, true) => "bidi",
        }
    }

    fn write_client(&self, w: &mut CodeWriter) {
        w.pub_fn(&self.client_sig(), |w| {
            let req = match self.proto.get_client_streaming() {
                false => ", req",
                true => "",
            };
            w.write_line(&format!(
                "self.grpc_client.call_{}(o{}, self.{}.clone())",
                self.streaming_lower(),
                req,
                self.descriptor_field_name()
            ))
        });
    }

    fn write_descriptor(&self, w: &mut CodeWriter, before: &str, after: &str) {
        w.block(
            &format!("{}{}", before, "::grpc::rt::MethodDescriptor {"),
            &format!("{}{}", "}", after),
            |w| {
                w.field_entry(
                    "name",
                    &format!(
                        "\"{}/{}\".to_string()",
                        self.service_path,
                        self.proto.get_name()
                    ),
                );
                w.field_entry(
                    "streaming",
                    &format!("::grpc::rt::GrpcStreaming::{}", self.streaming_upper()),
                );
                w.field_entry(
                    "req_marshaller",
                    "::std::sync::Arc::new(::grpc::protobuf::MarshallerProtobuf)",
                );
                w.field_entry(
                    "resp_marshaller",
                    "::std::sync::Arc::new(::grpc::protobuf::MarshallerProtobuf)",
                );
            },
        );
    }
}

struct ServiceGen<'a> {
    proto: &'a ServiceDescriptorProto,
    _root_scope: &'a RootScope<'a>,
    methods: Vec<MethodGen<'a>>,
    service_path: String,
    _package: String,
}

impl<'a> ServiceGen<'a> {
    fn new(
        proto: &'a ServiceDescriptorProto,
        file: &FileDescriptorProto,
        root_scope: &'a RootScope,
    ) -> ServiceGen<'a> {
        let service_path = if file.get_package().is_empty() {
            format!("/{}", proto.get_name())
        } else {
            format!("/{}.{}", file.get_package(), proto.get_name())
        };
        let methods = proto
            .get_method()
            .into_iter()
            .map(|m| MethodGen::new(m, service_path.clone(), root_scope))
            .collect();

        ServiceGen {
            proto: proto,
            _root_scope: root_scope,
            methods: methods,
            service_path: service_path,
            _package: file.get_package().to_string(),
        }
    }

    // trait name
    fn server_intf_name(&self) -> &str {
        self.proto.get_name()
    }

    // client struct name
    fn client_name(&self) -> String {
        format!("{}Client", self.proto.get_name())
    }

    // server struct name
    fn server_name(&self) -> String {
        format!("{}Server", self.proto.get_name())
    }

    fn write_server_intf(&self, w: &mut CodeWriter) {
        w.pub_trait(&self.server_intf_name(), |w| {
            for (i, method) in self.methods.iter().enumerate() {
                if i != 0 {
                    w.write_line("");
                }

                method.write_server_intf(w);
            }
        });
    }

    fn write_client_object(&self, grpc_client: &str, w: &mut CodeWriter) {
        w.expr_block(&self.client_name(), |w| {
            w.field_entry("grpc_client", grpc_client);
            for method in &self.methods {
                method.write_descriptor(
                    w,
                    &format!("{}: ::std::sync::Arc::new(", method.descriptor_field_name()),
                    "),",
                );
            }
        });
    }

    fn write_client(&self, w: &mut CodeWriter) {
        w.pub_struct(&self.client_name(), |w| {
            w.field_decl("grpc_client", "::std::sync::Arc<::grpc::Client>");
            for method in &self.methods {
                w.field_decl(
                    &method.descriptor_field_name(),
                    &format!("::std::sync::Arc<{}>", method.descriptor_type()),
                );
            }
        });

        w.write_line("");

        w.impl_for_block("::grpc::ClientStub", &self.client_name(), |w| {
            let sig = "with_client(grpc_client: ::std::sync::Arc<::grpc::Client>) -> Self";
            w.def_fn(sig, |w| {
                self.write_client_object("grpc_client", w);
            });
        });

        w.write_line("");

        w.impl_self_block(&self.client_name(), |w| {
            for (i, method) in self.methods.iter().enumerate() {
                if i != 0 {
                    w.write_line("");
                }

                method.write_client(w);
            }
        });
    }

    fn write_service_definition(
        &self,
        before: &str,
        after: &str,
        handler: &str,
        w: &mut CodeWriter,
    ) {
        w.block(
            &format!("{}::grpc::rt::ServerServiceDefinition::new(\"{}\",",
                before, self.service_path),
            &format!("){}", after),
            |w| {
                w.block("vec![", "],", |w| {
                    for method in &self.methods {
                        w.block("::grpc::rt::ServerMethod::new(", "),", |w| {
                            method.write_descriptor(w, "::std::sync::Arc::new(", "),");
                            w.block("{", "},", |w| {
                                w.write_line(&format!("let handler_copy = {}.clone();", handler));
                                w.write_line(&format!("::grpc::rt::MethodHandler{}::new(move |ctx, req, resp| handler_copy.{}(ctx, req, resp))",
                                    method.streaming_upper(),
                                    method.snake_name()));
                            });
                        });
                    }
                });
            });
    }

    fn write_server(&self, w: &mut CodeWriter) {
        w.write_line(&format!("pub struct {};", self.server_name()));

        w.write_line("");

        w.write_line("");

        w.impl_self_block(&self.server_name(), |w| {
            w.pub_fn(&format!("new_service_def<H : {} + 'static + Sync + Send + 'static>(handler: H) -> ::grpc::rt::ServerServiceDefinition", self.server_intf_name()), |w| {
                w.write_line("let handler_arc = ::std::sync::Arc::new(handler);");

                self.write_service_definition("", "", "handler_arc", w);
            });
        });
    }

    fn write(&self, w: &mut CodeWriter) {
        w.comment("server interface");
        w.write_line("");
        self.write_server_intf(w);
        w.write_line("");
        w.comment("client");
        w.write_line("");
        self.write_client(w);
        w.write_line("");
        w.comment("server");
        w.write_line("");
        self.write_server(w);
    }
}

fn gen_file(
    file: &FileDescriptorProto,
    root_scope: &RootScope,
) -> Option<compiler_plugin::GenResult> {
    if file.get_service().is_empty() {
        return None;
    }

    let base = protobuf::descriptorx::proto_path_to_rust_mod(file.get_name());

    let mut v = Vec::new();
    {
        let mut w = CodeWriter::new(&mut v);
        w.write_generated();
        w.write_line("");

        for service in file.get_service() {
            w.write_line("");
            ServiceGen::new(service, file, root_scope).write(&mut w);
        }
    }

    Some(compiler_plugin::GenResult {
        name: base + "_grpc.rs",
        content: v,
    })
}

pub fn gen(
    file_descriptors: &[FileDescriptorProto],
    files_to_generate: &[String],
) -> Vec<compiler_plugin::GenResult> {
    let files_map: HashMap<&str, &FileDescriptorProto> =
        file_descriptors.iter().map(|f| (f.get_name(), f)).collect();

    let root_scope = RootScope {
        file_descriptors: file_descriptors,
    };

    let mut results = Vec::new();

    for file_name in files_to_generate {
        let file = files_map[&file_name[..]];

        if file.get_service().is_empty() {
            continue;
        }

        results.extend(gen_file(file, &root_scope).into_iter());
    }

    results
}

pub fn protoc_gen_grpc_rust_main() {
    compiler_plugin::plugin_main(gen);
}

#[cfg(test)]
mod test {
    #[test]
    fn test_snake_name() {
        let cases = vec![
            ("AsyncRequest", "async_request"),
            ("asyncRequest", "async_request"),
            ("async_request", "async_request"),
            ("createID", "create_id"),
            ("CreateIDForReq", "create_id_for_req"),
            ("Create_ID_For_Req", "create_id_for_req"),
            ("ID", "id"),
            ("id", "id"),
        ];

        for (origin, exp) in cases {
            let res = super::snake_name(&origin);
            assert_eq!(res, exp);
        }
    }
}
<commit_msg>Dereference the Arc before calling methods on the interface<commit_after>use std::collections::HashMap;

use protobuf;
use protobuf::compiler_plugin;
use protobuf::descriptor::*;
use protobuf::descriptorx::*;
use protobuf_codegen::code_writer::CodeWriter;

/// Adjust method name to follow the rust's style.
fn snake_name(name: &str) -> String {
    let mut snake_method_name = String::with_capacity(name.len());
    let mut chars = name.chars();
    // initial char can be any char except '_'.
    let mut last_char = '.';
    'outer: while let Some(c) = chars.next() {
        // Please note that '_' is neither uppercase nor lowercase.
        if !c.is_uppercase() {
            last_char = c;
            snake_method_name.push(c);
            continue;
        }
        let mut can_append_underscore = false;
        // check if it's the first char.
        if !snake_method_name.is_empty() && last_char != '_' {
            snake_method_name.push('_');
        }
        last_char = c;
        // find all continous upper case char and append an underscore before
        // last upper case char if neccessary.
        while let Some(c) = chars.next() {
            if !c.is_uppercase() {
                if can_append_underscore && c != '_' {
                    snake_method_name.push('_');
                }
                snake_method_name.extend(last_char.to_lowercase());
                snake_method_name.push(c);
                last_char = c;
                continue 'outer;
            }
            snake_method_name.extend(last_char.to_lowercase());
            last_char = c;
            can_append_underscore = true;
        }
        snake_method_name.extend(last_char.to_lowercase());
    }
    snake_method_name
}

struct MethodGen<'a> {
    proto: &'a MethodDescriptorProto,
    service_path: String,
    root_scope: &'a RootScope<'a>,
}

impl<'a> MethodGen<'a> {
    fn new(
        proto: &'a MethodDescriptorProto,
        service_path: String,
        root_scope: &'a RootScope<'a>,
    ) -> MethodGen<'a> {
        MethodGen {
            proto: proto,
            service_path: service_path,
            root_scope: root_scope,
        }
    }

    fn snake_name(&self) -> String {
        snake_name(self.proto.get_name())
    }

    fn input_message(&self) -> String {
        format!(
            "super::{}",
            self.root_scope
                .find_message(self.proto.get_input_type())
                .rust_fq_name()
        )
    }

    fn output_message(&self) -> String {
        format!(
            "super::{}",
            self.root_scope
                .find_message(self.proto.get_output_type())
                .rust_fq_name()
        )
    }

    fn client_resp_type(&self) -> String {
        match self.proto.get_server_streaming() {
            false => format!("::grpc::SingleResponse<{}>", self.output_message()),
            true => format!("::grpc::StreamingResponse<{}>", self.output_message()),
        }
    }

    fn client_sig(&self) -> String {
        let req_param = match self.proto.get_client_streaming() {
            false => format!(", req: {}", self.input_message()),
            true => format!(""),
        };
        let resp_type = self.client_resp_type();
        let return_type = match self.proto.get_client_streaming() {
            false => resp_type,
            true => format!(
                "impl ::futures::future::Future<Item=(::grpc::ClientRequestSink<{}>, {}), Error=::grpc::Error>",
                self.input_message(),
                resp_type
            ),
        };
        format!(
            "{}(&self, o: ::grpc::RequestOptions{}) -> {}",
            self.snake_name(),
            req_param,
            return_type,
        )
    }

    fn server_req_type(&self) -> String {
        match self.proto.get_client_streaming() {
            false => format!("::grpc::ServerRequestSingle<{}>", self.input_message()),
            true => format!("::grpc::ServerRequest<{}>", self.input_message()),
        }
    }

    fn server_resp_type(&self) -> String {
        match self.proto.get_server_streaming() {
            false => format!("::grpc::ServerResponseUnarySink<{}>", self.output_message()),
            true => format!("::grpc::ServerResponseSink<{}>", self.output_message()),
        }
    }

    fn server_sig(&self) -> String {
        format!(
            "{}(&self, o: ::grpc::ServerHandlerContext, req: {}, resp: {}) -> ::grpc::Result<()>",
            self.snake_name(),
            self.server_req_type(),
            self.server_resp_type(),
        )
    }

    fn write_server_intf(&self, w: &mut CodeWriter) {
        w.fn_def(&self.server_sig())
    }

    fn descriptor_field_name(&self) -> String {
        format!("method_{}", self.proto.get_name())
    }

    fn descriptor_type(&self) -> String {
        format!(
            "::grpc::rt::MethodDescriptor<{}, {}>",
            self.input_message(),
            self.output_message()
        )
    }

    fn streaming_upper(&self) -> &'static str {
        match (
            self.proto.get_client_streaming(),
            self.proto.get_server_streaming(),
        ) {
            (false, false) => "Unary",
            (false, true) => "ServerStreaming",
            (true, false) => "ClientStreaming",
            (true, true) => "Bidi",
        }
    }

    fn streaming_lower(&self) -> &'static str {
        match (
            self.proto.get_client_streaming(),
            self.proto.get_server_streaming(),
        ) {
            (false, false) => "unary",
            (false, true) => "server_streaming",
            (true, false) => "client_streaming",
            (true, true) => "bidi",
        }
    }

    fn write_client(&self, w: &mut CodeWriter) {
        w.pub_fn(&self.client_sig(), |w| {
            let req = match self.proto.get_client_streaming() {
                false => ", req",
                true => "",
            };
            w.write_line(&format!(
                "self.grpc_client.call_{}(o{}, self.{}.clone())",
                self.streaming_lower(),
                req,
                self.descriptor_field_name()
            ))
        });
    }

    fn write_descriptor(&self, w: &mut CodeWriter, before: &str, after: &str) {
        w.block(
            &format!("{}{}", before, "::grpc::rt::MethodDescriptor {"),
            &format!("{}{}", "}", after),
            |w| {
                w.field_entry(
                    "name",
                    &format!(
                        "\"{}/{}\".to_string()",
                        self.service_path,
                        self.proto.get_name()
                    ),
                );
                w.field_entry(
                    "streaming",
                    &format!("::grpc::rt::GrpcStreaming::{}", self.streaming_upper()),
                );
                w.field_entry(
                    "req_marshaller",
                    "::std::sync::Arc::new(::grpc::protobuf::MarshallerProtobuf)",
                );
                w.field_entry(
                    "resp_marshaller",
                    "::std::sync::Arc::new(::grpc::protobuf::MarshallerProtobuf)",
                );
            },
        );
    }
}

struct ServiceGen<'a> {
    proto: &'a ServiceDescriptorProto,
    _root_scope: &'a RootScope<'a>,
    methods: Vec<MethodGen<'a>>,
    service_path: String,
    _package: String,
}

impl<'a> ServiceGen<'a> {
    fn new(
        proto: &'a ServiceDescriptorProto,
        file: &FileDescriptorProto,
        root_scope: &'a RootScope,
    ) -> ServiceGen<'a> {
        let service_path = if file.get_package().is_empty() {
            format!("/{}", proto.get_name())
        } else {
            format!("/{}.{}", file.get_package(), proto.get_name())
        };
        let methods = proto
            .get_method()
            .into_iter()
            .map(|m| MethodGen::new(m, service_path.clone(), root_scope))
            .collect();

        ServiceGen {
            proto: proto,
            _root_scope: root_scope,
            methods: methods,
            service_path: service_path,
            _package: file.get_package().to_string(),
        }
    }

    // trait name
    fn server_intf_name(&self) -> &str {
        self.proto.get_name()
    }

    // client struct name
    fn client_name(&self) -> String {
        format!("{}Client", self.proto.get_name())
    }

    // server struct name
    fn server_name(&self) -> String {
        format!("{}Server", self.proto.get_name())
    }

    fn write_server_intf(&self, w: &mut CodeWriter) {
        w.pub_trait(&self.server_intf_name(), |w| {
            for (i, method) in self.methods.iter().enumerate() {
                if i != 0 {
                    w.write_line("");
                }

                method.write_server_intf(w);
            }
        });
    }

    fn write_client_object(&self, grpc_client: &str, w: &mut CodeWriter) {
        w.expr_block(&self.client_name(), |w| {
            w.field_entry("grpc_client", grpc_client);
            for method in &self.methods {
                method.write_descriptor(
                    w,
                    &format!("{}: ::std::sync::Arc::new(", method.descriptor_field_name()),
                    "),",
                );
            }
        });
    }

    fn write_client(&self, w: &mut CodeWriter) {
        w.pub_struct(&self.client_name(), |w| {
            w.field_decl("grpc_client", "::std::sync::Arc<::grpc::Client>");
            for method in &self.methods {
                w.field_decl(
                    &method.descriptor_field_name(),
                    &format!("::std::sync::Arc<{}>", method.descriptor_type()),
                );
            }
        });

        w.write_line("");

        w.impl_for_block("::grpc::ClientStub", &self.client_name(), |w| {
            let sig = "with_client(grpc_client: ::std::sync::Arc<::grpc::Client>) -> Self";
            w.def_fn(sig, |w| {
                self.write_client_object("grpc_client", w);
            });
        });

        w.write_line("");

        w.impl_self_block(&self.client_name(), |w| {
            for (i, method) in self.methods.iter().enumerate() {
                if i != 0 {
                    w.write_line("");
                }

                method.write_client(w);
            }
        });
    }

    fn write_service_definition(
        &self,
        before: &str,
        after: &str,
        handler: &str,
        w: &mut CodeWriter,
    ) {
        w.block(
            &format!("{}::grpc::rt::ServerServiceDefinition::new(\"{}\",",
                before, self.service_path),
            &format!("){}", after),
            |w| {
                w.block("vec![", "],", |w| {
                    for method in &self.methods {
                        w.block("::grpc::rt::ServerMethod::new(", "),", |w| {
                            method.write_descriptor(w, "::std::sync::Arc::new(", "),");
                            w.block("{", "},", |w| {
                                w.write_line(&format!("let handler_copy = {}.clone();", handler));
                                w.write_line(&format!("::grpc::rt::MethodHandler{}::new(move |ctx, req, resp| (*handler_copy).{}(ctx, req, resp))",
                                    method.streaming_upper(),
                                    method.snake_name()));
                            });
                        });
                    }
                });
            });
    }

    fn write_server(&self, w: &mut CodeWriter) {
        w.write_line(&format!("pub struct {};", self.server_name()));

        w.write_line("");

        w.write_line("");

        w.impl_self_block(&self.server_name(), |w| {
            w.pub_fn(&format!("new_service_def<H : {} + 'static + Sync + Send + 'static>(handler: H) -> ::grpc::rt::ServerServiceDefinition", self.server_intf_name()), |w| {
                w.write_line("let handler_arc = ::std::sync::Arc::new(handler);");

                self.write_service_definition("", "", "handler_arc", w);
            });
        });
    }

    fn write(&self, w: &mut CodeWriter) {
        w.comment("server interface");
        w.write_line("");
        self.write_server_intf(w);
        w.write_line("");
        w.comment("client");
        w.write_line("");
        self.write_client(w);
        w.write_line("");
        w.comment("server");
        w.write_line("");
        self.write_server(w);
    }
}

fn gen_file(
    file: &FileDescriptorProto,
    root_scope: &RootScope,
) -> Option<compiler_plugin::GenResult> {
    if file.get_service().is_empty() {
        return None;
    }

    let base = protobuf::descriptorx::proto_path_to_rust_mod(file.get_name());

    let mut v = Vec::new();
    {
        let mut w = CodeWriter::new(&mut v);
        w.write_generated();
        w.write_line("");

        for service in file.get_service() {
            w.write_line("");
            ServiceGen::new(service, file, root_scope).write(&mut w);
        }
    }

    Some(compiler_plugin::GenResult {
        name: base + "_grpc.rs",
        content: v,
    })
}

pub fn gen(
    file_descriptors: &[FileDescriptorProto],
    files_to_generate: &[String],
) -> Vec<compiler_plugin::GenResult> {
    let files_map: HashMap<&str, &FileDescriptorProto> =
        file_descriptors.iter().map(|f| (f.get_name(), f)).collect();

    let root_scope = RootScope {
        file_descriptors: file_descriptors,
    };

    let mut results = Vec::new();

    for file_name in files_to_generate {
        let file = files_map[&file_name[..]];

        if file.get_service().is_empty() {
            continue;
        }

        results.extend(gen_file(file, &root_scope).into_iter());
    }

    results
}

pub fn protoc_gen_grpc_rust_main() {
    compiler_plugin::plugin_main(gen);
}

#[cfg(test)]
mod test {
    #[test]
    fn test_snake_name() {
        let cases = vec![
            ("AsyncRequest", "async_request"),
            ("asyncRequest", "async_request"),
            ("async_request", "async_request"),
            ("createID", "create_id"),
            ("CreateIDForReq", "create_id_for_req"),
            ("Create_ID_For_Req", "create_id_for_req"),
            ("ID", "id"),
            ("id", "id"),
        ];

        for (origin, exp) in cases {
            let res = super::snake_name(&origin);
            assert_eq!(res, exp);
        }
    }
}
<|endoftext|>


<commit_before>//! The `parser` module contains a lot of useful functionality
//! to parse tokens from the lexer (and creating the parsetree
//! and the ast)
//! its an predictiv parser for a LL(1) grammar
//! for more info about the parser: look in the Compiler Dragonbook,
//! Chapter 4.4.4, "Nonrecursive Predictive Parsing"

use frontend::lexer::Token;
use frontend::ast;
use frontend::parsetree::{ParseTree, PNode};
use self::NonTerminalType::*;
use frontend::lexer::Token::{TokPassageName, TokText, TokNewLine, TokFormatItalicStart, TokFormatItalicEnd, TokFormatBoldStart, TokFormatBoldEnd};

/*

----------------------------------------
Grammatik:

LL(1)
------------------------------------------------------------+-----------------------------------
S -> Passage S2                                             |
S2 -> S                                                     |
S2 -> ɛ                                                     |
Passage -> PassageName PassageContent                       | "add passage (name)", simple
PassageContent -> TextPassage PassageContent                | add text as child
PassageContent -> Formatting PassageContent                 |
PassageContent -> ɛ                                         |
Formating -> BoldFormatting                                 |
Formating -> ItalicFormatting                               |
BoldFormatting -> FormatBold BoldContent FormatBold         | add child bold
BoldContent -> TextPassage BoldContent                      | add text as child
BoldContent -> FormatItalic BoldItalicContent FormatItalic  | add child italic
BoldContent -> ɛ                                            |
ItalicFormatting -> FormatItalic ItalicContent FormatItalic | add child italic
ItalicContent -> TextPassage ItalicContent                  | add text as child
ItalicContent -> FormatBold BoldItalicContent FormatBold    | add child bold
ItalicContent -> ɛ                                          | add text as child
BoldItalicContent -> TextPassage                            |
------------------------------------------------------------+-----------------------------------

::Start
Hello World, ''Yeah''.
//Italic// is possible too.

*/

pub fn parse_tokens(tokens: Vec<Token>) -> ast::AST {
    let mut parser: Parser = Parser::new(tokens);
    parser.parsing();
    parser.ast
}

//==============================
// grammar

#[derive(Debug, Copy, Clone)]
pub enum NonTerminalType {
    S,
    S2,
    Passage,
    PassageContent,
    Formating,
    BoldFormatting,
    ItalicFormatting,
    BoldContent,
    ItalicContent,
    BoldItalicContent
}

//==============================
// parser

struct Parser {
    tree: ParseTree,
    ast: ast::AST,
    stack: Stack,
    ast_path: Vec<usize>,
    tokens: Vec<Token>,
    lookahead: usize
}

impl Parser {
    pub fn new(tokens: Vec<Token>) -> Parser {
        Parser {
            tree: ParseTree::new(),
            ast: ast::AST::new(),
            stack: Stack::new(),
            ast_path: Vec::new(),
            tokens: tokens,
            lookahead: 0
        }
    }

    /// the predictive stack ll(1) parsing routine
    pub fn parsing(&mut self) {
        self.stack.push_start();

        while let Some(top) = self.stack.pop() {
            if self.tree.is_terminal(top.to_vec()) {
                self.next_token();
            } else {
                self.apply_grammar(top.to_vec());
            }
        }

        self.tree.print();
    }

    /// apply the ll(1) grammar
    /// the match-statement simulates the parsing-table behavior
    ///
    /// it creates the parse tree (from the ll(1) grammar)
    /// and the ast from the sdd
    fn apply_grammar(&mut self, top_path: Vec<usize>) {
        if let Some(token) = self.tokens.get_mut(self.lookahead) {

            let to_add_path: Vec<usize> = top_path.to_vec();

            // the frst item in the tuple is the current state and
            // the snd is the current lookup-token
            let state_first: (NonTerminalType, &Token) = (self.tree.get_non_terminal(top_path).clone(), token);

            let mut new_nodes = Vec::new();

            //println!("match {:?}", state_first);
            match state_first {
                (S, &TokPassageName(_)) => {
                    new_nodes.push(PNode::new_non_terminal(Passage));
                    new_nodes.push(PNode::new_non_terminal(S2));
                },
                (S2, &TokPassageName(_)) => {
                    new_nodes.push(PNode::new_non_terminal(S));
                },
                (Passage, &TokPassageName(ref name)) => {
                    let new_token: Token = TokPassageName(name.clone());
                    new_nodes.push(PNode::new_terminal(new_token));
                    new_nodes.push(PNode::new_non_terminal(PassageContent));

                    // ast
                    self.ast_path.clear();
                    let ast_count_passages = self.ast.count_childs(self.ast_path.to_vec());
                    let new_token2: Token = TokPassageName(name.clone());
                    self.ast.add_passage(new_token2);
                    self.ast_path.push(ast_count_passages);
                },
                (PassageContent, &TokText(ref text)) => {
                    let new_token: Token = TokText(text.clone());
                    new_nodes.push(PNode::new_terminal(new_token));
                    new_nodes.push(PNode::new_non_terminal(PassageContent));

                    // ast
                    let new_token2: Token = TokText(text.clone());
                    self.ast.add_child(&self.ast_path, new_token2);
                },
                (PassageContent, &TokNewLine) => {
                    new_nodes.push(PNode::new_terminal(TokNewLine));
                    new_nodes.push(PNode::new_non_terminal(PassageContent));

                    // ast
                    self.ast.add_child(&self.ast_path, TokNewLine);
                },
                (PassageContent, &TokFormatBoldStart) | (PassageContent, &TokFormatItalicStart) => {
                    new_nodes.push(PNode::new_non_terminal(Formating));
                    new_nodes.push(PNode::new_non_terminal(PassageContent));
                },
                (Formating, &TokFormatBoldStart) => {
                    new_nodes.push(PNode::new_non_terminal(BoldFormatting));
                },
                (Formating, &TokFormatItalicStart) => {
                    new_nodes.push(PNode::new_non_terminal(ItalicFormatting));
                },
                (BoldFormatting, &TokFormatBoldStart) => {
                    new_nodes.push(PNode::new_terminal(TokFormatBoldStart));
                    new_nodes.push(PNode::new_non_terminal(BoldContent));
                    new_nodes.push(PNode::new_terminal(TokFormatBoldEnd));

                    // ast
                    let ast_count_passages = self.ast.count_childs(self.ast_path.to_vec());
                    let ast_token: Token = TokFormatBoldStart;
                    self.ast.add_child(&self.ast_path, ast_token);
                    self.ast_path.push(ast_count_passages);
                },
                (ItalicFormatting, &TokFormatItalicStart) => {
                    new_nodes.push(PNode::new_terminal(TokFormatItalicStart));
                    new_nodes.push(PNode::new_non_terminal(ItalicContent));
                    new_nodes.push(PNode::new_terminal(TokFormatItalicEnd));

                    // ast
                    let ast_count_passages = self.ast.count_childs(self.ast_path.to_vec());
                    let ast_token: Token = TokFormatItalicStart;
                    self.ast.add_child(&self.ast_path, ast_token);
                    self.ast_path.push(ast_count_passages);
                },
                (BoldContent, &TokText(ref text)) => {
                    let new_token: Token = TokText(text.clone());
                    new_nodes.push(PNode::new_terminal(new_token));
                    new_nodes.push(PNode::new_non_terminal(BoldContent));

                    // ast
                    let ast_token: Token = TokText(text.clone());
                    self.ast.add_child(&self.ast_path, ast_token);
                },
                (ItalicContent, &TokText(ref text)) => {
                    let new_token: Token = TokText(text.clone());
                    new_nodes.push(PNode::new_terminal(new_token));
                    new_nodes.push(PNode::new_non_terminal(ItalicContent));

                    // ast
                    let ast_token: Token = TokText(text.clone());
                    self.ast.add_child(&self.ast_path, ast_token);
                },
                (BoldContent, &TokFormatItalicStart) => {
                    new_nodes.push(PNode::new_terminal(TokFormatItalicStart));
                    new_nodes.push(PNode::new_non_terminal(BoldItalicContent));
                    new_nodes.push(PNode::new_terminal(TokFormatItalicEnd));
                },
                (ItalicContent, &TokFormatBoldStart) => {
                    new_nodes.push(PNode::new_terminal(TokFormatBoldEnd));
                    new_nodes.push(PNode::new_non_terminal(BoldItalicContent));
                    new_nodes.push(PNode::new_terminal(TokFormatBoldStart));
                },
                (BoldItalicContent, &TokText(ref text)) => {
                    let new_token: Token = TokText(text.clone());
                    new_nodes.push(PNode::new_terminal(new_token));
                },

                (BoldContent, &TokFormatBoldEnd) => {
                    // jump one ast-level higher
                    self.ast_path.pop();
                },
                (ItalicContent, &TokFormatItalicEnd) => {
                    // jump one ast-level higher
                    self.ast_path.pop();
                },
                _ => {

                }
            }

            // adds the new nodes to the tree
            // and adds the path in the tree to the stack
            let length = new_nodes.len().clone();
            self.tree.add_nodes(new_nodes, &to_add_path);
            self.stack.push_path(length as u8, to_add_path);

        } else {
            // no token left
            // only ɛ-productions could be here
            // these productions will be poped of the stack
        }
    }

    /// sets the lookahead to the next token
    fn next_token(&mut self) {
        self.lookahead = self.lookahead + 1;
    }
}

//==============================
// stack of the parser
struct Stack {
    data: Vec<Vec<usize>>
}

impl Stack {
    pub fn new() -> Stack {
        Stack { data: Vec::new() }
    }

    /// pushs the address of the first startsymbol to the stack
    fn push_start(&mut self) {
        self.data.push(vec![]);
    }

    /// save the path of the nodes in the tree to the stack
    /// the right part of the production
    /// should be on the stack in reverse order
    fn push_path(&mut self, count_elements: u8, to_add_path: Vec<usize>) {
        for i in 0..count_elements {
            let mut path: Vec<usize> = to_add_path.to_vec();
            path.push((count_elements-i-1) as usize);
            self.data.push(path);
        }
    }

    fn pop(&mut self) -> Option<Vec<usize>> {
        self.data.pop()
    }
}
<commit_msg>parser support for new ll(1) grammar<commit_after>//! The `parser` module contains a lot of useful functionality
//! to parse tokens from the lexer (and creating the parsetree
//! and the ast)
//! its an predictiv parser for a LL(1) grammar
//! for more info about the parser: look in the Compiler Dragonbook,
//! Chapter 4.4.4, "Nonrecursive Predictive Parsing"

use frontend::lexer::Token;
use frontend::ast;
use frontend::parsetree::{ParseTree, PNode};
use self::NonTerminalType::*;
use frontend::lexer::Token::{TokPassageName, TokText, TokNewLine,
    TokFormatItalicStart, TokFormatItalicEnd, TokFormatBoldStart, TokFormatBoldEnd,
    TokFormatMonoStart, TokFormatMonoEnd, TokPassageLink};

/*

----------------------------------------
Grammatik:

LL(1)
------------------------------------------------------------+-----------------------------------
S -> Passage S2                                             |
S2 -> S                                                     |
S2 -> ɛ                                                     |
Passage -> PassageName PassageContent                       | "add passage (name)", simple
PassageContent -> TextPassage PassageContent                | add text as child
PassageContent -> Formatting PassageContent                 |
PassageContent -> ɛ                                         |
Formating -> BoldFormatting                                 |
Formating -> ItalicFormatting                               |
BoldFormatting -> FormatBold BoldContent FormatBold         | add child bold
BoldContent -> TextPassage BoldContent                      | add text as child
BoldContent -> FormatItalic BoldItalicContent FormatItalic  | add child italic
BoldContent -> ɛ                                            |
ItalicFormatting -> FormatItalic ItalicContent FormatItalic | add child italic
ItalicContent -> TextPassage ItalicContent                  | add text as child
ItalicContent -> FormatBold BoldItalicContent FormatBold    | add child bold
ItalicContent -> ɛ                                          | add text as child
BoldItalicContent -> TextPassage                            |
------------------------------------------------------------+-----------------------------------

::Start
Hello World, ''Yeah''.
//Italic// is possible too.

*/

pub fn parse_tokens(tokens: Vec<Token>) -> ast::AST {
    let mut parser: Parser = Parser::new(tokens);
    parser.parsing();
    parser.ast
}

//==============================
// grammar

#[derive(Debug, Copy, Clone)]
pub enum NonTerminalType {
    S,
    Sf,
    Passage,
    Passagef,
    PassageContentNewline,
    PassageContentNonNewline,
    Formating,
    BoldFormatting,
    ItalicFormatting,
    MonoFormatting,
    MonoContent,
    Link
}

//==============================
// parser

struct Parser {
    tree: ParseTree,
    ast: ast::AST,
    stack: Stack,
    ast_path: Vec<usize>,
    tokens: Vec<Token>,
    lookahead: usize
}

impl Parser {
    pub fn new(tokens: Vec<Token>) -> Parser {
        Parser {
            tree: ParseTree::new(),
            ast: ast::AST::new(),
            stack: Stack::new(),
            ast_path: Vec::new(),
            tokens: tokens,
            lookahead: 0
        }
    }

    /// the predictive stack ll(1) parsing routine
    pub fn parsing(&mut self) {
        self.stack.push_start();

        while let Some(top) = self.stack.pop() {
            if self.tree.is_terminal(top.to_vec()) {
                self.next_token();
            } else {
                self.apply_grammar(top.to_vec());
            }
        }

        self.tree.print();
    }

    /// apply the ll(1) grammar
    /// the match-statement simulates the parsing-table behavior
    ///
    /// it creates the parse tree (from the ll(1) grammar)
    /// and the ast from the sdd
    fn apply_grammar(&mut self, top_path: Vec<usize>) {
        if let Some(token) = self.tokens.get_mut(self.lookahead) {

            let to_add_path: Vec<usize> = top_path.to_vec();

            // the frst item in the tuple is the current state and
            // the snd is the current lookup-token
            let state_first: (NonTerminalType, &Token) = (self.tree.get_non_terminal(top_path).clone(), token);

            let mut new_nodes = Vec::new();

            println!("match {:?}", state_first);
            match state_first {
                (S, &TokPassageName(_)) => {
                    new_nodes.push(PNode::new_non_terminal(Passage));
                    new_nodes.push(PNode::new_non_terminal(Sf));
                },
                (Sf, &TokPassageName(_)) => {
                    new_nodes.push(PNode::new_non_terminal(S));
                },
                (Passage, &TokPassageName(ref name)) => {
                    let new_token: Token = TokPassageName(name.clone());
                    new_nodes.push(PNode::new_terminal(new_token));
                    new_nodes.push(PNode::new_non_terminal(PassageContentNewline));

                    // ast
                    self.ast_path.clear();
                    let ast_count_passages = self.ast.count_childs(self.ast_path.to_vec());
                    let new_token2: Token = TokPassageName(name.clone());
                    self.ast.add_passage(new_token2);
                    self.ast_path.push(ast_count_passages);
                },

                // PassageContentNewline / PassageContentNonNewline
                (PassageContentNewline, &TokText(ref text)) |
                (PassageContentNonNewline, &TokText(ref text)) => {
                    let new_token: Token = TokText(text.clone());
                    new_nodes.push(PNode::new_terminal(new_token));
                    new_nodes.push(PNode::new_non_terminal(PassageContentNonNewline));

                    let new_token2: Token = TokText(text.clone());
                    self.ast.add_child(&self.ast_path, new_token2);
                },
                (PassageContentNewline, &TokFormatBoldStart) |
                (PassageContentNewline, &TokFormatItalicStart) |
                (PassageContentNewline, &TokFormatMonoStart) |
                (PassageContentNonNewline, &TokFormatBoldStart) |
                (PassageContentNonNewline, &TokFormatItalicStart) |
                (PassageContentNonNewline, &TokFormatMonoStart) => {
                    new_nodes.push(PNode::new_non_terminal(Formating));
                    new_nodes.push(PNode::new_non_terminal(PassageContentNonNewline));
                },
                (PassageContentNewline, &TokPassageLink(_, _)) |
                (PassageContentNonNewline, &TokPassageLink(_, _)) => {
                    new_nodes.push(PNode::new_non_terminal(Link));
                    new_nodes.push(PNode::new_non_terminal(PassageContentNewline));
                },
                (PassageContentNewline, &TokNewLine) |
                (PassageContentNonNewline, &TokNewLine) => {
                    new_nodes.push(PNode::new_terminal(TokNewLine));
                    new_nodes.push(PNode::new_non_terminal(PassageContentNewline));

                    // ast
                    self.ast.add_child(&self.ast_path, TokNewLine);
                },
                (PassageContentNonNewline, &TokFormatBoldEnd) |
                (PassageContentNewline, &TokFormatBoldEnd) => {
                    // jump one ast-level higher
                    self.ast_path.pop();
                },
                (PassageContentNonNewline, &TokFormatItalicEnd) |
                (PassageContentNewline, &TokFormatItalicEnd) => {
                    // jump one ast-level higher
                    self.ast_path.pop();
                },

                // Formating
                (Formating, &TokFormatBoldStart) => {
                    new_nodes.push(PNode::new_non_terminal(BoldFormatting));
                },
                (Formating, &TokFormatItalicStart) => {
                    new_nodes.push(PNode::new_non_terminal(ItalicFormatting));
                },
                (Formating, &TokFormatMonoStart) => {
                    new_nodes.push(PNode::new_non_terminal(MonoFormatting));
                },

                // BoldFormatting
                (BoldFormatting, &TokFormatBoldStart) => {
                    new_nodes.push(PNode::new_terminal(TokFormatBoldStart));
                    new_nodes.push(PNode::new_non_terminal(PassageContentNonNewline));
                    new_nodes.push(PNode::new_terminal(TokFormatBoldEnd));

                    //ast
                    let ast_count_passages = self.ast.count_childs(self.ast_path.to_vec());
                    let ast_token: Token = TokFormatBoldStart;
                    self.ast.add_child(&self.ast_path, ast_token);
                    self.ast_path.push(ast_count_passages);
                },

                // ItalicFormatting
                (ItalicFormatting, &TokFormatItalicStart) => {
                    new_nodes.push(PNode::new_terminal(TokFormatItalicStart));
                    new_nodes.push(PNode::new_non_terminal(PassageContentNonNewline));
                    new_nodes.push(PNode::new_terminal(TokFormatItalicEnd));

                    //ast
                    let ast_count_passages = self.ast.count_childs(self.ast_path.to_vec());
                    let ast_token: Token = TokFormatItalicStart;
                    self.ast.add_child(&self.ast_path, ast_token);
                    self.ast_path.push(ast_count_passages);
                },

                // MonoFormatting
                (MonoFormatting, &TokFormatMonoStart) => {
                    new_nodes.push(PNode::new_terminal(TokFormatMonoStart));
                    new_nodes.push(PNode::new_non_terminal(MonoContent));
                    new_nodes.push(PNode::new_terminal(TokFormatMonoEnd));
                },

                // MonoContent
                (MonoContent, &TokText(ref text)) => {
                    let new_token: Token = TokText(text.clone());
                    new_nodes.push(PNode::new_terminal(new_token));
                    new_nodes.push(PNode::new_non_terminal(MonoContent));
                },
                (MonoContent, &TokNewLine) => {
                    new_nodes.push(PNode::new_terminal(TokNewLine));
                    new_nodes.push(PNode::new_non_terminal(MonoContent));
                },

                // Link
                (Link, &TokPassageLink(ref text, ref name)) => {
                    let new_token: Token = TokPassageLink(text.clone(), name.clone());
                    new_nodes.push(PNode::new_terminal(new_token));

                    // ast
                    let new_token2: Token = TokPassageLink(text.clone(), name.clone());
                    self.ast.add_child(&self.ast_path, new_token2);
                },

                _ => {

                }
            }

            // adds the new nodes to the tree
            // and adds the path in the tree to the stack
            let length = new_nodes.len().clone();
            self.tree.add_nodes(new_nodes, &to_add_path);
            self.stack.push_path(length as u8, to_add_path);

        } else {
            // no token left
            // only ɛ-productions could be here
            // these productions will be poped of the stack
        }
    }

    /// sets the lookahead to the next token
    fn next_token(&mut self) {
        self.lookahead = self.lookahead + 1;
    }
}

//==============================
// stack of the parser
struct Stack {
    data: Vec<Vec<usize>>
}

impl Stack {
    pub fn new() -> Stack {
        Stack { data: Vec::new() }
    }

    /// pushs the address of the first startsymbol to the stack
    fn push_start(&mut self) {
        self.data.push(vec![]);
    }

    /// save the path of the nodes in the tree to the stack
    /// the right part of the production
    /// should be on the stack in reverse order
    fn push_path(&mut self, count_elements: u8, to_add_path: Vec<usize>) {
        for i in 0..count_elements {
            let mut path: Vec<usize> = to_add_path.to_vec();
            path.push((count_elements-i-1) as usize);
            self.data.push(path);
        }
    }

    fn pop(&mut self) -> Option<Vec<usize>> {
        self.data.pop()
    }
}
<|endoftext|>


<commit_before>fn main() {
    let u: &[u8] = [49, 50, 51];

    unsafe {
        assert!(u == std::cast::transmute("123"));
    }
}
<commit_msg>unsafe: transmute is now in std::mem<commit_after>fn main() {
    let u: &[u8] = [49, 50, 51];

    unsafe {
        assert!(u == std::mem::transmute("123"));
    }
}
<|endoftext|>


<commit_before>use std::hash::Hash;
use std::collections::{HashMap, HashSet};
use std::cmp::Ordering;
use parking_lot::RwLock;
use bifrost_hasher::hash_str;

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub enum Relation {
    Equal,
    Before,
    After,
    Concurrent
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct VectorClock<S: Hash + Eq + Copy> {
    map: HashMap<S, u64>
}

impl <S: Eq + Copy + Hash> PartialOrd for VectorClock<S> {
    fn partial_cmp(&self, other: &VectorClock<S>) -> Option<Ordering> {
        let rel = self.relation(other);
        match rel {
            Relation::Before => Some(Ordering::Less),
            Relation::After => Some(Ordering::Greater),
            Relation::Equal => Some(Ordering::Equal),
            Relation::Concurrent => None
        }
    }

    fn lt(&self, other: &VectorClock<S>) -> bool {
        self.relation(other) == Relation::Before
    }

    fn le(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::Before || rel == Relation::Equal
    }

    fn gt(&self, other: &VectorClock<S>) -> bool {
        self.relation(other) == Relation::After
    }

    fn ge(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::After || rel == Relation::Equal
    }
}

impl <S: Eq + Copy + Hash> PartialEq for VectorClock<S> {
    fn eq(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::Equal
    }

    fn ne(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        !(rel == Relation::After || rel == Relation::Before)
    }
}

impl <S: Hash + Eq + Copy>VectorClock<S> {
    pub fn new() -> VectorClock<S> {
        VectorClock {
            map: HashMap::new()
        }
    }

    pub fn inc(&mut self, server: S) {
        *self.map.entry(server).or_insert(0) += 1;
    }

    pub fn happened_before(&self, clock_b: &VectorClock<S>) -> bool {
        let mut a_lt_b = false;
        for (server, ai) in self.map.iter() {
            let bi = *clock_b.map.get(server).unwrap_or(&0);
            if *ai > bi {return false;}
            a_lt_b = a_lt_b || *ai < bi;
        }
        for (server, bi) in clock_b.map.iter() {
            let ai = *self.map.get(server).unwrap_or(&0);
            if ai > *bi {return false;}
            a_lt_b = a_lt_b || ai < *bi;
        }
        return a_lt_b;
    }
    pub fn equals(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                if ac != bc {return false;}
            }
        }
        return true;
    }
    pub fn relation(&self, clock_b: &VectorClock<S>) -> Relation {
        if self.equals(clock_b) {
            return Relation::Equal;
        }
        if self.happened_before(clock_b) {
            return Relation::Before;
        }
        if clock_b.happened_before(self) {
            return Relation::After;
        }
        return Relation::Concurrent;
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<S>) {
        // merge_with is used to update counter for other servers (also learn from it)
        for (server, bc) in clock_b.map.iter() {
            let mut ba = self.map.entry(*server).or_insert(0);
            if *ba < *bc {*ba = *bc}
        }
    }
    pub fn learn_from(&mut self, clock_b: &VectorClock<S>) {
        // learn_from only insert missing servers into the clock
        for (server, bc) in clock_b.map.iter() {
            self.map.entry(*server).or_insert(*bc);
        }
    }
}

pub struct ServerVectorClock {
    server: u64,
    clock: RwLock<VectorClock<u64>>
}

impl ServerVectorClock {
    pub fn new(server_address: &String) -> ServerVectorClock {
        ServerVectorClock {
            server: hash_str(server_address),
            clock: RwLock::new(VectorClock::new())
        }
    }
    pub fn inc(&self) {
        let mut clock = self.clock.write();
        clock.inc(self.server)
    }

    pub fn happened_before(&self, clock_b: &VectorClock<u64>) -> bool {
        let clock = self.clock.read();
        clock.happened_before(clock_b)
    }
    pub fn equals(&self, clock_b: &VectorClock<u64>) -> bool {
        let clock = self.clock.read();
        clock.equals(clock_b)
    }
    pub fn relation(&self, clock_b: &VectorClock<u64>) -> Relation {
        let clock = self.clock.read();
        clock.relation(clock_b)
    }
    pub fn merge_with(&self, clock_b: &VectorClock<u64>) {
        let mut clock = self.clock.write();
        clock.merge_with(clock_b)
    }
    pub fn learn_from(&self, clock_b: &VectorClock<u64>) {
        let mut clock = self.clock.write();
        clock.learn_from(clock_b)
    }
    pub fn to_clock(&self) -> VectorClock<u64> {
        let clock = self.clock.read();
        clock.clone()
    }
}

pub type StandardVectorClock = VectorClock<u64>;<commit_msg>return clock on increasement<commit_after>use std::hash::Hash;
use std::collections::{HashMap, HashSet};
use std::cmp::Ordering;
use parking_lot::RwLock;
use bifrost_hasher::hash_str;

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub enum Relation {
    Equal,
    Before,
    After,
    Concurrent
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct VectorClock<S: Hash + Eq + Copy> {
    map: HashMap<S, u64>
}

impl <S: Eq + Copy + Hash> PartialOrd for VectorClock<S> {
    fn partial_cmp(&self, other: &VectorClock<S>) -> Option<Ordering> {
        let rel = self.relation(other);
        match rel {
            Relation::Before => Some(Ordering::Less),
            Relation::After => Some(Ordering::Greater),
            Relation::Equal => Some(Ordering::Equal),
            Relation::Concurrent => None
        }
    }

    fn lt(&self, other: &VectorClock<S>) -> bool {
        self.relation(other) == Relation::Before
    }

    fn le(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::Before || rel == Relation::Equal
    }

    fn gt(&self, other: &VectorClock<S>) -> bool {
        self.relation(other) == Relation::After
    }

    fn ge(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::After || rel == Relation::Equal
    }
}

impl <S: Eq + Copy + Hash> PartialEq for VectorClock<S> {
    fn eq(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::Equal
    }

    fn ne(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        !(rel == Relation::After || rel == Relation::Before)
    }
}

impl <S: Hash + Eq + Copy>VectorClock<S> {
    pub fn new() -> VectorClock<S> {
        VectorClock {
            map: HashMap::new()
        }
    }

    pub fn inc(&mut self, server: S) -> VectorClock<S> {
        *self.map.entry(server).or_insert(0) += 1;
        self.clone()
    }

    pub fn happened_before(&self, clock_b: &VectorClock<S>) -> bool {
        let mut a_lt_b = false;
        for (server, ai) in self.map.iter() {
            let bi = *clock_b.map.get(server).unwrap_or(&0);
            if *ai > bi {return false;}
            a_lt_b = a_lt_b || *ai < bi;
        }
        for (server, bi) in clock_b.map.iter() {
            let ai = *self.map.get(server).unwrap_or(&0);
            if ai > *bi {return false;}
            a_lt_b = a_lt_b || ai < *bi;
        }
        return a_lt_b;
    }
    pub fn equals(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                if ac != bc {return false;}
            }
        }
        return true;
    }
    pub fn relation(&self, clock_b: &VectorClock<S>) -> Relation {
        if self.equals(clock_b) {
            return Relation::Equal;
        }
        if self.happened_before(clock_b) {
            return Relation::Before;
        }
        if clock_b.happened_before(self) {
            return Relation::After;
        }
        return Relation::Concurrent;
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<S>) {
        // merge_with is used to update counter for other servers (also learn from it)
        for (server, bc) in clock_b.map.iter() {
            let mut ba = self.map.entry(*server).or_insert(0);
            if *ba < *bc {*ba = *bc}
        }
    }
    pub fn learn_from(&mut self, clock_b: &VectorClock<S>) {
        // learn_from only insert missing servers into the clock
        for (server, bc) in clock_b.map.iter() {
            self.map.entry(*server).or_insert(*bc);
        }
    }
}

pub struct ServerVectorClock {
    server: u64,
    clock: RwLock<VectorClock<u64>>
}

impl ServerVectorClock {
    pub fn new(server_address: &String) -> ServerVectorClock {
        ServerVectorClock {
            server: hash_str(server_address),
            clock: RwLock::new(VectorClock::new())
        }
    }
    pub fn inc(&self) -> StandardVectorClock {
        let mut clock = self.clock.write();
        clock.inc(self.server)
    }

    pub fn happened_before(&self, clock_b: &StandardVectorClock) -> bool {
        let clock = self.clock.read();
        clock.happened_before(clock_b)
    }
    pub fn equals(&self, clock_b: &StandardVectorClock) -> bool {
        let clock = self.clock.read();
        clock.equals(clock_b)
    }
    pub fn relation(&self, clock_b: &StandardVectorClock) -> Relation {
        let clock = self.clock.read();
        clock.relation(clock_b)
    }
    pub fn merge_with(&self, clock_b: &StandardVectorClock) {
        let mut clock = self.clock.write();
        clock.merge_with(clock_b)
    }
    pub fn learn_from(&self, clock_b: &StandardVectorClock) {
        let mut clock = self.clock.write();
        clock.learn_from(clock_b)
    }
    pub fn to_clock(&self) -> StandardVectorClock {
        let clock = self.clock.read();
        clock.clone()
    }
}

pub type StandardVectorClock = VectorClock<u64>;<|endoftext|>


<commit_before><commit_msg>Add a comment.<commit_after><|endoftext|>


<commit_before>use super::common::*;
use crate::prelude::*;

use crate::idents;
use crate::model;
use crate::utils;
use std::iter::FromIterator;

use syn::spanned::Spanned;

/// Expands the `com_library` macro.
///
/// The macro expansion results in the following items:
///
/// - `DllGetClassObject` extern function implementation.
/// - `IntercomListClassObjects` extern function implementation.
pub fn expand_com_module(
    arg_tokens: TokenStreamNightly,
    com_library: bool,
) -> Result<TokenStreamNightly, model::ParseError>
{
    let mut output = vec![];
    let lib = model::ComLibrary::parse(&lib_name(), arg_tokens.into())?;

    // Create the match-statmeent patterns for each supposedly visible COM class.
    let mut match_arms = vec![];
    for struct_path in &lib.coclasses {
        // Construct the match pattern.
        let clsid_path = idents::clsid_path(struct_path);
        match_arms.push(quote_spanned!(struct_path.span() =>
            #clsid_path =>
                return Some(intercom::ClassFactory::<#struct_path>::create(riid, pout))
        ));
    }

    let try_submodule_class_factory = lib.submodules.iter().map(|submod| {
        quote!(
            if let Some(hr) = #submod::__get_module_class_factory(rclsid, riid, pout) {
                return Some(hr);
            }
        )
    });

    // Implement the __get_module_class_factory function.
    output.push(quote!(
        #[allow(dead_code)]
        #[doc(hidden)]
        pub unsafe fn __get_module_class_factory(
            rclsid : intercom::REFCLSID,
            riid : intercom::REFIID,
            pout : *mut intercom::raw::RawComPtr
        ) -> Option<intercom::raw::HRESULT>
        {
            // Create new class factory.
            // Specify a create function that is able to create all the
            // contained coclasses.
            match *rclsid {
                #( #match_arms, )*
                _ => {},
            };

            // Try each sub-module
            #( #try_submodule_class_factory )*

            None
        }
    ));

    // Implement DllGetClassObject and DllMain.
    //
    // This is more or less the only symbolic entry point that the COM
    // infrastructure uses. The COM client uses this method to acquire
    // the IClassFactory interfaces that are then used to construct the
    // actual coclasses.
    if com_library {
        let dll_get_class_object = get_dll_get_class_object_function();
        output.push(dll_get_class_object);
        output.push(quote!(
            // Do we need this? Would rather not export this through an extern crate
            // for another dll.
            //
            // com_library should have dllmain!() macro or similar that implements this
            // together with the COM registration.
            #[no_mangle]
            #[allow(non_camel_case_types)]
            #[deprecated]
            #[doc(hidden)]
            pub extern "stdcall" fn DllMain(
                _dll_instance: *mut std::os::raw::c_void,
                reason: u32,
                _reserved: *mut std::os::raw::c_void,
            ) -> bool
            {
                true
            }
        ));
    }

    // Implement get_intercom_typelib()
    output.push(create_gather_module_types(&lib).map_err(model::ParseError::ComLibrary)?);
    if com_library {
        output.push(create_get_typelib_function(&lib).map_err(model::ParseError::ComLibrary)?);
    }

    // Implement DllListClassObjects
    // DllListClassObjects returns all CLSIDs implemented in the crate.
    if com_library {
        let list_class_objects = get_intercom_list_class_objects_function();
        output.push(list_class_objects);
    }

    Ok(TokenStream::from_iter(output.into_iter()).into())
}

fn get_dll_get_class_object_function() -> TokenStream
{
    quote!(
        #[no_mangle]
        #[allow(non_snake_case)]
        #[allow(dead_code)]
        #[doc(hidden)]
        pub unsafe extern "system" fn DllGetClassObject(
            rclsid: intercom::REFCLSID,
            riid: intercom::REFIID,
            pout: *mut intercom::raw::RawComPtr,
        ) -> intercom::raw::HRESULT
        {
            // Delegate to the module implementation.
            if let Some(hr) = __get_module_class_factory(rclsid, riid, pout) {
                return hr;
            }

            // Try intercom built in types.
            if let Some(hr) = intercom::__get_module_class_factory(rclsid, riid, pout) {
                return hr;
            }

            intercom::raw::E_CLASSNOTAVAILABLE
        }
    )
}

fn create_gather_module_types(lib: &model::ComLibrary) -> Result<TokenStream, String>
{
    let create_class_typeinfo = lib.coclasses.iter().map(|path| {
        quote!(
            <#path as intercom::attributes::ComClassTypeInfo>::gather_type_info()
        )
    });
    let gather_submodule_types = lib
        .submodules
        .iter()
        .map(|path| quote!( #path::__gather_module_types()));
    Ok(quote!(
        pub fn __gather_module_types() -> Vec<intercom::typelib::TypeInfo>
        {
            vec![
                #( #create_class_typeinfo, )*
                #( #gather_submodule_types, )*
            ]
            .into_iter()
            .flatten()
            .collect()
        }
    ))
}

fn create_get_typelib_function(lib: &model::ComLibrary) -> Result<TokenStream, String>
{
    let lib_name = lib_name();
    let libid = utils::get_guid_tokens(&lib.libid, Span::call_site());
    Ok(quote!(
        #[no_mangle]
        pub unsafe extern "system" fn IntercomTypeLib(
            type_system: intercom::type_system::TypeSystemName,
            out: *mut intercom::raw::RawComPtr,
        ) -> intercom::raw::HRESULT
        {
            let mut tlib = intercom::ComBox::new(intercom::typelib::TypeLib::__new(
                    #lib_name.into(),
                    #libid,
                    "0.1".into(),
                    intercom::__gather_module_types()
                        .into_iter().chain(__gather_module_types())
                        .collect()
            ));
            let rc = intercom::ComRc::<intercom::typelib::IIntercomTypeLib>::from( &tlib );
            let itf = intercom::ComRc::detach(rc);
            *out = type_system.get_ptr(&itf);

            intercom::raw::S_OK
        }
    ))
}

fn get_intercom_list_class_objects_function() -> TokenStream
{
    quote!(
        #[no_mangle]
        #[allow(non_snake_case)]
        #[allow(dead_code)]
        #[doc(hidden)]
        pub unsafe extern "system" fn IntercomListClassObjects(
            pcount: *mut usize,
            pclsids: *mut *const intercom::CLSID,
        ) -> intercom::raw::HRESULT
        {
            // Do not crash due to invalid parameters.
            if pcount.is_null() {
                return intercom::raw::E_POINTER;
            }
            if pclsids.is_null() {
                return intercom::raw::E_POINTER;
            }

            // Store the available CLSID in a static variable so that we can
            // pass them as-is to the caller.
            static mut AVAILABLE_CLASSES: Option<Vec<intercom::CLSID>> = None;
            static INIT_AVAILABLE_CLASSES: std::sync::Once = std::sync::Once::new();
            INIT_AVAILABLE_CLASSES.call_once(|| unsafe {
                AVAILABLE_CLASSES = Some(
                    __gather_module_types()
                        .into_iter()
                        .chain(intercom::__gather_module_types())
                        .filter_map(|ty| match ty {
                            intercom::typelib::TypeInfo::Class(cls) => Some(cls.clsid.clone()),
                            _ => None,
                        })
                        .collect(),
                );
            });

            // com_struct will drop here and decrement the referenc ecount.
            // This is okay, as the query_interface incremented it, leaving
            // it at two at this point.
            let available_classes = AVAILABLE_CLASSES
                .as_ref()
                .expect("AVAILABLE_CLASSES was not initialized");
            *pcount = available_classes.len();
            *pclsids = available_classes.as_ptr();

            intercom::raw::S_OK
        }
    )
}
<commit_msg>Remove outdated comment from DllMain<commit_after>use super::common::*;
use crate::prelude::*;

use crate::idents;
use crate::model;
use crate::utils;
use std::iter::FromIterator;

use syn::spanned::Spanned;

/// Expands the `com_library` macro.
///
/// The macro expansion results in the following items:
///
/// - `DllGetClassObject` extern function implementation.
/// - `IntercomListClassObjects` extern function implementation.
pub fn expand_com_module(
    arg_tokens: TokenStreamNightly,
    com_library: bool,
) -> Result<TokenStreamNightly, model::ParseError>
{
    let mut output = vec![];
    let lib = model::ComLibrary::parse(&lib_name(), arg_tokens.into())?;

    // Create the match-statmeent patterns for each supposedly visible COM class.
    let mut match_arms = vec![];
    for struct_path in &lib.coclasses {
        // Construct the match pattern.
        let clsid_path = idents::clsid_path(struct_path);
        match_arms.push(quote_spanned!(struct_path.span() =>
            #clsid_path =>
                return Some(intercom::ClassFactory::<#struct_path>::create(riid, pout))
        ));
    }

    let try_submodule_class_factory = lib.submodules.iter().map(|submod| {
        quote!(
            if let Some(hr) = #submod::__get_module_class_factory(rclsid, riid, pout) {
                return Some(hr);
            }
        )
    });

    // Implement the __get_module_class_factory function.
    output.push(quote!(
        #[allow(dead_code)]
        #[doc(hidden)]
        pub unsafe fn __get_module_class_factory(
            rclsid : intercom::REFCLSID,
            riid : intercom::REFIID,
            pout : *mut intercom::raw::RawComPtr
        ) -> Option<intercom::raw::HRESULT>
        {
            // Create new class factory.
            // Specify a create function that is able to create all the
            // contained coclasses.
            match *rclsid {
                #( #match_arms, )*
                _ => {},
            };

            // Try each sub-module
            #( #try_submodule_class_factory )*

            None
        }
    ));

    // Implement DllGetClassObject and DllMain.
    //
    // This is more or less the only symbolic entry point that the COM
    // infrastructure uses. The COM client uses this method to acquire
    // the IClassFactory interfaces that are then used to construct the
    // actual coclasses.
    if com_library {
        let dll_get_class_object = get_dll_get_class_object_function();
        output.push(dll_get_class_object);
        output.push(quote!(
            #[no_mangle]
            #[allow(non_camel_case_types)]
            #[deprecated]
            #[doc(hidden)]
            pub extern "stdcall" fn DllMain(
                _dll_instance: *mut std::os::raw::c_void,
                reason: u32,
                _reserved: *mut std::os::raw::c_void,
            ) -> bool
            {
                true
            }
        ));
    }

    // Implement get_intercom_typelib()
    output.push(create_gather_module_types(&lib).map_err(model::ParseError::ComLibrary)?);
    if com_library {
        output.push(create_get_typelib_function(&lib).map_err(model::ParseError::ComLibrary)?);
    }

    // Implement DllListClassObjects
    // DllListClassObjects returns all CLSIDs implemented in the crate.
    if com_library {
        let list_class_objects = get_intercom_list_class_objects_function();
        output.push(list_class_objects);
    }

    Ok(TokenStream::from_iter(output.into_iter()).into())
}

fn get_dll_get_class_object_function() -> TokenStream
{
    quote!(
        #[no_mangle]
        #[allow(non_snake_case)]
        #[allow(dead_code)]
        #[doc(hidden)]
        pub unsafe extern "system" fn DllGetClassObject(
            rclsid: intercom::REFCLSID,
            riid: intercom::REFIID,
            pout: *mut intercom::raw::RawComPtr,
        ) -> intercom::raw::HRESULT
        {
            // Delegate to the module implementation.
            if let Some(hr) = __get_module_class_factory(rclsid, riid, pout) {
                return hr;
            }

            // Try intercom built in types.
            if let Some(hr) = intercom::__get_module_class_factory(rclsid, riid, pout) {
                return hr;
            }

            intercom::raw::E_CLASSNOTAVAILABLE
        }
    )
}

fn create_gather_module_types(lib: &model::ComLibrary) -> Result<TokenStream, String>
{
    let create_class_typeinfo = lib.coclasses.iter().map(|path| {
        quote!(
            <#path as intercom::attributes::ComClassTypeInfo>::gather_type_info()
        )
    });
    let gather_submodule_types = lib
        .submodules
        .iter()
        .map(|path| quote!( #path::__gather_module_types()));
    Ok(quote!(
        pub fn __gather_module_types() -> Vec<intercom::typelib::TypeInfo>
        {
            vec![
                #( #create_class_typeinfo, )*
                #( #gather_submodule_types, )*
            ]
            .into_iter()
            .flatten()
            .collect()
        }
    ))
}

fn create_get_typelib_function(lib: &model::ComLibrary) -> Result<TokenStream, String>
{
    let lib_name = lib_name();
    let libid = utils::get_guid_tokens(&lib.libid, Span::call_site());
    Ok(quote!(
        #[no_mangle]
        pub unsafe extern "system" fn IntercomTypeLib(
            type_system: intercom::type_system::TypeSystemName,
            out: *mut intercom::raw::RawComPtr,
        ) -> intercom::raw::HRESULT
        {
            let mut tlib = intercom::ComBox::new(intercom::typelib::TypeLib::__new(
                    #lib_name.into(),
                    #libid,
                    "0.1".into(),
                    intercom::__gather_module_types()
                        .into_iter().chain(__gather_module_types())
                        .collect()
            ));
            let rc = intercom::ComRc::<intercom::typelib::IIntercomTypeLib>::from( &tlib );
            let itf = intercom::ComRc::detach(rc);
            *out = type_system.get_ptr(&itf);

            intercom::raw::S_OK
        }
    ))
}

fn get_intercom_list_class_objects_function() -> TokenStream
{
    quote!(
        #[no_mangle]
        #[allow(non_snake_case)]
        #[allow(dead_code)]
        #[doc(hidden)]
        pub unsafe extern "system" fn IntercomListClassObjects(
            pcount: *mut usize,
            pclsids: *mut *const intercom::CLSID,
        ) -> intercom::raw::HRESULT
        {
            // Do not crash due to invalid parameters.
            if pcount.is_null() {
                return intercom::raw::E_POINTER;
            }
            if pclsids.is_null() {
                return intercom::raw::E_POINTER;
            }

            // Store the available CLSID in a static variable so that we can
            // pass them as-is to the caller.
            static mut AVAILABLE_CLASSES: Option<Vec<intercom::CLSID>> = None;
            static INIT_AVAILABLE_CLASSES: std::sync::Once = std::sync::Once::new();
            INIT_AVAILABLE_CLASSES.call_once(|| unsafe {
                AVAILABLE_CLASSES = Some(
                    __gather_module_types()
                        .into_iter()
                        .chain(intercom::__gather_module_types())
                        .filter_map(|ty| match ty {
                            intercom::typelib::TypeInfo::Class(cls) => Some(cls.clsid.clone()),
                            _ => None,
                        })
                        .collect(),
                );
            });

            // com_struct will drop here and decrement the referenc ecount.
            // This is okay, as the query_interface incremented it, leaving
            // it at two at this point.
            let available_classes = AVAILABLE_CLASSES
                .as_ref()
                .expect("AVAILABLE_CLASSES was not initialized");
            *pcount = available_classes.len();
            *pclsids = available_classes.as_ptr();

            intercom::raw::S_OK
        }
    )
}
<|endoftext|>


<commit_before>extern crate csv;

use super::enums;
use super::moves::Technique;
use enum_primitive::FromPrimitive;
use std::collections::HashMap;

/// Manages the list of moves that are available. Contains a bool that is true whenever all
/// available moves are inside the entries to make an easier search possible.
/// By now the whole movedex contains 617 moves, which are nearly all moves from the main game
/// series. 4 Moves are missing due to missing data in the used database.
#[derive(Debug, Clone)]
pub struct Movedex {
    entries: Vec<Technique>,
    complete: bool,
}

// TODO: last 4 attacks are missing in move_meta.csv, therefore are not implemented right now.
// DB must be extended and if statements adjusted accordingly

impl Movedex {
    /// Takes an ID and a movedex and returns an option with the move that can be find with the
    /// given ID. Returns None if the ID isn't in the movedex.
    pub fn move_by_id(&self, id: usize) -> Option<Technique> {
        if id < 617 && self.is_complete() {
            return Some(self.get_entries()[id - 1].clone());
        } else if id < 617 {
            for entry in self.entries.clone() {
                if entry.get_id() == id {
                    return Some(entry);
                }
            }
        }
        None
    }

    /// Returns a list of all learnable moves by level for a specific pokemon with a specific
    /// level.
    pub fn for_token(&self, level: u16, id: usize) -> Movedex {
        let mut new_dex = Vec::new();
        let mut move_db = csv::Reader::from_file("./src/db/tables/pokemon_moves.csv").unwrap();
        for record in move_db.decode() {
            let (poke_id, version, move_id, _, move_level, _): (usize,
                                                                u8,
                                                                usize,
                                                                usize,
                                                                u16,
                                                                Option<usize>) = record.unwrap();
            if move_id < 617 && move_level <= level && poke_id == id && version == 16 {
                let move_tmp = self.move_by_id(move_id);
                // ifs are needed to exclude unimplemented moves from the list
                if move_tmp.clone().is_some() &&
                   !(move_tmp.clone().unwrap().get_name() == "counter" ||
                     move_tmp.clone().unwrap().get_name() == "bide" ||
                     move_tmp.clone().unwrap().get_name() == "mirror-coat" ||
                     move_tmp.clone().unwrap().get_name() == "spit-up" ||
                     move_tmp.clone().unwrap().get_name() == "natural-gift" ||
                     move_tmp.clone().unwrap().get_name() == "metal-burst" ||
                     move_tmp.clone().unwrap().get_name() == "fling" ||
                     move_tmp.clone().unwrap().get_name() == "trump-card" ||
                     move_tmp.clone().unwrap().get_name() == "me-first" ||
                     move_tmp.unwrap().get_category() == enums::MoveCategory::Unique) ||
                   (move_tmp.unwrap().get_category() == enums::MoveCategory::Unique &&
                    (move_tmp.clone().unwrap().get_name() == "teleport" ||
                     move_tmp.clone().unwrap().get_name() == "mimic" ||
                     move_tmp.clone().unwrap().get_name() == "metronome" ||
                     move_tmp.clone().unwrap().get_name() == "mirror-move" ||
                     move_tmp.clone().unwrap().get_name() == "nature-power" ||
                     move_tmp.clone().unwrap().get_name() == "splash" ||
                     //move_tmp.clone().unwrap().get_name() == "rest" ||
                     move_tmp.clone().unwrap().get_name() == "conversion" ||
                     move_tmp.clone().unwrap().get_name() == "spite" ||
                     move_tmp.clone().unwrap().get_name() == "sleep-talk" ||
                     move_tmp.clone().unwrap().get_name() == "celebrate" ||
                     move_tmp.clone().unwrap().get_name() == "powder" ||
                     move_tmp.clone().unwrap().get_name() == "reflect-type" ||
                     move_tmp.clone().unwrap().get_name() == "soak" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "")) {
                    new_dex.push(self.move_by_id(move_id).unwrap());

                }
            }
        }
        new_dex.sort();
        new_dex.dedup();
        Movedex {
            entries: new_dex,
            complete: false,
        }
    }

    /// Returns the entry field of a movedex.
    pub fn get_entries(&self) -> Vec<Technique> {
        self.entries.clone()
    }

    /// Returns true if the movedex contains all possible moves, and false if not.
    fn is_complete(&self) -> bool {
        self.complete
    }

    /// Creates a complete Movedex from the type_efficacy, moves_whole and move_flag_map databases
    /// in the table folder.
    pub fn new() -> Movedex {
        // In the first step creates a vec with the effectivities for every type.
        let mut effectivity = Vec::new();
        let mut effective_db = csv::Reader::from_file("./src/db/tables/type_efficacy.csv").unwrap();
        for record in effective_db.decode() {
            let (off, def, factor): (i32, i32, u8) = record.unwrap();
            effectivity.push((off, def, factor));
        }

        // Creates the main part with most simpel values and directly adds a Hash Map for the type
        // efficiency of the move.
        let mut moves = Vec::new();
        let mut move_db = csv::Reader::from_file("./src/db/tables/moves_whole.csv").unwrap();
        for record in move_db.decode() {
            let mut move_tmp: Technique = record.unwrap();
            let mut effective_hash = HashMap::new();
            for entry in effectivity.clone() {
                if entry.0 == move_tmp.get_type() as i32 && entry.2 != 100 {
                    let eff_id = match entry.2 {
                        0 => -4,
                        50 => -1,
                        200 => 1,
                        _ => unreachable!(),
                    };
                    effective_hash.insert(enums::Types::from_i32(entry.1).unwrap(), eff_id);
                    move_tmp.set_effectivity_map(effective_hash.clone());
                }

            }

            moves.push(move_tmp);
        }

        // Adds all flags, that are valid for the moves.
        let mut flags = Vec::new();
        let mut last_id = 1;
        let mut flag_db = csv::Reader::from_file("./src/db/tables/move_flag_map.csv").unwrap();
        for record in flag_db.decode() {
            let (id, identifier): (usize, i32) = record.unwrap();
            if id < 617 {
                if !(id == last_id) {
                    moves[last_id - 1].set_flags(flags);
                    last_id = id;
                    flags = Vec::new();
                }
                flags.push(enums::MoveFlags::from_i32(identifier).unwrap());
            }
        }

        Movedex {
            entries: moves,
            complete: true,
        }
    }
}
<commit_msg>fix errors in movedex.rs<commit_after>extern crate csv;

use super::enums;
use super::moves::Technique;
use enum_primitive::FromPrimitive;
use std::collections::HashMap;

/// Manages the list of moves that are available. Contains a bool that is true whenever all
/// available moves are inside the entries to make an easier search possible.
/// By now the whole movedex contains 617 moves, which are nearly all moves from the main game
/// series. 4 Moves are missing due to missing data in the used database.
#[derive(Debug, Clone)]
pub struct Movedex {
    entries: Vec<Technique>,
    complete: bool,
}

// TODO: last 4 attacks are missing in move_meta.csv, therefore are not implemented right now.
// DB must be extended and if statements adjusted accordingly

impl Movedex {
    /// Takes an ID and a movedex and returns an option with the move that can be find with the
    /// given ID. Returns None if the ID isn't in the movedex.
    pub fn move_by_id(&self, id: usize) -> Option<Technique> {
        if id < 617 && self.is_complete() {
            return Some(self.get_entries()[id - 1].clone());
        } else if id < 617 {
            for entry in self.entries.clone() {
                if entry.get_id() == id {
                    return Some(entry);
                }
            }
        }
        None
    }

    /// Returns a list of all learnable moves by level for a specific pokemon with a specific
    /// level.
    pub fn for_token(&self, level: u16, id: usize) -> Movedex {
        let mut new_dex = Vec::new();
        let mut move_db = csv::Reader::from_file("./src/db/tables/pokemon_moves.csv").unwrap();
        for record in move_db.decode() {
            let (poke_id, version, move_id, _, move_level, _): (usize,
                                                                u8,
                                                                usize,
                                                                usize,
                                                                u16,
                                                                Option<usize>) = record.unwrap();
            if move_id < 617 && move_level <= level && poke_id == id && version == 16 {
                let move_tmp = self.move_by_id(move_id);
                // ifs are needed to exclude unimplemented moves from the list
                if move_tmp.clone().is_some() &&
                   !(move_tmp.clone().unwrap().get_name() == "counter" ||
                     move_tmp.clone().unwrap().get_name() == "bide" ||
                     move_tmp.clone().unwrap().get_name() == "mirror-coat" ||
                     move_tmp.clone().unwrap().get_name() == "spit-up" ||
                     move_tmp.clone().unwrap().get_name() == "natural-gift" ||
                     move_tmp.clone().unwrap().get_name() == "metal-burst" ||
                     move_tmp.clone().unwrap().get_name() == "fling" ||
                     move_tmp.clone().unwrap().get_name() == "trump-card" ||
                     move_tmp.clone().unwrap().get_name() == "me-first" ||
                     move_tmp.clone().unwrap().get_category() == enums::MoveCategory::Unique) ||
                    (move_tmp.clone().unwrap().get_category() == enums::MoveCategory::Unique &&
                    (move_tmp.clone().unwrap().get_name() == "teleport" ||
                     move_tmp.clone().unwrap().get_name() == "mimic" ||
                     move_tmp.clone().unwrap().get_name() == "metronome" ||
                     move_tmp.clone().unwrap().get_name() == "mirror-move" ||
                     move_tmp.clone().unwrap().get_name() == "nature-power" ||
                     move_tmp.clone().unwrap().get_name() == "splash" ||
                     //move_tmp.clone().unwrap().get_name() == "rest" ||
                     move_tmp.clone().unwrap().get_name() == "conversion" ||
                     move_tmp.clone().unwrap().get_name() == "spite" ||
                     move_tmp.clone().unwrap().get_name() == "sleep-talk" ||
                     move_tmp.clone().unwrap().get_name() == "celebrate" ||
                     move_tmp.clone().unwrap().get_name() == "powder" ||
                     move_tmp.clone().unwrap().get_name() == "reflect-type" ||
                     move_tmp.clone().unwrap().get_name() == "soak" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "" ||
                     move_tmp.clone().unwrap().get_name() == "")) {
                    new_dex.push(self.move_by_id(move_id).unwrap());

                }
            }
        }
        new_dex.sort();
        new_dex.dedup();
        Movedex {
            entries: new_dex,
            complete: false,
        }
    }

    /// Returns the entry field of a movedex.
    pub fn get_entries(&self) -> Vec<Technique> {
        self.entries.clone()
    }

    /// Returns true if the movedex contains all possible moves, and false if not.
    fn is_complete(&self) -> bool {
        self.complete
    }

    /// Creates a complete Movedex from the type_efficacy, moves_whole and move_flag_map databases
    /// in the table folder.
    pub fn new() -> Movedex {
        // In the first step creates a vec with the effectivities for every type.
        let mut effectivity = Vec::new();
        let mut effective_db = csv::Reader::from_file("./src/db/tables/type_efficacy.csv").unwrap();
        for record in effective_db.decode() {
            let (off, def, factor): (i32, i32, u8) = record.unwrap();
            effectivity.push((off, def, factor));
        }

        // Creates the main part with most simpel values and directly adds a Hash Map for the type
        // efficiency of the move.
        let mut moves = Vec::new();
        let mut move_db = csv::Reader::from_file("./src/db/tables/moves_whole.csv").unwrap();
        for record in move_db.decode() {
            let mut move_tmp: Technique = record.unwrap();
            let mut effective_hash = HashMap::new();
            for entry in effectivity.clone() {
                if entry.0 == move_tmp.get_type() as i32 && entry.2 != 100 {
                    let eff_id = match entry.2 {
                        0 => -4,
                        50 => -1,
                        200 => 1,
                        _ => unreachable!(),
                    };
                    effective_hash.insert(enums::Types::from_i32(entry.1).unwrap(), eff_id);
                    move_tmp.set_effectivity_map(effective_hash.clone());
                }

            }

            moves.push(move_tmp);
        }

        // Adds all flags, that are valid for the moves.
        let mut flags = Vec::new();
        let mut last_id = 1;
        let mut flag_db = csv::Reader::from_file("./src/db/tables/move_flag_map.csv").unwrap();
        for record in flag_db.decode() {
            let (id, identifier): (usize, i32) = record.unwrap();
            if id < 617 {
                if !(id == last_id) {
                    moves[last_id - 1].set_flags(flags);
                    last_id = id;
                    flags = Vec::new();
                }
                flags.push(enums::MoveFlags::from_i32(identifier).unwrap());
            }
        }

        Movedex {
            entries: moves,
            complete: true,
        }
    }
}
<|endoftext|>