Import protobuf-codegen-2.14.0

* Add OWNERS, Android.bp, and README.android.
* Hard code version number in src/lib.rs for now.
  It could be in a smarter update_package.sh to get the
  new version number from Cargo.tom. But until then,
  the difference in lib.rs will be caught and fixed manually.
* Rename protoc_gen_rust to protoc-gen-rust for aprotoc plugin.

Bug: 143953733
Test: make
Change-Id: I9b3c3b9f2e7ad0eb203c26534f2b6ba5fac46eef
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..d6337d5
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,5 @@
+{
+  "git": {
+    "sha1": "09cb48471825c36fc5c8205f197eefbf664a10f7"
+  }
+}
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..2d4ef0a
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,38 @@
+// This file is generated by cargo2android.py --run --dependencies.
+
+// Rename protoc_gen_rust to protoc-gen-rust for aprotoc plugin.
+
+rust_library_host_rlib {
+    name: "libprotobuf_codegen",
+    crate_name: "protobuf_codegen",
+    srcs: ["src/lib.rs"],
+    edition: "2015",
+    rlibs: [
+        "libprotobuf",
+    ],
+}
+
+// rust_binary_host {
+//     name: "protobuf_bin_gen_rust_do_not_use",
+//     crate_name: "protobuf_bin_gen_rust_do_not_use",
+//     srcs: ["src/bin/protobuf-bin-gen-rust-do-not-use.rs"],
+//     edition: "2015",
+//     rlibs: [
+//         "libprotobuf",
+//         "libprotobuf_codegen",
+//     ],
+// }
+
+rust_binary_host {
+    name: "protoc-gen-rust",
+    crate_name: "protoc_gen_rust",
+    srcs: ["src/bin/protoc-gen-rust.rs"],
+    edition: "2015",
+    rlibs: [
+        "libprotobuf",
+        "libprotobuf_codegen",
+    ],
+}
+
+// dependent_library ["feature_list"]
+//   protobuf-2.14.0
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..b9bafb0
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,14 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "protobuf"
+version = "2.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e86d370532557ae7573551a1ec8235a0f8d6cb276c7c9e6aa490b511c447485"
+
+[[package]]
+name = "protobuf-codegen"
+version = "2.14.0"
+dependencies = [
+ "protobuf",
+]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..afcb5be
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,37 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "protobuf-codegen"
+version = "2.14.0"
+authors = ["Stepan Koltsov <stepan.koltsov@gmail.com>"]
+description = "Code generator for rust-protobuf.\n\nIncludes a library and `protoc-gen-rust` binary.\n\nSee `protoc-rust` and `protobuf-codegen-pure` crates.\n"
+homepage = "https://github.com/stepancheg/rust-protobuf/"
+license = "MIT"
+repository = "https://github.com/stepancheg/rust-protobuf/"
+[package.metadata.docs.rs]
+all-features = true
+
+[lib]
+bench = false
+
+[[bin]]
+name = "protoc-gen-rust"
+path = "src/bin/protoc-gen-rust.rs"
+test = false
+
+[[bin]]
+name = "protobuf-bin-gen-rust-do-not-use"
+path = "src/bin/protobuf-bin-gen-rust-do-not-use.rs"
+test = false
+[dependencies.protobuf]
+version = "=2.14.0"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..0511478
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,35 @@
+[package]
+name = "protobuf-codegen"
+version = "2.14.0"
+authors = ["Stepan Koltsov <stepan.koltsov@gmail.com>"]
+license = "MIT"
+homepage = "https://github.com/stepancheg/rust-protobuf/"
+repository = "https://github.com/stepancheg/rust-protobuf/"
+description = """
+Code generator for rust-protobuf.
+
+Includes a library and `protoc-gen-rust` binary.
+
+See `protoc-rust` and `protobuf-codegen-pure` crates.
+"""
+
+[lib]
+bench = false
+
+[dependencies]
+protobuf = { path = "../protobuf", version = "=2.14.0" }
+
+[[bin]]
+
+name = "protoc-gen-rust"
+path = "src/bin/protoc-gen-rust.rs"
+test = false
+
+[[bin]]
+
+name = "protobuf-bin-gen-rust-do-not-use"
+path = "src/bin/protobuf-bin-gen-rust-do-not-use.rs"
+test = false
+
+[package.metadata.docs.rs]
+all-features = true
diff --git a/LICENSE b/LICENSE
new file mode 120000
index 0000000..85de3d4
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+LICENSE.txt
\ No newline at end of file
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..acce639
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,19 @@
+Copyright (c) 2019 Stepan Koltsov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..94eb560
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,19 @@
+name: "protobuf-codegen"
+description: "Code generator for rust-protobuf.\n\nIncludes a library and `protoc-gen-rust` binary.\n\nSee `protoc-rust` and `protobuf-codegen-pure` crates.\n"
+third_party {
+  url {
+    type: HOMEPAGE
+    value: "https://crates.io/crates/protobuf-codegen"
+  }
+  url {
+    type: GIT
+    value: "https://github.com/stepancheg/rust-protobuf"
+  }
+  version: "2.14.0"
+  license_type: NOTICE
+  last_upgrade_date {
+    year: 2020
+    month: 6
+    day: 3
+  }
+}
diff --git a/MODULE_LICENSE_BSD_LIKE b/MODULE_LICENSE_BSD_LIKE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_BSD_LIKE
diff --git a/NOTICE b/NOTICE
new file mode 120000
index 0000000..7a694c9
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1 @@
+LICENSE
\ No newline at end of file
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..46fc303
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:/OWNERS
diff --git a/README.android b/README.android
new file mode 100644
index 0000000..93d2ac7
--- /dev/null
+++ b/README.android
@@ -0,0 +1,15 @@
+Since we do not run build.rs during an Android build,
+we need to set up the version number in src/lib.rs
+until we have a smarter way to patch it based on new
+version number in Cargo.toml.
+
+To update this package, please make sure that the following code
+in src/lib.rs is up to data.
+
+        // Hack: hard code version number here because Android.bp
+        // rust modules cannot pass it though env variable yet.
+        w.write_generated_by("rust-protobuf", "2.14.0");
+
+If there are non-trivial changes in build.rs or src/lib.rs,
+please rerun cargo2android.py and verify the differences in
+Android.bp and src/lib.rs.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5b654ef
--- /dev/null
+++ b/README.md
@@ -0,0 +1,57 @@
+# protobuf-codegen
+
+This crate contains protobuf code generator and a `protoc-gen-rust` `protoc` plugin.
+
+## protoc-gen-rust
+
+`protoc-gen-rust` implements standard protobuf `protoc` plugin conventions.
+
+Probably you do not want to use it directly in Rust environment, there are easier to use alternatives:
+
+* [protoc-rust crate](https://github.com/stepancheg/rust-protobuf/tree/master/protoc-rust)
+  which can be invoked programmatically from `build.rs` of your project
+  which requires only `protoc` in `$PATH` but not `protoc-gen-rust`.
+* [protobuf-codegen-pure crate](https://github.com/stepancheg/rust-protobuf/tree/master/protobuf-codegen-pure)
+  which behaves like protoc-rust, but does not depend on `protoc` binary
+
+## But if you really want to use that plugin, here's the instruction
+
+(Note `protoc` can be invoked programmatically with
+[protoc crate](https://github.com/stepancheg/rust-protobuf/tree/master/protoc/))
+
+0) Install protobuf for `protoc` binary.
+
+On OS X [Homebrew](https://github.com/Homebrew/brew) can be used:
+
+```
+brew install protobuf
+```
+
+On Ubuntu, `protobuf-compiler` package can be installed:
+
+```
+apt-get install protobuf-compiler
+```
+
+Protobuf is needed only for code generation, `rust-protobuf` runtime
+does not use `protobuf` library.
+
+1) Install `protoc-gen-rust` program (which is `protoc` plugin)
+
+It can be installed either from source or with `cargo install protobuf` command.
+
+2) Add `protoc-gen-rust` to $PATH
+
+If you installed it with cargo, it should be
+
+```
+PATH="$HOME/.cargo/bin:$PATH"
+```
+
+3) Generate .rs files:
+
+```
+protoc --rust_out . foo.proto
+```
+
+This will generate .rs files in current directory.
diff --git a/src/bin/protobuf-bin-gen-rust-do-not-use.rs b/src/bin/protobuf-bin-gen-rust-do-not-use.rs
new file mode 100644
index 0000000..fc66d27
--- /dev/null
+++ b/src/bin/protobuf-bin-gen-rust-do-not-use.rs
@@ -0,0 +1,37 @@
+extern crate protobuf;
+extern crate protobuf_codegen;
+
+use std::fs::*;
+use std::io::Read;
+use std::path::Path;
+
+use protobuf::descriptor::*;
+use protobuf::parse_from_reader;
+use protobuf_codegen::*;
+
+fn write_file(bin: &str) {
+    let mut is = File::open(&Path::new(bin)).unwrap();
+    let fds = parse_from_reader::<FileDescriptorSet>(&mut is as &mut dyn Read).unwrap();
+
+    let file_names: Vec<String> = fds
+        .get_file()
+        .iter()
+        .map(|f| f.get_name().to_string())
+        .collect();
+    gen_and_write(
+        fds.get_file(),
+        &file_names,
+        Path::new("."),
+        &Default::default(),
+    )
+    .expect("gen_and_write");
+}
+
+fn main() {
+    let args: Vec<String> = std::env::args().collect();
+    if args.len() != 2 {
+        panic!("must have exactly one argument");
+    }
+    let ref pb_bin = args[1];
+    write_file(&pb_bin);
+}
diff --git a/src/bin/protoc-gen-rust.rs b/src/bin/protoc-gen-rust.rs
new file mode 100644
index 0000000..97ac7d2
--- /dev/null
+++ b/src/bin/protoc-gen-rust.rs
@@ -0,0 +1,5 @@
+extern crate protobuf_codegen;
+
+fn main() {
+    protobuf_codegen::protoc_gen_rust_main();
+}
diff --git a/src/code_writer.rs b/src/code_writer.rs
new file mode 100644
index 0000000..61ce92f
--- /dev/null
+++ b/src/code_writer.rs
@@ -0,0 +1,383 @@
+// TODO: used by grpc-rust, should move it into separate crate.
+#![doc(hidden)]
+
+use std::io::Write;
+
+/// Field visibility.
+pub enum Visibility {
+    Public,
+    Default,
+}
+
+pub struct CodeWriter<'a> {
+    writer: &'a mut (dyn Write + 'a),
+    indent: String,
+}
+
+impl<'a> CodeWriter<'a> {
+    pub fn new(writer: &'a mut dyn Write) -> CodeWriter<'a> {
+        CodeWriter {
+            writer: writer,
+            indent: "".to_string(),
+        }
+    }
+
+    pub fn write_line<S: AsRef<str>>(&mut self, line: S) {
+        (if line.as_ref().is_empty() {
+            self.writer.write_all("\n".as_bytes())
+        } else {
+            let s: String = [self.indent.as_ref(), line.as_ref(), "\n"].concat();
+            self.writer.write_all(s.as_bytes())
+        })
+        .unwrap();
+    }
+
+    pub fn write_generated(&mut self) {
+        self.write_line("// This file is generated. Do not edit");
+        self.write_generated_common();
+    }
+
+    pub fn write_generated_by(&mut self, pkg: &str, version: &str) {
+        self.write_line(format!(
+            "// This file is generated by {pkg} {version}. Do not edit",
+            pkg = pkg,
+            version = version
+        ));
+        self.write_generated_common();
+    }
+
+    fn write_generated_common(&mut self) {
+        // https://secure.phabricator.com/T784
+        self.write_line("// @generated");
+
+        self.write_line("");
+        self.comment("https://github.com/rust-lang/rust-clippy/issues/702");
+        self.write_line("#![allow(unknown_lints)]");
+        self.write_line("#![allow(clippy::all)]");
+        self.write_line("");
+        self.write_line("#![cfg_attr(rustfmt, rustfmt_skip)]");
+        self.write_line("");
+        self.write_line("#![allow(box_pointers)]");
+        self.write_line("#![allow(dead_code)]");
+        self.write_line("#![allow(missing_docs)]");
+        self.write_line("#![allow(non_camel_case_types)]");
+        self.write_line("#![allow(non_snake_case)]");
+        self.write_line("#![allow(non_upper_case_globals)]");
+        self.write_line("#![allow(trivial_casts)]");
+        self.write_line("#![allow(unsafe_code)]");
+        self.write_line("#![allow(unused_imports)]");
+        self.write_line("#![allow(unused_results)]");
+    }
+
+    pub fn todo(&mut self, message: &str) {
+        self.write_line(format!("panic!(\"TODO: {}\");", message));
+    }
+
+    pub fn unimplemented(&mut self) {
+        self.write_line(format!("unimplemented!();"));
+    }
+
+    pub fn indented<F>(&mut self, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        cb(&mut CodeWriter {
+            writer: self.writer,
+            indent: format!("{}    ", self.indent),
+        });
+    }
+
+    #[allow(dead_code)]
+    pub fn commented<F>(&mut self, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        cb(&mut CodeWriter {
+            writer: self.writer,
+            indent: format!("// {}", self.indent),
+        });
+    }
+
+    pub fn pub_const(&mut self, name: &str, field_type: &str, init: &str) {
+        self.write_line(&format!("pub const {}: {} = {};", name, field_type, init));
+    }
+
+    pub fn lazy_static(&mut self, name: &str, ty: &str) {
+        self.lazy_static_protobuf_path(name, ty, "::protobuf")
+    }
+
+    pub fn lazy_static_protobuf_path(&mut self, name: &str, ty: &str, protobuf_crate_path: &str) {
+        self.write_line(&format!(
+            "static mut {}: {}::lazy::Lazy<{}> = {}::lazy::Lazy::INIT;",
+            name, protobuf_crate_path, ty, protobuf_crate_path,
+        ));
+    }
+
+    pub fn lazy_static_decl_get<F>(&mut self, name: &str, ty: &str, init: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.lazy_static(name, ty);
+        self.unsafe_expr(|w| {
+            w.write_line(&format!("{}.get(|| {{", name));
+            w.indented(|w| init(w));
+            w.write_line(&format!("}})"));
+        });
+    }
+
+    pub fn lazy_static_decl_get_simple(&mut self, name: &str, ty: &str, init: &str) {
+        self.lazy_static(name, ty);
+        self.unsafe_expr(|w| {
+            w.write_line(&format!("{}.get({})", name, init));
+        });
+    }
+
+    pub fn block<F>(&mut self, first_line: &str, last_line: &str, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.write_line(first_line);
+        self.indented(cb);
+        self.write_line(last_line);
+    }
+
+    pub fn expr_block<F>(&mut self, prefix: &str, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.block(&format!("{} {{", prefix), "}", cb);
+    }
+
+    pub fn stmt_block<S: AsRef<str>, F>(&mut self, prefix: S, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.block(&format!("{} {{", prefix.as_ref()), "};", cb);
+    }
+
+    pub fn unsafe_expr<F>(&mut self, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.expr_block("unsafe", cb);
+    }
+
+    pub fn impl_self_block<S: AsRef<str>, F>(&mut self, name: S, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.expr_block(&format!("impl {}", name.as_ref()), cb);
+    }
+
+    pub fn impl_for_block<S1: AsRef<str>, S2: AsRef<str>, F>(&mut self, tr: S1, ty: S2, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.impl_args_for_block(&[], tr.as_ref(), ty.as_ref(), cb);
+    }
+
+    pub fn impl_args_for_block<F>(&mut self, args: &[&str], tr: &str, ty: &str, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        let args_str = if args.is_empty() {
+            "".to_owned()
+        } else {
+            format!("<{}>", args.join(", "))
+        };
+        self.expr_block(&format!("impl{} {} for {}", args_str, tr, ty), cb);
+    }
+
+    pub fn unsafe_impl(&mut self, what: &str, for_what: &str) {
+        self.write_line(&format!("unsafe impl {} for {} {{}}", what, for_what));
+    }
+
+    pub fn pub_struct<S: AsRef<str>, F>(&mut self, name: S, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.expr_block(&format!("pub struct {}", name.as_ref()), cb);
+    }
+
+    pub fn def_struct<S: AsRef<str>, F>(&mut self, name: S, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.expr_block(&format!("struct {}", name.as_ref()), cb);
+    }
+
+    pub fn pub_enum<F>(&mut self, name: &str, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.expr_block(&format!("pub enum {}", name), cb);
+    }
+
+    pub fn pub_trait<F>(&mut self, name: &str, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.expr_block(&format!("pub trait {}", name), cb);
+    }
+
+    pub fn pub_trait_extend<F>(&mut self, name: &str, extend: &str, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.expr_block(&format!("pub trait {} : {}", name, extend), cb);
+    }
+
+    pub fn field_entry(&mut self, name: &str, value: &str) {
+        self.write_line(&format!("{}: {},", name, value));
+    }
+
+    pub fn field_decl(&mut self, name: &str, field_type: &str) {
+        self.write_line(&format!("{}: {},", name, field_type));
+    }
+
+    pub fn pub_field_decl(&mut self, name: &str, field_type: &str) {
+        self.write_line(&format!("pub {}: {},", name, field_type));
+    }
+
+    pub fn field_decl_vis(&mut self, vis: Visibility, name: &str, field_type: &str) {
+        match vis {
+            Visibility::Public => self.pub_field_decl(name, field_type),
+            Visibility::Default => self.field_decl(name, field_type),
+        }
+    }
+
+    pub fn derive(&mut self, derive: &[&str]) {
+        let v: Vec<String> = derive.iter().map(|&s| s.to_string()).collect();
+        self.write_line(&format!("#[derive({})]", v.join(",")));
+    }
+
+    pub fn allow(&mut self, what: &[&str]) {
+        let v: Vec<String> = what.iter().map(|&s| s.to_string()).collect();
+        self.write_line(&format!("#[allow({})]", v.join(",")));
+    }
+
+    pub fn comment(&mut self, comment: &str) {
+        if comment.is_empty() {
+            self.write_line("//");
+        } else {
+            self.write_line(&format!("// {}", comment));
+        }
+    }
+
+    pub fn fn_def(&mut self, sig: &str) {
+        self.write_line(&format!("fn {};", sig));
+    }
+
+    pub fn fn_block<F>(&mut self, public: bool, sig: &str, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        if public {
+            self.expr_block(&format!("pub fn {}", sig), cb);
+        } else {
+            self.expr_block(&format!("fn {}", sig), cb);
+        }
+    }
+
+    pub fn pub_fn<F>(&mut self, sig: &str, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.fn_block(true, sig, cb);
+    }
+
+    pub fn def_fn<F>(&mut self, sig: &str, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.fn_block(false, sig, cb);
+    }
+
+    pub fn def_mod<F>(&mut self, name: &str, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.expr_block(&format!("mod {}", name), cb)
+    }
+
+    pub fn pub_mod<F>(&mut self, name: &str, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.expr_block(&format!("pub mod {}", name), cb)
+    }
+
+    pub fn while_block<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.expr_block(&format!("while {}", cond.as_ref()), cb);
+    }
+
+    // if ... { ... }
+    pub fn if_stmt<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.expr_block(&format!("if {}", cond.as_ref()), cb);
+    }
+
+    // if ... {} else { ... }
+    pub fn if_else_stmt<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.write_line(&format!("if {} {{", cond.as_ref()));
+        self.write_line("} else {");
+        self.indented(cb);
+        self.write_line("}");
+    }
+
+    // if let ... = ... { ... }
+    pub fn if_let_stmt<F>(&mut self, decl: &str, expr: &str, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.if_stmt(&format!("let {} = {}", decl, expr), cb);
+    }
+
+    // if let ... = ... { } else { ... }
+    pub fn if_let_else_stmt<F>(&mut self, decl: &str, expr: &str, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.if_else_stmt(&format!("let {} = {}", decl, expr), cb);
+    }
+
+    pub fn for_stmt<S1: AsRef<str>, S2: AsRef<str>, F>(&mut self, over: S1, varn: S2, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.stmt_block(&format!("for {} in {}", varn.as_ref(), over.as_ref()), cb)
+    }
+
+    pub fn match_block<S: AsRef<str>, F>(&mut self, value: S, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.stmt_block(&format!("match {}", value.as_ref()), cb);
+    }
+
+    pub fn match_expr<S: AsRef<str>, F>(&mut self, value: S, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.expr_block(&format!("match {}", value.as_ref()), cb);
+    }
+
+    pub fn case_block<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        self.block(&format!("{} => {{", cond.as_ref()), "},", cb);
+    }
+
+    pub fn case_expr<S1: AsRef<str>, S2: AsRef<str>>(&mut self, cond: S1, body: S2) {
+        self.write_line(&format!("{} => {},", cond.as_ref(), body.as_ref()));
+    }
+}
diff --git a/src/customize.rs b/src/customize.rs
new file mode 100644
index 0000000..c55fb07
--- /dev/null
+++ b/src/customize.rs
@@ -0,0 +1,199 @@
+use protobuf::descriptor::FieldOptions;
+use protobuf::descriptor::FileOptions;
+use protobuf::descriptor::MessageOptions;
+use protobuf::rustproto;
+
+/// Specifies style of generated code.
+#[derive(Default, Debug, Clone)]
+pub struct Customize {
+    /// Make oneof enum public.
+    pub expose_oneof: Option<bool>,
+    /// When true all fields are public, and accessors are not generated
+    pub expose_fields: Option<bool>,
+    /// When false, `get_`, `set_`, `mut_` etc. accessors are not generated
+    pub generate_accessors: Option<bool>,
+    /// Use `bytes::Bytes` for `bytes` fields
+    pub carllerche_bytes_for_bytes: Option<bool>,
+    /// Use `bytes::Bytes` for `string` fields
+    pub carllerche_bytes_for_string: Option<bool>,
+    /// Implement serde_derive for messages
+    pub serde_derive: Option<bool>,
+    /// When `serde_derive` is set, serde annotations will be guarded with `#[cfg(cfg, ...)]`.
+    pub serde_derive_cfg: Option<String>,
+    /// Enable lite runtime
+    pub lite_runtime: Option<bool>,
+    /// Used internally to generate protos bundled in protobuf crate
+    /// like `descriptor.proto`
+    pub inside_protobuf: Option<bool>,
+
+    // When adding more options please keep in sync with `parse_from_parameter` below.
+    /// Make sure `Customize` is always used with `..Default::default()`
+    /// for future compatibility.
+    pub _future_options: (),
+}
+
+#[derive(Debug)]
+pub enum CustomizeParseParameterError {
+    EqNotFound,
+    CannotParseBool,
+    UnknownOptionName(String),
+}
+
+pub type CustomizeParseParameterResult<T> = Result<T, CustomizeParseParameterError>;
+
+impl Customize {
+    /// Update fields of self with fields defined in other customize
+    pub fn update_with(&mut self, that: &Customize) {
+        if let Some(v) = that.expose_oneof {
+            self.expose_oneof = Some(v);
+        }
+        if let Some(v) = that.expose_fields {
+            self.expose_fields = Some(v);
+        }
+        if let Some(v) = that.generate_accessors {
+            self.generate_accessors = Some(v);
+        }
+        if let Some(v) = that.carllerche_bytes_for_bytes {
+            self.carllerche_bytes_for_bytes = Some(v);
+        }
+        if let Some(v) = that.carllerche_bytes_for_string {
+            self.carllerche_bytes_for_string = Some(v);
+        }
+        if let Some(v) = that.serde_derive {
+            self.serde_derive = Some(v);
+        }
+        if let Some(ref v) = that.serde_derive_cfg {
+            self.serde_derive_cfg = Some(v.clone());
+        }
+        if let Some(v) = that.lite_runtime {
+            self.lite_runtime = Some(v);
+        }
+        if let Some(v) = that.inside_protobuf {
+            self.inside_protobuf = Some(v);
+        }
+    }
+
+    /// Update unset fields of self with fields from other customize
+    pub fn set_defaults_from(&mut self, other: &Customize) {
+        let mut tmp = other.clone();
+        tmp.update_with(self);
+        *self = tmp;
+    }
+
+    /// Parse customize options from a string passed via protoc flag.
+    pub fn parse_from_parameter(parameter: &str) -> CustomizeParseParameterResult<Customize> {
+        fn parse_bool(v: &str) -> CustomizeParseParameterResult<bool> {
+            v.parse()
+                .map_err(|_| CustomizeParseParameterError::CannotParseBool)
+        }
+
+        let mut r = Customize::default();
+        for nv in parameter.split_whitespace() {
+            let eq = match nv.find('=') {
+                Some(eq) => eq,
+                None => return Err(CustomizeParseParameterError::EqNotFound),
+            };
+
+            let n = &nv[..eq];
+            let v = &nv[eq + 1..];
+
+            if n == "expose_oneof" {
+                r.expose_oneof = Some(parse_bool(v)?);
+            } else if n == "expose_fields" {
+                r.expose_fields = Some(parse_bool(v)?);
+            } else if n == "generate_accessors" {
+                r.generate_accessors = Some(parse_bool(v)?);
+            } else if n == "carllerche_bytes_for_bytes" {
+                r.carllerche_bytes_for_bytes = Some(parse_bool(v)?);
+            } else if n == "carllerche_bytes_for_string" {
+                r.carllerche_bytes_for_string = Some(parse_bool(v)?);
+            } else if n == "serde_derive" {
+                r.serde_derive = Some(parse_bool(v)?);
+            } else if n == "serde_derive_cfg" {
+                r.serde_derive_cfg = Some(v.to_owned());
+            } else if n == "lite_runtime" {
+                r.lite_runtime = Some(parse_bool(v)?);
+            } else if n == "inside_protobuf" {
+                r.inside_protobuf = Some(parse_bool(v)?);
+            } else {
+                return Err(CustomizeParseParameterError::UnknownOptionName(
+                    n.to_owned(),
+                ));
+            }
+        }
+        Ok(r)
+    }
+}
+
+pub fn customize_from_rustproto_for_message(source: &MessageOptions) -> Customize {
+    let expose_oneof = rustproto::exts::expose_oneof.get(source);
+    let expose_fields = rustproto::exts::expose_fields.get(source);
+    let generate_accessors = rustproto::exts::generate_accessors.get(source);
+    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes.get(source);
+    let carllerche_bytes_for_string = rustproto::exts::carllerche_bytes_for_string.get(source);
+    let serde_derive = rustproto::exts::serde_derive.get(source);
+    let serde_derive_cfg = rustproto::exts::serde_derive_cfg.get(source);
+    let lite_runtime = None;
+    let inside_protobuf = None;
+    Customize {
+        expose_oneof,
+        expose_fields,
+        generate_accessors,
+        carllerche_bytes_for_bytes,
+        carllerche_bytes_for_string,
+        serde_derive,
+        serde_derive_cfg,
+        lite_runtime,
+        inside_protobuf,
+        _future_options: (),
+    }
+}
+
+pub fn customize_from_rustproto_for_field(source: &FieldOptions) -> Customize {
+    let expose_oneof = None;
+    let expose_fields = rustproto::exts::expose_fields_field.get(source);
+    let generate_accessors = rustproto::exts::generate_accessors_field.get(source);
+    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes_field.get(source);
+    let carllerche_bytes_for_string =
+        rustproto::exts::carllerche_bytes_for_string_field.get(source);
+    let serde_derive = None;
+    let serde_derive_cfg = None;
+    let lite_runtime = None;
+    let inside_protobuf = None;
+    Customize {
+        expose_oneof,
+        expose_fields,
+        generate_accessors,
+        carllerche_bytes_for_bytes,
+        carllerche_bytes_for_string,
+        serde_derive,
+        serde_derive_cfg,
+        lite_runtime,
+        inside_protobuf,
+        _future_options: (),
+    }
+}
+
+pub fn customize_from_rustproto_for_file(source: &FileOptions) -> Customize {
+    let expose_oneof = rustproto::exts::expose_oneof_all.get(source);
+    let expose_fields = rustproto::exts::expose_fields_all.get(source);
+    let generate_accessors = rustproto::exts::generate_accessors_all.get(source);
+    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes_all.get(source);
+    let carllerche_bytes_for_string = rustproto::exts::carllerche_bytes_for_string_all.get(source);
+    let serde_derive = rustproto::exts::serde_derive_all.get(source);
+    let serde_derive_cfg = rustproto::exts::serde_derive_cfg_all.get(source);
+    let lite_runtime = rustproto::exts::lite_runtime_all.get(source);
+    let inside_protobuf = None;
+    Customize {
+        expose_oneof,
+        expose_fields,
+        generate_accessors,
+        carllerche_bytes_for_bytes,
+        carllerche_bytes_for_string,
+        serde_derive,
+        serde_derive_cfg,
+        lite_runtime,
+        inside_protobuf,
+        _future_options: (),
+    }
+}
diff --git a/src/enums.rs b/src/enums.rs
new file mode 100644
index 0000000..2c60f0c
--- /dev/null
+++ b/src/enums.rs
@@ -0,0 +1,324 @@
+use std::collections::HashSet;
+
+use protobuf::descriptor::*;
+
+use super::code_writer::*;
+use super::customize::Customize;
+use file_descriptor::file_descriptor_proto_expr;
+use protobuf_name::ProtobufAbsolutePath;
+use rust_types_values::type_name_to_rust_relative;
+use scope::EnumWithScope;
+use scope::RootScope;
+use scope::WithScope;
+use serde;
+
+#[derive(Clone)]
+pub struct EnumValueGen {
+    proto: EnumValueDescriptorProto,
+    enum_rust_name: String,
+    variant_rust_name: String,
+}
+
+impl EnumValueGen {
+    fn parse(
+        proto: &EnumValueDescriptorProto,
+        enum_rust_name: &str,
+        variant_rust_name: &str,
+    ) -> EnumValueGen {
+        EnumValueGen {
+            proto: proto.clone(),
+            enum_rust_name: enum_rust_name.to_string(),
+            variant_rust_name: variant_rust_name.to_string(),
+        }
+    }
+
+    // enum value
+    fn number(&self) -> i32 {
+        self.proto.get_number()
+    }
+
+    // name of enum variant in generated rust code
+    fn rust_name_inner(&self) -> String {
+        self.variant_rust_name.clone()
+    }
+
+    pub fn rust_name_outer(&self) -> String {
+        let mut r = String::new();
+        r.push_str(&self.enum_rust_name);
+        r.push_str("::");
+        r.push_str(&self.rust_name_inner());
+        r
+    }
+}
+
+pub(crate) struct EnumGen<'a> {
+    enum_with_scope: &'a EnumWithScope<'a>,
+    type_name: String,
+    lite_runtime: bool,
+    customize: Customize,
+}
+
+impl<'a> EnumGen<'a> {
+    pub fn new(
+        enum_with_scope: &'a EnumWithScope<'a>,
+        current_file: &FileDescriptorProto,
+        customize: &Customize,
+        root_scope: &RootScope,
+    ) -> EnumGen<'a> {
+        let rust_name = if enum_with_scope.get_scope().get_file_descriptor().get_name()
+            == current_file.get_name()
+        {
+            // field type is a message or enum declared in the same file
+            enum_with_scope.rust_name().to_string()
+        } else {
+            type_name_to_rust_relative(
+                &ProtobufAbsolutePath::from(enum_with_scope.name_absolute()),
+                current_file,
+                false,
+                root_scope,
+            )
+            .to_string()
+        };
+        let lite_runtime = customize.lite_runtime.unwrap_or_else(|| {
+            enum_with_scope
+                .get_scope()
+                .get_file_descriptor()
+                .get_options()
+                .get_optimize_for()
+                == FileOptions_OptimizeMode::LITE_RUNTIME
+        });
+
+        EnumGen {
+            enum_with_scope,
+            type_name: rust_name,
+            lite_runtime,
+            customize: customize.clone(),
+        }
+    }
+
+    fn allow_alias(&self) -> bool {
+        self.enum_with_scope.en.get_options().get_allow_alias()
+    }
+
+    fn values_all(&self) -> Vec<EnumValueGen> {
+        let mut r = Vec::new();
+        for p in self.enum_with_scope.values() {
+            r.push(EnumValueGen::parse(
+                &p.proto,
+                &self.type_name,
+                p.rust_name().get(),
+            ));
+        }
+        r
+    }
+
+    pub fn values_unique(&self) -> Vec<EnumValueGen> {
+        let mut used = HashSet::new();
+        let mut r = Vec::new();
+        for p in self.enum_with_scope.values() {
+            // skipping non-unique enums
+            // TODO: should support it
+            if !used.insert(p.proto.get_number()) {
+                continue;
+            }
+            r.push(EnumValueGen::parse(
+                p.proto,
+                &self.type_name,
+                p.rust_name().get(),
+            ));
+        }
+        r
+    }
+
+    // find enum value by name
+    pub fn value_by_name(&'a self, name: &str) -> EnumValueGen {
+        let v = self.enum_with_scope.value_by_name(name);
+        EnumValueGen::parse(v.proto, &self.type_name, v.rust_name().get())
+    }
+
+    pub fn write(&self, w: &mut CodeWriter) {
+        self.write_struct(w);
+        if self.allow_alias() {
+            w.write_line("");
+            self.write_impl_eq(w);
+            w.write_line("");
+            self.write_impl_hash(w);
+        }
+        w.write_line("");
+        self.write_impl_enum(w);
+        w.write_line("");
+        self.write_impl_copy(w);
+        w.write_line("");
+        self.write_impl_default(w);
+        w.write_line("");
+        self.write_impl_value(w);
+    }
+
+    fn write_struct(&self, w: &mut CodeWriter) {
+        let mut derive = Vec::new();
+        derive.push("Clone");
+        if !self.allow_alias() {
+            derive.push("PartialEq");
+        }
+        derive.push("Eq");
+        derive.push("Debug");
+        if !self.allow_alias() {
+            derive.push("Hash");
+        } else {
+            w.comment("Note: you cannot use pattern matching for enums with allow_alias option");
+        }
+        w.derive(&derive);
+        serde::write_serde_attr(w, &self.customize, "derive(Serialize, Deserialize)");
+        let ref type_name = self.type_name;
+        w.expr_block(&format!("pub enum {}", type_name), |w| {
+            for value in self.values_all() {
+                if self.allow_alias() {
+                    w.write_line(&format!(
+                        "{}, // {}",
+                        value.rust_name_inner(),
+                        value.number()
+                    ));
+                } else {
+                    w.write_line(&format!(
+                        "{} = {},",
+                        value.rust_name_inner(),
+                        value.number()
+                    ));
+                }
+            }
+        });
+    }
+
+    fn write_fn_value(&self, w: &mut CodeWriter) {
+        w.def_fn("value(&self) -> i32", |w| {
+            if self.allow_alias() {
+                w.match_expr("*self", |w| {
+                    for value in self.values_all() {
+                        w.case_expr(value.rust_name_outer(), format!("{}", value.number()));
+                    }
+                });
+            } else {
+                w.write_line("*self as i32")
+            }
+        });
+    }
+
+    fn write_impl_enum(&self, w: &mut CodeWriter) {
+        let ref type_name = self.type_name;
+        w.impl_for_block("::protobuf::ProtobufEnum", &type_name, |w| {
+            self.write_fn_value(w);
+
+            w.write_line("");
+            let ref type_name = self.type_name;
+            w.def_fn(
+                &format!(
+                    "from_i32(value: i32) -> ::std::option::Option<{}>",
+                    type_name
+                ),
+                |w| {
+                    w.match_expr("value", |w| {
+                        let values = self.values_unique();
+                        for value in values {
+                            w.write_line(&format!(
+                                "{} => ::std::option::Option::Some({}),",
+                                value.number(),
+                                value.rust_name_outer()
+                            ));
+                        }
+                        w.write_line(&format!("_ => ::std::option::Option::None"));
+                    });
+                },
+            );
+
+            w.write_line("");
+            w.def_fn(&format!("values() -> &'static [Self]"), |w| {
+                w.write_line(&format!("static values: &'static [{}] = &[", type_name));
+                w.indented(|w| {
+                    for value in self.values_all() {
+                        w.write_line(&format!("{},", value.rust_name_outer()));
+                    }
+                });
+                w.write_line("];");
+                w.write_line("values");
+            });
+
+            if !self.lite_runtime {
+                w.write_line("");
+                w.def_fn(
+                    &format!(
+                        "enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor"
+                    ),
+                    |w| {
+                        w.lazy_static_decl_get(
+                            "descriptor",
+                            "::protobuf::reflect::EnumDescriptor",
+                            |w| {
+                                let ref type_name = self.type_name;
+                                w.write_line(&format!(
+                                    "::protobuf::reflect::EnumDescriptor::new_pb_name::<{}>(\"{}\", {})",
+                                    type_name,
+                                    self.enum_with_scope.name_to_package(),
+                                    file_descriptor_proto_expr(&self.enum_with_scope.scope)
+                                ));
+                            },
+                        );
+                    },
+                );
+            }
+        });
+    }
+
+    fn write_impl_value(&self, w: &mut CodeWriter) {
+        w.impl_for_block("::protobuf::reflect::ProtobufValue", &self.type_name, |w| {
+            w.def_fn(
+                "as_ref(&self) -> ::protobuf::reflect::ReflectValueRef",
+                |w| w.write_line("::protobuf::reflect::ReflectValueRef::Enum(self.descriptor())"),
+            )
+        })
+    }
+
+    fn write_impl_copy(&self, w: &mut CodeWriter) {
+        w.impl_for_block("::std::marker::Copy", &self.type_name, |_w| {});
+    }
+
+    fn write_impl_eq(&self, w: &mut CodeWriter) {
+        assert!(self.allow_alias());
+        w.impl_for_block("::std::cmp::PartialEq", &self.type_name, |w| {
+            w.def_fn("eq(&self, other: &Self) -> bool", |w| {
+                w.write_line("self.value() == other.value()");
+            });
+        });
+    }
+
+    fn write_impl_hash(&self, w: &mut CodeWriter) {
+        assert!(self.allow_alias());
+        w.impl_for_block("::std::hash::Hash", &self.type_name, |w| {
+            w.def_fn("hash<H : ::std::hash::Hasher>(&self, state: &mut H)", |w| {
+                w.write_line("state.write_i32(self.value())");
+            });
+        });
+    }
+
+    fn write_impl_default(&self, w: &mut CodeWriter) {
+        let first_value = &self.enum_with_scope.values()[0];
+        if first_value.proto.get_number() != 0 {
+            // This warning is emitted only for proto2
+            // (because in proto3 first enum variant number is always 0).
+            // `Default` implemented unconditionally to simplify certain
+            // generic operations, e. g. reading a map.
+            // Also, note that even in proto2 some operations fallback to
+            // first enum value, e. g. `get_xxx` for unset field,
+            // so this implementation is not completely unreasonable.
+            w.comment("Note, `Default` is implemented although default value is not 0");
+        }
+        w.impl_for_block("::std::default::Default", &self.type_name, |w| {
+            w.def_fn("default() -> Self", |w| {
+                w.write_line(&format!(
+                    "{}::{}",
+                    &self.type_name,
+                    &first_value.rust_name()
+                ))
+            });
+        });
+    }
+}
diff --git a/src/extensions.rs b/src/extensions.rs
new file mode 100644
index 0000000..a3f8901
--- /dev/null
+++ b/src/extensions.rs
@@ -0,0 +1,109 @@
+use super::code_writer::CodeWriter;
+use super::rust_types_values::*;
+use field::rust_field_name_for_protobuf_field_name;
+use protobuf::descriptor::*;
+use protobuf_name::ProtobufAbsolutePath;
+use scope::RootScope;
+use Customize;
+
+struct ExtGen<'a> {
+    file: &'a FileDescriptorProto,
+    root_scope: &'a RootScope<'a>,
+    field: &'a FieldDescriptorProto,
+    customize: Customize,
+}
+
+impl<'a> ExtGen<'a> {
+    fn extendee_rust_name(&self) -> String {
+        type_name_to_rust_relative(
+            &ProtobufAbsolutePath::from(self.field.get_extendee()),
+            self.file,
+            true,
+            self.root_scope,
+        )
+    }
+
+    fn repeated(&self) -> bool {
+        match self.field.get_label() {
+            FieldDescriptorProto_Label::LABEL_REPEATED => true,
+            FieldDescriptorProto_Label::LABEL_OPTIONAL => false,
+            FieldDescriptorProto_Label::LABEL_REQUIRED => {
+                panic!("required ext field: {}", self.field.get_name())
+            }
+        }
+    }
+
+    fn return_type_gen(&self) -> ProtobufTypeGen {
+        if self.field.has_type_name() {
+            let rust_name_relative = type_name_to_rust_relative(
+                &ProtobufAbsolutePath::from(self.field.get_type_name()),
+                self.file,
+                true,
+                self.root_scope,
+            );
+            match self.field.get_field_type() {
+                FieldDescriptorProto_Type::TYPE_MESSAGE => {
+                    ProtobufTypeGen::Message(rust_name_relative)
+                }
+                FieldDescriptorProto_Type::TYPE_ENUM => ProtobufTypeGen::Enum(rust_name_relative),
+                t => panic!("unknown type: {:?}", t),
+            }
+        } else {
+            ProtobufTypeGen::Primitive(self.field.get_field_type(), PrimitiveTypeVariant::Default)
+        }
+    }
+
+    fn write(&self, w: &mut CodeWriter) {
+        let suffix = if self.repeated() {
+            "Repeated"
+        } else {
+            "Optional"
+        };
+        let field_type = format!("::protobuf::ext::ExtField{}", suffix);
+        w.pub_const(
+            rust_field_name_for_protobuf_field_name(self.field.get_name()).get(),
+            &format!(
+                "{}<{}, {}>",
+                field_type,
+                self.extendee_rust_name(),
+                self.return_type_gen().rust_type(&self.customize),
+            ),
+            &format!(
+                "{} {{ field_number: {}, phantom: ::std::marker::PhantomData }}",
+                field_type,
+                self.field.get_number()
+            ),
+        );
+    }
+}
+
+pub(crate) fn write_extensions(
+    file: &FileDescriptorProto,
+    root_scope: &RootScope,
+    w: &mut CodeWriter,
+    customize: &Customize,
+) {
+    if file.get_extension().is_empty() {
+        return;
+    }
+
+    w.write_line("");
+    w.pub_mod("exts", |w| {
+        w.write_line("use protobuf::Message as Message_imported_for_functions;");
+
+        for field in file.get_extension() {
+            if field.get_field_type() == FieldDescriptorProto_Type::TYPE_GROUP {
+                continue;
+            }
+
+            w.write_line("");
+            ExtGen {
+                file: file,
+                root_scope: root_scope,
+                field: field,
+                customize: customize.clone(),
+            }
+            .write(w);
+        }
+    });
+}
diff --git a/src/field/mod.rs b/src/field/mod.rs
new file mode 100644
index 0000000..37d4fe3
--- /dev/null
+++ b/src/field/mod.rs
@@ -0,0 +1,1996 @@
+use protobuf::descriptor::*;
+use protobuf::rt;
+use protobuf::rust;
+use protobuf::text_format;
+use protobuf::wire_format;
+
+use super::code_writer::CodeWriter;
+use super::enums::*;
+use super::rust_types_values::*;
+
+use super::customize::customize_from_rustproto_for_field;
+use super::customize::Customize;
+use oneof::OneofField;
+
+use float;
+use inside::protobuf_crate_path;
+use protobuf_name::ProtobufAbsolutePath;
+use rust_name::RustIdent;
+use scope::FieldWithContext;
+use scope::MessageOrEnumWithScope;
+use scope::RootScope;
+use scope::WithScope;
+use std::marker;
+use syntax::Syntax;
+
+fn type_is_copy(field_type: FieldDescriptorProto_Type) -> bool {
+    match field_type {
+        FieldDescriptorProto_Type::TYPE_MESSAGE
+        | FieldDescriptorProto_Type::TYPE_STRING
+        | FieldDescriptorProto_Type::TYPE_BYTES => false,
+        _ => true,
+    }
+}
+
+trait FieldDescriptorProtoTypeExt {
+    fn read(&self, is: &str, primitive_type_variant: PrimitiveTypeVariant) -> String;
+    fn is_s_varint(&self) -> bool;
+}
+
+impl FieldDescriptorProtoTypeExt for FieldDescriptorProto_Type {
+    fn read(&self, is: &str, primitive_type_variant: PrimitiveTypeVariant) -> String {
+        match primitive_type_variant {
+            PrimitiveTypeVariant::Default => format!("{}.read_{}()", is, protobuf_name(*self)),
+            PrimitiveTypeVariant::Carllerche => {
+                let protobuf_name = match self {
+                    &FieldDescriptorProto_Type::TYPE_STRING => "chars",
+                    _ => protobuf_name(*self),
+                };
+                format!("{}.read_carllerche_{}()", is, protobuf_name)
+            }
+        }
+    }
+
+    /// True if self is signed integer with zigzag encoding
+    fn is_s_varint(&self) -> bool {
+        match *self {
+            FieldDescriptorProto_Type::TYPE_SINT32 | FieldDescriptorProto_Type::TYPE_SINT64 => true,
+            _ => false,
+        }
+    }
+}
+
+fn field_type_wire_type(field_type: FieldDescriptorProto_Type) -> wire_format::WireType {
+    use protobuf::stream::wire_format::*;
+    match field_type {
+        FieldDescriptorProto_Type::TYPE_INT32 => WireTypeVarint,
+        FieldDescriptorProto_Type::TYPE_INT64 => WireTypeVarint,
+        FieldDescriptorProto_Type::TYPE_UINT32 => WireTypeVarint,
+        FieldDescriptorProto_Type::TYPE_UINT64 => WireTypeVarint,
+        FieldDescriptorProto_Type::TYPE_SINT32 => WireTypeVarint,
+        FieldDescriptorProto_Type::TYPE_SINT64 => WireTypeVarint,
+        FieldDescriptorProto_Type::TYPE_BOOL => WireTypeVarint,
+        FieldDescriptorProto_Type::TYPE_ENUM => WireTypeVarint,
+        FieldDescriptorProto_Type::TYPE_FIXED32 => WireTypeFixed32,
+        FieldDescriptorProto_Type::TYPE_FIXED64 => WireTypeFixed64,
+        FieldDescriptorProto_Type::TYPE_SFIXED32 => WireTypeFixed32,
+        FieldDescriptorProto_Type::TYPE_SFIXED64 => WireTypeFixed64,
+        FieldDescriptorProto_Type::TYPE_FLOAT => WireTypeFixed32,
+        FieldDescriptorProto_Type::TYPE_DOUBLE => WireTypeFixed64,
+        FieldDescriptorProto_Type::TYPE_STRING => WireTypeLengthDelimited,
+        FieldDescriptorProto_Type::TYPE_BYTES => WireTypeLengthDelimited,
+        FieldDescriptorProto_Type::TYPE_MESSAGE => WireTypeLengthDelimited,
+        FieldDescriptorProto_Type::TYPE_GROUP => WireTypeLengthDelimited, // not true
+    }
+}
+
+fn type_protobuf_name(field_type: FieldDescriptorProto_Type) -> &'static str {
+    match field_type {
+        FieldDescriptorProto_Type::TYPE_INT32 => "int32",
+        FieldDescriptorProto_Type::TYPE_INT64 => "int64",
+        FieldDescriptorProto_Type::TYPE_UINT32 => "uint32",
+        FieldDescriptorProto_Type::TYPE_UINT64 => "uint64",
+        FieldDescriptorProto_Type::TYPE_SINT32 => "sint32",
+        FieldDescriptorProto_Type::TYPE_SINT64 => "sint64",
+        FieldDescriptorProto_Type::TYPE_BOOL => "bool",
+        FieldDescriptorProto_Type::TYPE_FIXED32 => "fixed32",
+        FieldDescriptorProto_Type::TYPE_FIXED64 => "fixed64",
+        FieldDescriptorProto_Type::TYPE_SFIXED32 => "sfixed32",
+        FieldDescriptorProto_Type::TYPE_SFIXED64 => "sfixed64",
+        FieldDescriptorProto_Type::TYPE_FLOAT => "float",
+        FieldDescriptorProto_Type::TYPE_DOUBLE => "double",
+        FieldDescriptorProto_Type::TYPE_STRING => "string",
+        FieldDescriptorProto_Type::TYPE_BYTES => "bytes",
+        FieldDescriptorProto_Type::TYPE_ENUM
+        | FieldDescriptorProto_Type::TYPE_MESSAGE
+        | FieldDescriptorProto_Type::TYPE_GROUP => panic!(),
+    }
+}
+
+fn field_type_protobuf_name<'a>(field: &'a FieldDescriptorProto) -> &'a str {
+    if field.has_type_name() {
+        field.get_type_name()
+    } else {
+        type_protobuf_name(field.get_field_type())
+    }
+}
+
+// size of value for type, None if variable
+fn field_type_size(field_type: FieldDescriptorProto_Type) -> Option<u32> {
+    match field_type {
+        FieldDescriptorProto_Type::TYPE_BOOL => Some(1),
+        t if field_type_wire_type(t) == wire_format::WireTypeFixed32 => Some(4),
+        t if field_type_wire_type(t) == wire_format::WireTypeFixed64 => Some(8),
+        _ => None,
+    }
+}
+
+#[derive(Clone, PartialEq, Eq)]
+pub enum SingularFieldFlag {
+    // proto2 or proto3 message
+    WithFlag { required: bool },
+    // proto3
+    WithoutFlag,
+}
+
+impl SingularFieldFlag {
+    pub fn is_required(&self) -> bool {
+        match *self {
+            SingularFieldFlag::WithFlag { required, .. } => required,
+            SingularFieldFlag::WithoutFlag => false,
+        }
+    }
+}
+
+#[derive(Clone)]
+pub(crate) struct SingularField<'a> {
+    pub flag: SingularFieldFlag,
+    pub elem: FieldElem<'a>,
+}
+
+impl<'a> SingularField<'a> {
+    fn rust_storage_type(&self) -> RustType {
+        match self.flag {
+            SingularFieldFlag::WithFlag { .. } => match self.elem.proto_type() {
+                FieldDescriptorProto_Type::TYPE_MESSAGE => {
+                    RustType::SingularPtrField(Box::new(self.elem.rust_storage_type()))
+                }
+                FieldDescriptorProto_Type::TYPE_STRING | FieldDescriptorProto_Type::TYPE_BYTES
+                    if self.elem.primitive_type_variant() == PrimitiveTypeVariant::Default =>
+                {
+                    RustType::SingularField(Box::new(self.elem.rust_storage_type()))
+                }
+                _ => RustType::Option(Box::new(self.elem.rust_storage_type())),
+            },
+            SingularFieldFlag::WithoutFlag => self.elem.rust_storage_type(),
+        }
+    }
+}
+
+#[derive(Clone)]
+pub(crate) struct RepeatedField<'a> {
+    pub elem: FieldElem<'a>,
+    pub packed: bool,
+}
+
+impl<'a> RepeatedField<'a> {
+    fn rust_type(&self) -> RustType {
+        if !self.elem.is_copy()
+            && self.elem.primitive_type_variant() != PrimitiveTypeVariant::Carllerche
+        {
+            RustType::RepeatedField(Box::new(self.elem.rust_storage_type()))
+        } else {
+            RustType::Vec(Box::new(self.elem.rust_storage_type()))
+        }
+    }
+}
+
+#[derive(Clone)]
+pub struct MapField<'a> {
+    name: String,
+    key: FieldElem<'a>,
+    value: FieldElem<'a>,
+}
+
+#[derive(Clone)]
+pub(crate) enum FieldKind<'a> {
+    // optional or required
+    Singular(SingularField<'a>),
+    // repeated except map
+    Repeated(RepeatedField<'a>),
+    // map
+    Map(MapField<'a>),
+    // part of oneof
+    Oneof(OneofField<'a>),
+}
+
+impl<'a> FieldKind<'a> {
+    fn elem(&self) -> &FieldElem {
+        match self {
+            &FieldKind::Singular(ref s) => &s.elem,
+            &FieldKind::Repeated(ref r) => &r.elem,
+            &FieldKind::Oneof(ref o) => &o.elem,
+            &FieldKind::Map(..) => {
+                panic!("no single elem type for map field");
+            }
+        }
+    }
+
+    fn primitive_type_variant(&self) -> PrimitiveTypeVariant {
+        self.elem().primitive_type_variant()
+    }
+}
+
+// Representation of map entry: key type and value type
+#[derive(Clone, Debug)]
+pub struct EntryKeyValue<'a>(FieldElem<'a>, FieldElem<'a>);
+
+#[derive(Clone, Debug)]
+pub(crate) enum FieldElem<'a> {
+    Primitive(FieldDescriptorProto_Type, PrimitiveTypeVariant),
+    // name, file name, entry
+    Message(
+        String,
+        String,
+        Option<Box<EntryKeyValue<'a>>>,
+        marker::PhantomData<&'a ()>,
+    ),
+    // name, file name, default value
+    Enum(String, String, RustIdent),
+    Group,
+}
+
+impl<'a> FieldElem<'a> {
+    fn proto_type(&self) -> FieldDescriptorProto_Type {
+        match *self {
+            FieldElem::Primitive(t, ..) => t,
+            FieldElem::Group => FieldDescriptorProto_Type::TYPE_GROUP,
+            FieldElem::Message(..) => FieldDescriptorProto_Type::TYPE_MESSAGE,
+            FieldElem::Enum(..) => FieldDescriptorProto_Type::TYPE_ENUM,
+        }
+    }
+
+    fn is_copy(&self) -> bool {
+        type_is_copy(self.proto_type())
+    }
+
+    pub fn rust_storage_type(&self) -> RustType {
+        match *self {
+            FieldElem::Primitive(t, PrimitiveTypeVariant::Default) => rust_name(t),
+            FieldElem::Primitive(
+                FieldDescriptorProto_Type::TYPE_STRING,
+                PrimitiveTypeVariant::Carllerche,
+            ) => RustType::Chars,
+            FieldElem::Primitive(
+                FieldDescriptorProto_Type::TYPE_BYTES,
+                PrimitiveTypeVariant::Carllerche,
+            ) => RustType::Bytes,
+            FieldElem::Primitive(.., PrimitiveTypeVariant::Carllerche) => unreachable!(),
+            FieldElem::Group => RustType::Group,
+            FieldElem::Message(ref name, ..) => RustType::Message(name.clone()),
+            FieldElem::Enum(ref name, _, ref default_value) => {
+                RustType::Enum(name.clone(), default_value.clone())
+            }
+        }
+    }
+
+    fn protobuf_type_gen(&self) -> ProtobufTypeGen {
+        match *self {
+            FieldElem::Primitive(t, v) => ProtobufTypeGen::Primitive(t, v),
+            FieldElem::Message(ref name, ..) => ProtobufTypeGen::Message(name.clone()),
+            FieldElem::Enum(ref name, ..) => ProtobufTypeGen::Enum(name.clone()),
+            FieldElem::Group => unreachable!(),
+        }
+    }
+
+    /// implementation of ProtobufType trait
+    fn lib_protobuf_type(&self, customize: &Customize) -> String {
+        self.protobuf_type_gen().rust_type(customize)
+    }
+
+    fn primitive_type_variant(&self) -> PrimitiveTypeVariant {
+        match self {
+            &FieldElem::Primitive(_, v) => v,
+            _ => PrimitiveTypeVariant::Default,
+        }
+    }
+}
+
+fn field_elem<'a>(
+    field: &FieldWithContext,
+    root_scope: &'a RootScope<'a>,
+    parse_map: bool,
+    customize: &Customize,
+) -> (FieldElem<'a>, Option<EnumValueGen>) {
+    if field.field.get_field_type() == FieldDescriptorProto_Type::TYPE_GROUP {
+        (FieldElem::Group, None)
+    } else if field.field.has_type_name() {
+        let message_or_enum = root_scope
+            .find_message_or_enum(&ProtobufAbsolutePath::from(field.field.get_type_name()));
+        let file_name = message_or_enum
+            .get_scope()
+            .file_scope
+            .file_descriptor
+            .get_name()
+            .to_owned();
+        let rust_relative_name = type_name_to_rust_relative(
+            &ProtobufAbsolutePath::from(field.field.get_type_name()),
+            field.message.get_scope().file_scope.file_descriptor,
+            false,
+            root_scope,
+        );
+        match (field.field.get_field_type(), message_or_enum) {
+            (
+                FieldDescriptorProto_Type::TYPE_MESSAGE,
+                MessageOrEnumWithScope::Message(message_with_scope),
+            ) => {
+                let entry_key_value = if let (true, Some((key, value))) =
+                    (parse_map, message_with_scope.map_entry())
+                {
+                    Some(Box::new(EntryKeyValue(
+                        field_elem(&key, root_scope, false, customize).0,
+                        field_elem(&value, root_scope, false, customize).0,
+                    )))
+                } else {
+                    None
+                };
+                (
+                    FieldElem::Message(
+                        rust_relative_name,
+                        file_name,
+                        entry_key_value,
+                        marker::PhantomData,
+                    ),
+                    None,
+                )
+            }
+            (
+                FieldDescriptorProto_Type::TYPE_ENUM,
+                MessageOrEnumWithScope::Enum(enum_with_scope),
+            ) => {
+                let e = EnumGen::new(
+                    &enum_with_scope,
+                    field.message.get_scope().get_file_descriptor(),
+                    customize,
+                    root_scope,
+                );
+                let ev = if field.field.has_default_value() {
+                    e.value_by_name(field.field.get_default_value()).clone()
+                } else {
+                    e.values_unique().into_iter().next().unwrap()
+                };
+                (
+                    FieldElem::Enum(
+                        rust_relative_name,
+                        file_name,
+                        RustIdent::from(enum_with_scope.values()[0].rust_name().to_owned()),
+                    ),
+                    Some(ev),
+                )
+            }
+            _ => panic!("unknown named type: {:?}", field.field.get_field_type()),
+        }
+    } else if field.field.has_field_type() {
+        let carllerche_for_bytes = customize.carllerche_bytes_for_bytes.unwrap_or(false);
+        let carllerche_for_string = customize.carllerche_bytes_for_string.unwrap_or(false);
+
+        let elem = match field.field.get_field_type() {
+            FieldDescriptorProto_Type::TYPE_STRING if carllerche_for_string => {
+                FieldElem::Primitive(
+                    FieldDescriptorProto_Type::TYPE_STRING,
+                    PrimitiveTypeVariant::Carllerche,
+                )
+            }
+            FieldDescriptorProto_Type::TYPE_BYTES if carllerche_for_bytes => FieldElem::Primitive(
+                FieldDescriptorProto_Type::TYPE_BYTES,
+                PrimitiveTypeVariant::Carllerche,
+            ),
+            t => FieldElem::Primitive(t, PrimitiveTypeVariant::Default),
+        };
+
+        (elem, None)
+    } else {
+        panic!(
+            "neither type_name, nor field_type specified for field: {}",
+            field.field.get_name()
+        );
+    }
+}
+
+pub enum AccessorStyle {
+    Lambda,
+    HasGet,
+}
+
+pub struct AccessorFn {
+    name: String,
+    type_params: Vec<String>,
+    pub style: AccessorStyle,
+}
+
+impl AccessorFn {
+    pub fn sig(&self) -> String {
+        let mut s = self.name.clone();
+        s.push_str("::<_");
+        for p in &self.type_params {
+            s.push_str(", ");
+            s.push_str(&p);
+        }
+        s.push_str(">");
+        s
+    }
+}
+
+#[derive(Clone)]
+pub(crate) struct FieldGen<'a> {
+    root_scope: &'a RootScope<'a>,
+    syntax: Syntax,
+    pub proto_field: FieldWithContext<'a>,
+    // field name in generated code
+    pub rust_name: RustIdent,
+    pub proto_type: FieldDescriptorProto_Type,
+    wire_type: wire_format::WireType,
+    enum_default_value: Option<EnumValueGen>,
+    pub kind: FieldKind<'a>,
+    pub expose_field: bool,
+    pub generate_accessors: bool,
+    pub(crate) customize: Customize,
+}
+
+impl<'a> FieldGen<'a> {
+    pub fn parse(
+        field: FieldWithContext<'a>,
+        root_scope: &'a RootScope<'a>,
+        customize: &Customize,
+    ) -> FieldGen<'a> {
+        let mut customize = customize.clone();
+        customize.update_with(&customize_from_rustproto_for_field(
+            &field.field.get_options(),
+        ));
+
+        let (elem, enum_default_value) = field_elem(&field, root_scope, true, &customize);
+
+        let generate_accessors = customize.generate_accessors.unwrap_or(true);
+
+        let default_expose_field =
+            field.message.scope.file_scope.syntax() == Syntax::PROTO3 || !generate_accessors;
+
+        let expose_field = customize.expose_fields.unwrap_or(default_expose_field);
+
+        let kind = if field.field.get_label() == FieldDescriptorProto_Label::LABEL_REPEATED {
+            match (elem, true) {
+                // map field
+                (FieldElem::Message(name, _, Some(key_value), _), true) => {
+                    FieldKind::Map(MapField {
+                        name: name,
+                        key: key_value.0.clone(),
+                        value: key_value.1.clone(),
+                    })
+                }
+                // regular repeated field
+                (elem, _) => FieldKind::Repeated(RepeatedField {
+                    elem,
+                    packed: field.field.get_options().get_packed(),
+                }),
+            }
+        } else if let Some(oneof) = field.oneof() {
+            FieldKind::Oneof(OneofField::parse(&oneof, &field, elem, root_scope))
+        } else {
+            let flag = if field.message.scope.file_scope.syntax() == Syntax::PROTO3
+                && field.field.get_field_type() != FieldDescriptorProto_Type::TYPE_MESSAGE
+            {
+                SingularFieldFlag::WithoutFlag
+            } else {
+                SingularFieldFlag::WithFlag {
+                    required: field.field.get_label() == FieldDescriptorProto_Label::LABEL_REQUIRED,
+                }
+            };
+            FieldKind::Singular(SingularField { elem, flag })
+        };
+
+        FieldGen {
+            root_scope,
+            syntax: field.message.get_scope().file_scope.syntax(),
+            rust_name: field.rust_name(),
+            proto_type: field.field.get_field_type(),
+            wire_type: field_type_wire_type(field.field.get_field_type()),
+            enum_default_value,
+            proto_field: field.clone(),
+            kind,
+            expose_field,
+            generate_accessors,
+            customize,
+        }
+    }
+
+    fn tag_size(&self) -> u32 {
+        rt::tag_size(self.proto_field.number())
+    }
+
+    pub fn is_oneof(&self) -> bool {
+        match self.kind {
+            FieldKind::Oneof(..) => true,
+            _ => false,
+        }
+    }
+
+    pub fn oneof(&self) -> &OneofField {
+        match self.kind {
+            FieldKind::Oneof(ref oneof) => &oneof,
+            _ => panic!("not a oneof field: {}", self.reconstruct_def()),
+        }
+    }
+
+    fn is_singular(&self) -> bool {
+        match self.kind {
+            FieldKind::Singular(..) => true,
+            _ => false,
+        }
+    }
+
+    fn is_repeated_not_map(&self) -> bool {
+        match self.kind {
+            FieldKind::Repeated(..) => true,
+            _ => false,
+        }
+    }
+
+    fn is_repeated_or_map(&self) -> bool {
+        match self.kind {
+            FieldKind::Repeated(..) | FieldKind::Map(..) => true,
+            _ => false,
+        }
+    }
+
+    fn is_repeated_packed(&self) -> bool {
+        match self.kind {
+            FieldKind::Repeated(RepeatedField { packed: true, .. }) => true,
+            _ => false,
+        }
+    }
+
+    #[allow(dead_code)]
+    fn repeated(&self) -> &RepeatedField {
+        match self.kind {
+            FieldKind::Repeated(ref repeated) => &repeated,
+            _ => panic!("not a repeated field: {}", self.reconstruct_def()),
+        }
+    }
+
+    fn singular(&self) -> &SingularField {
+        match self.kind {
+            FieldKind::Singular(ref singular) => &singular,
+            _ => panic!("not a singular field: {}", self.reconstruct_def()),
+        }
+    }
+
+    fn map(&self) -> &MapField {
+        match self.kind {
+            FieldKind::Map(ref map) => &map,
+            _ => panic!("not a map field: {}", self.reconstruct_def()),
+        }
+    }
+
+    fn variant_path(&self) -> String {
+        // TODO: should reuse code from OneofVariantGen
+        format!(
+            "{}::{}",
+            self.oneof().oneof_type_name.to_code(&self.customize),
+            self.rust_name
+        )
+    }
+
+    // TODO: drop it
+    pub fn elem(&self) -> &FieldElem {
+        match self.kind {
+            FieldKind::Singular(SingularField { ref elem, .. }) => &elem,
+            FieldKind::Repeated(RepeatedField { ref elem, .. }) => &elem,
+            FieldKind::Oneof(OneofField { ref elem, .. }) => &elem,
+            FieldKind::Map(..) => unreachable!(),
+        }
+    }
+
+    // type of field in struct
+    pub fn full_storage_type(&self) -> RustType {
+        match self.kind {
+            FieldKind::Repeated(ref repeated) => repeated.rust_type(),
+            FieldKind::Map(MapField {
+                ref key, ref value, ..
+            }) => RustType::HashMap(
+                Box::new(key.rust_storage_type()),
+                Box::new(value.rust_storage_type()),
+            ),
+            FieldKind::Singular(ref singular) => singular.rust_storage_type(),
+            FieldKind::Oneof(..) => unreachable!(),
+        }
+    }
+
+    // type of `v` in `for v in field`
+    fn full_storage_iter_elem_type(&self) -> RustType {
+        if let FieldKind::Oneof(ref oneof) = self.kind {
+            oneof.elem.rust_storage_type()
+        } else {
+            self.full_storage_type().iter_elem_type()
+        }
+    }
+
+    // suffix `xxx` as in `os.write_xxx_no_tag(..)`
+    fn os_write_fn_suffix(&self) -> &str {
+        protobuf_name(self.proto_type)
+    }
+
+    // type of `v` in `os.write_xxx_no_tag(v)`
+    fn os_write_fn_param_type(&self) -> RustType {
+        match self.proto_type {
+            FieldDescriptorProto_Type::TYPE_STRING => RustType::Ref(Box::new(RustType::Str)),
+            FieldDescriptorProto_Type::TYPE_BYTES => {
+                RustType::Ref(Box::new(RustType::Slice(Box::new(RustType::Int(false, 8)))))
+            }
+            FieldDescriptorProto_Type::TYPE_ENUM => RustType::Int(true, 32),
+            t => rust_name(t),
+        }
+    }
+
+    // for field `foo`, type of param of `fn set_foo(..)`
+    fn set_xxx_param_type(&self) -> RustType {
+        match self.kind {
+            FieldKind::Singular(SingularField { ref elem, .. })
+            | FieldKind::Oneof(OneofField { ref elem, .. }) => elem.rust_storage_type(),
+            FieldKind::Repeated(..) | FieldKind::Map(..) => self.full_storage_type(),
+        }
+    }
+
+    // for field `foo`, return type if `fn take_foo(..)`
+    fn take_xxx_return_type(&self) -> RustType {
+        self.set_xxx_param_type()
+    }
+
+    // for field `foo`, return type of `fn mut_foo(..)`
+    fn mut_xxx_return_type(&self) -> RustType {
+        RustType::Ref(Box::new(match self.kind {
+            FieldKind::Singular(SingularField { ref elem, .. })
+            | FieldKind::Oneof(OneofField { ref elem, .. }) => elem.rust_storage_type(),
+            FieldKind::Repeated(..) | FieldKind::Map(..) => self.full_storage_type(),
+        }))
+    }
+
+    // for field `foo`, return type of `fn get_foo(..)`
+    fn get_xxx_return_type(&self) -> RustType {
+        match self.kind {
+            FieldKind::Singular(SingularField { ref elem, .. })
+            | FieldKind::Oneof(OneofField { ref elem, .. }) => match elem.is_copy() {
+                true => elem.rust_storage_type(),
+                false => elem.rust_storage_type().ref_type(),
+            },
+            FieldKind::Repeated(RepeatedField { ref elem, .. }) => RustType::Ref(Box::new(
+                RustType::Slice(Box::new(elem.rust_storage_type())),
+            )),
+            FieldKind::Map(..) => RustType::Ref(Box::new(self.full_storage_type())),
+        }
+    }
+
+    // fixed size type?
+    fn is_fixed(&self) -> bool {
+        field_type_size(self.proto_type).is_some()
+    }
+
+    // must use zigzag encoding?
+    fn is_zigzag(&self) -> bool {
+        match self.proto_type {
+            FieldDescriptorProto_Type::TYPE_SINT32 | FieldDescriptorProto_Type::TYPE_SINT64 => true,
+            _ => false,
+        }
+    }
+
+    // data is enum
+    fn is_enum(&self) -> bool {
+        match self.proto_type {
+            FieldDescriptorProto_Type::TYPE_ENUM => true,
+            _ => false,
+        }
+    }
+
+    // elem data is not stored in heap
+    pub fn elem_type_is_copy(&self) -> bool {
+        type_is_copy(self.proto_type)
+    }
+
+    fn defaut_value_from_proto_float(&self) -> String {
+        assert!(self.proto_field.field.has_default_value());
+
+        let type_name = match self.proto_type {
+            FieldDescriptorProto_Type::TYPE_FLOAT => "f32",
+            FieldDescriptorProto_Type::TYPE_DOUBLE => "f64",
+            _ => unreachable!(),
+        };
+        let proto_default = self.proto_field.field.get_default_value();
+
+        let f = float::parse_protobuf_float(proto_default)
+            .expect(&format!("failed to parse float: {:?}", proto_default));
+
+        if f.is_nan() {
+            format!("::std::{}::NAN", type_name)
+        } else if f.is_infinite() {
+            if f > 0.0 {
+                format!("::std::{}::INFINITY", type_name)
+            } else {
+                format!("::std::{}::NEG_INFINITY", type_name)
+            }
+        } else {
+            format!("{:?}{}", f, type_name)
+        }
+    }
+
+    fn default_value_from_proto(&self) -> Option<String> {
+        assert!(self.is_singular() || self.is_oneof());
+        if self.enum_default_value.is_some() {
+            Some(self.enum_default_value.as_ref().unwrap().rust_name_outer())
+        } else if self.proto_field.field.has_default_value() {
+            let proto_default = self.proto_field.field.get_default_value();
+            Some(match self.proto_type {
+                // For numeric types, contains the original text representation of the value
+                FieldDescriptorProto_Type::TYPE_DOUBLE | FieldDescriptorProto_Type::TYPE_FLOAT => {
+                    self.defaut_value_from_proto_float()
+                }
+                FieldDescriptorProto_Type::TYPE_INT32
+                | FieldDescriptorProto_Type::TYPE_SINT32
+                | FieldDescriptorProto_Type::TYPE_SFIXED32 => format!("{}i32", proto_default),
+                FieldDescriptorProto_Type::TYPE_UINT32
+                | FieldDescriptorProto_Type::TYPE_FIXED32 => format!("{}u32", proto_default),
+                FieldDescriptorProto_Type::TYPE_INT64
+                | FieldDescriptorProto_Type::TYPE_SINT64
+                | FieldDescriptorProto_Type::TYPE_SFIXED64 => format!("{}i64", proto_default),
+                FieldDescriptorProto_Type::TYPE_UINT64
+                | FieldDescriptorProto_Type::TYPE_FIXED64 => format!("{}u64", proto_default),
+
+                // For booleans, "true" or "false"
+                FieldDescriptorProto_Type::TYPE_BOOL => format!("{}", proto_default),
+                // For strings, contains the default text contents (not escaped in any way)
+                FieldDescriptorProto_Type::TYPE_STRING => rust::quote_escape_str(proto_default),
+                // For bytes, contains the C escaped value.  All bytes >= 128 are escaped
+                FieldDescriptorProto_Type::TYPE_BYTES => {
+                    rust::quote_escape_bytes(&text_format::unescape_string(proto_default))
+                }
+                // TODO: resolve outer message prefix
+                FieldDescriptorProto_Type::TYPE_GROUP | FieldDescriptorProto_Type::TYPE_ENUM => {
+                    unreachable!()
+                }
+                FieldDescriptorProto_Type::TYPE_MESSAGE => panic!(
+                    "default value is not implemented for type: {:?}",
+                    self.proto_type
+                ),
+            })
+        } else {
+            None
+        }
+    }
+
+    fn default_value_from_proto_typed(&self) -> Option<RustValueTyped> {
+        self.default_value_from_proto().map(|v| {
+            let default_value_type = match self.proto_type {
+                FieldDescriptorProto_Type::TYPE_STRING => RustType::Ref(Box::new(RustType::Str)),
+                FieldDescriptorProto_Type::TYPE_BYTES => {
+                    RustType::Ref(Box::new(RustType::Slice(Box::new(RustType::u8()))))
+                }
+                _ => self.full_storage_iter_elem_type(),
+            };
+
+            RustValueTyped {
+                value: v,
+                rust_type: default_value_type,
+            }
+        })
+    }
+
+    // default value to be returned from fn get_xxx
+    fn get_xxx_default_value_rust(&self) -> String {
+        assert!(self.is_singular() || self.is_oneof());
+        self.default_value_from_proto()
+            .unwrap_or_else(|| self.get_xxx_return_type().default_value(&self.customize))
+    }
+
+    // default to be assigned to field
+    fn element_default_value_rust(&self) -> RustValueTyped {
+        assert!(
+            self.is_singular() || self.is_oneof(),
+            "field is not singular: {}",
+            self.reconstruct_def()
+        );
+        self.default_value_from_proto_typed().unwrap_or_else(|| {
+            self.elem()
+                .rust_storage_type()
+                .default_value_typed(&self.customize)
+        })
+    }
+
+    pub fn reconstruct_def(&self) -> String {
+        let prefix = match (self.proto_field.field.get_label(), self.syntax) {
+            (FieldDescriptorProto_Label::LABEL_REPEATED, _) => "repeated ",
+            (_, Syntax::PROTO3) => "",
+            (FieldDescriptorProto_Label::LABEL_OPTIONAL, _) => "optional ",
+            (FieldDescriptorProto_Label::LABEL_REQUIRED, _) => "required ",
+        };
+        format!(
+            "{}{} {} = {}",
+            prefix,
+            field_type_protobuf_name(&self.proto_field.field),
+            self.proto_field.name(),
+            self.proto_field.number()
+        )
+    }
+
+    pub fn accessor_fn(&self) -> AccessorFn {
+        match self.kind {
+            FieldKind::Repeated(RepeatedField { ref elem, .. }) => {
+                let coll = match self.full_storage_type() {
+                    RustType::Vec(..) => "vec",
+                    RustType::RepeatedField(..) => "repeated_field",
+                    _ => unreachable!(),
+                };
+                let name = format!("make_{}_accessor", coll);
+                AccessorFn {
+                    name: name,
+                    type_params: vec![elem.lib_protobuf_type(&self.customize)],
+                    style: AccessorStyle::Lambda,
+                }
+            }
+            FieldKind::Map(MapField {
+                ref key, ref value, ..
+            }) => AccessorFn {
+                name: "make_map_accessor".to_owned(),
+                type_params: vec![
+                    key.lib_protobuf_type(&self.customize),
+                    value.lib_protobuf_type(&self.customize),
+                ],
+                style: AccessorStyle::Lambda,
+            },
+            FieldKind::Singular(SingularField {
+                ref elem,
+                flag: SingularFieldFlag::WithoutFlag,
+            }) => {
+                if let &FieldElem::Message(ref name, ..) = elem {
+                    // TODO: old style, needed because of default instance
+
+                    AccessorFn {
+                        name: "make_singular_message_accessor".to_owned(),
+                        type_params: vec![name.clone()],
+                        style: AccessorStyle::HasGet,
+                    }
+                } else {
+                    AccessorFn {
+                        name: "make_simple_field_accessor".to_owned(),
+                        type_params: vec![elem.lib_protobuf_type(&self.customize)],
+                        style: AccessorStyle::Lambda,
+                    }
+                }
+            }
+            FieldKind::Singular(SingularField {
+                ref elem,
+                flag: SingularFieldFlag::WithFlag { .. },
+            }) => {
+                let coll = match self.full_storage_type() {
+                    RustType::Option(..) => "option",
+                    RustType::SingularField(..) => "singular_field",
+                    RustType::SingularPtrField(..) => "singular_ptr_field",
+                    _ => unreachable!(),
+                };
+                let name = format!("make_{}_accessor", coll);
+                AccessorFn {
+                    name: name,
+                    type_params: vec![elem.lib_protobuf_type(&self.customize)],
+                    style: AccessorStyle::Lambda,
+                }
+            }
+            FieldKind::Oneof(OneofField { ref elem, .. }) => {
+                // TODO: uses old style
+
+                let suffix = match &self.elem().rust_storage_type() {
+                    t if t.is_primitive() => t.to_code(&self.customize),
+                    &RustType::String | &RustType::Chars => "string".to_string(),
+                    &RustType::Vec(ref t) if t.is_u8() => "bytes".to_string(),
+                    &RustType::Bytes => "bytes".to_string(),
+                    &RustType::Enum(..) => "enum".to_string(),
+                    &RustType::Message(..) => "message".to_string(),
+                    t => panic!("unexpected field type: {:?}", t),
+                };
+
+                let name = format!("make_singular_{}_accessor", suffix);
+
+                let mut type_params = Vec::new();
+                match elem {
+                    &FieldElem::Message(ref name, ..) | &FieldElem::Enum(ref name, ..) => {
+                        type_params.push(name.to_owned());
+                    }
+                    _ => (),
+                }
+
+                AccessorFn {
+                    name: name,
+                    type_params: type_params,
+                    style: AccessorStyle::HasGet,
+                }
+            }
+        }
+    }
+
+    pub fn write_clear(&self, w: &mut CodeWriter) {
+        if self.is_oneof() {
+            w.write_line(&format!(
+                "self.{} = ::std::option::Option::None;",
+                self.oneof().oneof_rust_field_name
+            ));
+        } else {
+            let clear_expr = self
+                .full_storage_type()
+                .clear(&self.self_field(), &self.customize);
+            w.write_line(&format!("{};", clear_expr));
+        }
+    }
+
+    // expression that returns size of data is variable
+    fn element_size(&self, var: &str, var_type: &RustType) -> String {
+        assert!(!self.is_repeated_packed());
+
+        match field_type_size(self.proto_type) {
+            Some(data_size) => format!("{}", data_size + self.tag_size()),
+            None => match self.proto_type {
+                FieldDescriptorProto_Type::TYPE_MESSAGE => panic!("not a single-liner"),
+                FieldDescriptorProto_Type::TYPE_BYTES => format!(
+                    "::protobuf::rt::bytes_size({}, &{})",
+                    self.proto_field.number(),
+                    var
+                ),
+                FieldDescriptorProto_Type::TYPE_STRING => format!(
+                    "::protobuf::rt::string_size({}, &{})",
+                    self.proto_field.number(),
+                    var
+                ),
+                FieldDescriptorProto_Type::TYPE_ENUM => {
+                    let param_type = match var_type {
+                        &RustType::Ref(ref t) => (**t).clone(),
+                        t => t.clone(),
+                    };
+                    format!(
+                        "::protobuf::rt::enum_size({}, {})",
+                        self.proto_field.number(),
+                        var_type.into_target(&param_type, var, &self.customize)
+                    )
+                }
+                _ => {
+                    let param_type = match var_type {
+                        &RustType::Ref(ref t) => (**t).clone(),
+                        t => t.clone(),
+                    };
+                    if self.proto_type.is_s_varint() {
+                        format!(
+                            "::protobuf::rt::value_varint_zigzag_size({}, {})",
+                            self.proto_field.number(),
+                            var_type.into_target(&param_type, var, &self.customize)
+                        )
+                    } else {
+                        format!(
+                            "::protobuf::rt::value_size({}, {}, ::protobuf::wire_format::{:?})",
+                            self.proto_field.number(),
+                            var_type.into_target(&param_type, var, &self.customize),
+                            self.wire_type
+                        )
+                    }
+                }
+            },
+        }
+    }
+
+    // output code that writes single element to stream
+    pub fn write_write_element(&self, w: &mut CodeWriter, os: &str, var: &str, ty: &RustType) {
+        if let FieldKind::Repeated(RepeatedField { packed: true, .. }) = self.kind {
+            unreachable!();
+        };
+
+        match self.proto_type {
+            FieldDescriptorProto_Type::TYPE_MESSAGE => {
+                w.write_line(&format!(
+                    "{}.write_tag({}, ::protobuf::wire_format::{:?})?;",
+                    os,
+                    self.proto_field.number(),
+                    wire_format::WireTypeLengthDelimited
+                ));
+                w.write_line(&format!(
+                    "{}.write_raw_varint32({}.get_cached_size())?;",
+                    os, var
+                ));
+                w.write_line(&format!("{}.write_to_with_cached_sizes({})?;", var, os));
+            }
+            _ => {
+                let param_type = self.os_write_fn_param_type();
+                let os_write_fn_suffix = self.os_write_fn_suffix();
+                let number = self.proto_field.number();
+                w.write_line(&format!(
+                    "{}.write_{}({}, {})?;",
+                    os,
+                    os_write_fn_suffix,
+                    number,
+                    ty.into_target(&param_type, var, &self.customize)
+                ));
+            }
+        }
+    }
+
+    fn self_field(&self) -> String {
+        format!("self.{}", self.rust_name)
+    }
+
+    fn self_field_is_some(&self) -> String {
+        assert!(self.is_singular());
+        format!("{}.is_some()", self.self_field())
+    }
+
+    fn self_field_is_not_empty(&self) -> String {
+        assert!(self.is_repeated_or_map());
+        format!("!{}.is_empty()", self.self_field())
+    }
+
+    fn self_field_is_none(&self) -> String {
+        assert!(self.is_singular());
+        format!("{}.is_none()", self.self_field())
+    }
+
+    // type of expression returned by `as_option()`
+    fn as_option_type(&self) -> RustType {
+        assert!(self.is_singular());
+        match self.full_storage_type() {
+            RustType::Option(ref e) if e.is_copy() => RustType::Option(e.clone()),
+            RustType::Option(e) => RustType::Option(Box::new(e.ref_type())),
+            RustType::SingularField(ty) | RustType::SingularPtrField(ty) => {
+                RustType::Option(Box::new(RustType::Ref(ty)))
+            }
+            x => panic!("cannot convert {:?} to option", x),
+        }
+    }
+
+    // field data viewed as Option
+    fn self_field_as_option(&self) -> RustValueTyped {
+        assert!(self.is_singular());
+
+        let suffix = match self.full_storage_type() {
+            RustType::Option(ref e) if e.is_copy() => "",
+            _ => ".as_ref()",
+        };
+
+        self.as_option_type()
+            .value(format!("{}{}", self.self_field(), suffix))
+    }
+
+    fn write_if_let_self_field_is_some<F>(&self, w: &mut CodeWriter, cb: F)
+    where
+        F: Fn(&str, &RustType, &mut CodeWriter),
+    {
+        match self.kind {
+            FieldKind::Repeated(..) | FieldKind::Map(..) => panic!("field is not singular"),
+            FieldKind::Singular(SingularField {
+                flag: SingularFieldFlag::WithFlag { .. },
+                ref elem,
+            }) => {
+                let var = "v";
+                let ref_prefix = match elem.rust_storage_type().is_copy() {
+                    true => "",
+                    false => "ref ",
+                };
+                let as_option = self.self_field_as_option();
+                w.if_let_stmt(
+                    &format!("Some({}{})", ref_prefix, var),
+                    &as_option.value,
+                    |w| {
+                        let v_type = as_option.rust_type.elem_type();
+                        cb(var, &v_type, w);
+                    },
+                );
+            }
+            FieldKind::Singular(SingularField {
+                flag: SingularFieldFlag::WithoutFlag,
+                ref elem,
+            }) => match *elem {
+                FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_STRING, ..)
+                | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_BYTES, ..) => {
+                    w.if_stmt(format!("!{}.is_empty()", self.self_field()), |w| {
+                        cb(&self.self_field(), &self.full_storage_type(), w);
+                    });
+                }
+                _ => {
+                    w.if_stmt(
+                        format!(
+                            "{} != {}",
+                            self.self_field(),
+                            self.full_storage_type().default_value(&self.customize)
+                        ),
+                        |w| {
+                            cb(&self.self_field(), &self.full_storage_type(), w);
+                        },
+                    );
+                }
+            },
+            FieldKind::Oneof(..) => unreachable!(),
+        }
+    }
+
+    fn write_if_self_field_is_not_empty<F>(&self, w: &mut CodeWriter, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        assert!(self.is_repeated_or_map());
+        let self_field_is_not_empty = self.self_field_is_not_empty();
+        w.if_stmt(self_field_is_not_empty, cb);
+    }
+
+    pub fn write_if_self_field_is_none<F>(&self, w: &mut CodeWriter, cb: F)
+    where
+        F: Fn(&mut CodeWriter),
+    {
+        let self_field_is_none = self.self_field_is_none();
+        w.if_stmt(self_field_is_none, cb)
+    }
+
+    // repeated or singular
+    pub fn write_for_self_field<F>(&self, w: &mut CodeWriter, varn: &str, cb: F)
+    where
+        F: Fn(&mut CodeWriter, &RustType),
+    {
+        match self.kind {
+            FieldKind::Oneof(OneofField {
+                ref elem,
+                ref oneof_type_name,
+                ..
+            }) => {
+                let cond = format!(
+                    "Some({}::{}(ref {}))",
+                    oneof_type_name.to_code(&self.customize),
+                    self.rust_name,
+                    varn
+                );
+                w.if_let_stmt(&cond, &self.self_field_oneof(), |w| {
+                    cb(w, &elem.rust_storage_type())
+                })
+            }
+            _ => {
+                let v_type = self.full_storage_iter_elem_type();
+                let self_field = self.self_field();
+                w.for_stmt(&format!("&{}", self_field), varn, |w| cb(w, &v_type));
+            }
+        }
+    }
+
+    fn write_self_field_assign(&self, w: &mut CodeWriter, value: &str) {
+        let self_field = self.self_field();
+        w.write_line(&format!("{} = {};", self_field, value));
+    }
+
+    fn write_self_field_assign_some(&self, w: &mut CodeWriter, value: &str) {
+        let full_storage_type = self.full_storage_type();
+        match self.singular() {
+            &SingularField {
+                flag: SingularFieldFlag::WithFlag { .. },
+                ..
+            } => {
+                self.write_self_field_assign(w, &full_storage_type.wrap_value(value));
+            }
+            &SingularField {
+                flag: SingularFieldFlag::WithoutFlag,
+                ..
+            } => {
+                self.write_self_field_assign(w, value);
+            }
+        }
+    }
+
+    fn write_self_field_assign_value(&self, w: &mut CodeWriter, value: &str, ty: &RustType) {
+        match self.kind {
+            FieldKind::Repeated(..) | FieldKind::Map(..) => {
+                let converted = ty.into_target(&self.full_storage_type(), value, &self.customize);
+                self.write_self_field_assign(w, &converted);
+            }
+            FieldKind::Singular(SingularField { ref elem, ref flag }) => {
+                let converted = ty.into_target(&elem.rust_storage_type(), value, &self.customize);
+                let wrapped = if *flag == SingularFieldFlag::WithoutFlag {
+                    converted
+                } else {
+                    self.full_storage_type().wrap_value(&converted)
+                };
+                self.write_self_field_assign(w, &wrapped);
+            }
+            FieldKind::Oneof(..) => unreachable!(),
+        }
+    }
+
+    fn write_self_field_assign_default(&self, w: &mut CodeWriter) {
+        assert!(self.is_singular());
+        if self.is_oneof() {
+            let self_field_oneof = self.self_field_oneof();
+            w.write_line(format!(
+                "{} = ::std::option::Option::Some({}({}))",
+                self_field_oneof,
+                self.variant_path(),
+                // TODO: default from .proto is not needed here (?)
+                self.element_default_value_rust()
+                    .into_type(self.full_storage_iter_elem_type(), &self.customize)
+                    .value
+            ));
+        } else {
+            // Note it is different from C++ protobuf, where field is initialized
+            // with default value
+            match self.full_storage_type() {
+                RustType::SingularField(..) | RustType::SingularPtrField(..) => {
+                    let self_field = self.self_field();
+                    w.write_line(&format!("{}.set_default();", self_field));
+                }
+                _ => {
+                    self.write_self_field_assign_some(
+                        w,
+                        &self
+                            .elem()
+                            .rust_storage_type()
+                            .default_value_typed(&self.customize)
+                            .into_type(self.elem().rust_storage_type(), &self.customize)
+                            .value,
+                    );
+                }
+            }
+        }
+    }
+
+    fn self_field_vec_packed_fixed_data_size(&self) -> String {
+        assert!(self.is_fixed());
+        format!(
+            "({}.len() * {}) as u32",
+            self.self_field(),
+            field_type_size(self.proto_type).unwrap()
+        )
+    }
+
+    fn self_field_vec_packed_varint_data_size(&self) -> String {
+        assert!(!self.is_fixed());
+        let fn_name = if self.is_enum() {
+            "vec_packed_enum_data_size".to_string()
+        } else {
+            let zigzag_suffix = if self.is_zigzag() { "_zigzag" } else { "" };
+            format!("vec_packed_varint{}_data_size", zigzag_suffix)
+        };
+        format!(
+            "{}::rt::{}(&{})",
+            protobuf_crate_path(&self.customize),
+            fn_name,
+            self.self_field()
+        )
+    }
+
+    fn self_field_vec_packed_data_size(&self) -> String {
+        assert!(self.is_repeated_not_map());
+        if self.is_fixed() {
+            self.self_field_vec_packed_fixed_data_size()
+        } else {
+            self.self_field_vec_packed_varint_data_size()
+        }
+    }
+
+    fn self_field_vec_packed_fixed_size(&self) -> String {
+        // zero is filtered outside
+        format!(
+            "{} + {}::rt::compute_raw_varint32_size({}) + {}",
+            self.tag_size(),
+            protobuf_crate_path(&self.customize),
+            self.self_field_vec_packed_fixed_data_size(),
+            self.self_field_vec_packed_fixed_data_size()
+        )
+    }
+
+    fn self_field_vec_packed_varint_size(&self) -> String {
+        // zero is filtered outside
+        assert!(!self.is_fixed());
+        let fn_name = if self.is_enum() {
+            "vec_packed_enum_size".to_string()
+        } else {
+            let zigzag_suffix = if self.is_zigzag() { "_zigzag" } else { "" };
+            format!("vec_packed_varint{}_size", zigzag_suffix)
+        };
+        format!(
+            "{}::rt::{}({}, &{})",
+            protobuf_crate_path(&self.customize),
+            fn_name,
+            self.proto_field.number(),
+            self.self_field()
+        )
+    }
+
+    fn self_field_oneof(&self) -> String {
+        format!("self.{}", self.oneof().oneof_rust_field_name)
+    }
+
+    pub fn clear_field_func(&self) -> String {
+        format!("clear_{}", self.rust_name)
+    }
+
+    // Write `merge_from` part for this singular or repeated field
+    // of type message, string or bytes
+    fn write_merge_from_field_message_string_bytes(&self, w: &mut CodeWriter) {
+        let singular_or_repeated = match self.kind {
+            FieldKind::Repeated(..) => "repeated",
+            FieldKind::Singular(SingularField {
+                flag: SingularFieldFlag::WithFlag { .. },
+                ..
+            }) => "singular",
+            FieldKind::Singular(SingularField {
+                flag: SingularFieldFlag::WithoutFlag,
+                ..
+            }) => "singular_proto3",
+            FieldKind::Map(..) | FieldKind::Oneof(..) => unreachable!(),
+        };
+        let carllerche = match self.kind.primitive_type_variant() {
+            PrimitiveTypeVariant::Carllerche => "carllerche_",
+            PrimitiveTypeVariant::Default => "",
+        };
+        let type_name_for_fn = protobuf_name(self.proto_type);
+        w.write_line(&format!(
+            "::protobuf::rt::read_{}_{}{}_into(wire_type, is, &mut self.{})?;",
+            singular_or_repeated, carllerche, type_name_for_fn, self.rust_name
+        ));
+    }
+
+    fn write_error_unexpected_wire_type(&self, wire_type_var: &str, w: &mut CodeWriter) {
+        w.write_line(&format!(
+            "return ::std::result::Result::Err({}::rt::unexpected_wire_type({}));",
+            protobuf_crate_path(&self.customize),
+            wire_type_var
+        ));
+    }
+
+    fn write_assert_wire_type(&self, wire_type_var: &str, w: &mut CodeWriter) {
+        w.if_stmt(
+            &format!(
+                "{} != ::protobuf::wire_format::{:?}",
+                wire_type_var, self.wire_type
+            ),
+            |w| {
+                self.write_error_unexpected_wire_type(wire_type_var, w);
+            },
+        );
+    }
+
+    // Write `merge_from` part for this oneof field
+    fn write_merge_from_oneof(&self, f: &OneofField, wire_type_var: &str, w: &mut CodeWriter) {
+        self.write_assert_wire_type(wire_type_var, w);
+
+        let typed = RustValueTyped {
+            value: format!(
+                "{}?",
+                self.proto_type.read("is", f.elem.primitive_type_variant())
+            ),
+            rust_type: self.full_storage_iter_elem_type(),
+        };
+
+        let maybe_boxed = if f.boxed {
+            typed.boxed(&self.customize)
+        } else {
+            typed
+        };
+
+        w.write_line(&format!(
+            "self.{} = ::std::option::Option::Some({}({}));",
+            self.oneof().oneof_rust_field_name,
+            self.variant_path(),
+            maybe_boxed.value
+        )); // TODO: into_type
+    }
+
+    // Write `merge_from` part for this map field
+    fn write_merge_from_map(&self, w: &mut CodeWriter) {
+        let &MapField {
+            ref key, ref value, ..
+        } = self.map();
+        w.write_line(&format!(
+            "::protobuf::rt::read_map_into::<{}, {}>(wire_type, is, &mut {})?;",
+            key.lib_protobuf_type(&self.customize),
+            value.lib_protobuf_type(&self.customize),
+            self.self_field()
+        ));
+    }
+
+    // Write `merge_from` part for this singular field
+    fn write_merge_from_singular(&self, wire_type_var: &str, w: &mut CodeWriter) {
+        let field = match self.kind {
+            FieldKind::Singular(ref field) => field,
+            _ => panic!(),
+        };
+
+        match field.elem {
+            FieldElem::Message(..)
+            | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_STRING, ..)
+            | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_BYTES, ..) => {
+                self.write_merge_from_field_message_string_bytes(w);
+            }
+            FieldElem::Enum(..) => {
+                let version = match field.flag {
+                    SingularFieldFlag::WithFlag { .. } => "proto2",
+                    SingularFieldFlag::WithoutFlag => "proto3",
+                };
+                w.write_line(&format!(
+                    "::protobuf::rt::read_{}_enum_with_unknown_fields_into({}, is, &mut self.{}, {}, &mut self.unknown_fields)?",
+                    version,
+                    wire_type_var,
+                    self.rust_name,
+                    self.proto_field.number()
+                ));
+            }
+            _ => {
+                let read_proc = format!(
+                    "{}?",
+                    self.proto_type.read("is", PrimitiveTypeVariant::Default)
+                );
+
+                self.write_assert_wire_type(wire_type_var, w);
+                w.write_line(&format!("let tmp = {};", read_proc));
+                self.write_self_field_assign_some(w, "tmp");
+            }
+        }
+    }
+
+    // Write `merge_from` part for this repeated field
+    fn write_merge_from_repeated(&self, wire_type_var: &str, w: &mut CodeWriter) {
+        let field = match self.kind {
+            FieldKind::Repeated(ref field) => field,
+            _ => panic!(),
+        };
+
+        match field.elem {
+            FieldElem::Message(..)
+            | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_STRING, ..)
+            | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_BYTES, ..) => {
+                self.write_merge_from_field_message_string_bytes(w);
+            }
+            FieldElem::Enum(..) => {
+                w.write_line(&format!(
+                    "::protobuf::rt::read_repeated_enum_with_unknown_fields_into({}, is, &mut self.{}, {}, &mut self.unknown_fields)?",
+                    wire_type_var,
+                    self.rust_name,
+                    self.proto_field.number()
+                ));
+            }
+            _ => {
+                w.write_line(&format!(
+                    "{}::rt::read_repeated_{}_into({}, is, &mut self.{})?;",
+                    protobuf_crate_path(&self.customize),
+                    protobuf_name(self.proto_type),
+                    wire_type_var,
+                    self.rust_name
+                ));
+            }
+        }
+    }
+
+    // Write `merge_from` part for this field
+    pub fn write_merge_from_field(&self, wire_type_var: &str, w: &mut CodeWriter) {
+        match self.kind {
+            FieldKind::Oneof(ref f) => self.write_merge_from_oneof(&f, wire_type_var, w),
+            FieldKind::Map(..) => self.write_merge_from_map(w),
+            FieldKind::Singular(..) => self.write_merge_from_singular(wire_type_var, w),
+            FieldKind::Repeated(..) => self.write_merge_from_repeated(wire_type_var, w),
+        }
+    }
+
+    fn self_field_vec_packed_size(&self) -> String {
+        match self.kind {
+            FieldKind::Repeated(RepeatedField { packed: true, .. }) => {
+                // zero is filtered outside
+                if self.is_fixed() {
+                    self.self_field_vec_packed_fixed_size()
+                } else {
+                    self.self_field_vec_packed_varint_size()
+                }
+            }
+            _ => {
+                panic!("not packed");
+            }
+        }
+    }
+
+    pub fn write_element_size(
+        &self,
+        w: &mut CodeWriter,
+        item_var: &str,
+        item_var_type: &RustType,
+        sum_var: &str,
+    ) {
+        assert!(!self.is_repeated_packed());
+
+        match self.proto_type {
+            FieldDescriptorProto_Type::TYPE_MESSAGE => {
+                w.write_line(&format!("let len = {}.compute_size();", item_var));
+                let tag_size = self.tag_size();
+                w.write_line(&format!(
+                    "{} += {} + ::protobuf::rt::compute_raw_varint32_size(len) + len;",
+                    sum_var, tag_size
+                ));
+            }
+            _ => {
+                w.write_line(&format!(
+                    "{} += {};",
+                    sum_var,
+                    self.element_size(item_var, item_var_type)
+                ));
+            }
+        }
+    }
+
+    pub fn write_message_write_field(&self, w: &mut CodeWriter) {
+        match self.kind {
+            FieldKind::Singular(..) => {
+                self.write_if_let_self_field_is_some(w, |v, v_type, w| {
+                    self.write_write_element(w, "os", v, v_type);
+                });
+            }
+            FieldKind::Repeated(RepeatedField { packed: false, .. }) => {
+                self.write_for_self_field(w, "v", |w, v_type| {
+                    self.write_write_element(w, "os", "v", v_type);
+                });
+            }
+            FieldKind::Repeated(RepeatedField { packed: true, .. }) => {
+                self.write_if_self_field_is_not_empty(w, |w| {
+                    let number = self.proto_field.number();
+                    w.write_line(&format!(
+                        "os.write_tag({}, {}::wire_format::{:?})?;",
+                        number,
+                        protobuf_crate_path(&self.customize),
+                        wire_format::WireTypeLengthDelimited
+                    ));
+                    w.comment("TODO: Data size is computed again, it should be cached");
+                    let data_size_expr = self.self_field_vec_packed_data_size();
+                    w.write_line(&format!("os.write_raw_varint32({})?;", data_size_expr));
+                    self.write_for_self_field(w, "v", |w, v_type| {
+                        let param_type = self.os_write_fn_param_type();
+                        let os_write_fn_suffix = self.os_write_fn_suffix();
+                        w.write_line(&format!(
+                            "os.write_{}_no_tag({})?;",
+                            os_write_fn_suffix,
+                            v_type.into_target(&param_type, "v", &self.customize)
+                        ));
+                    });
+                });
+            }
+            FieldKind::Map(MapField {
+                ref key, ref value, ..
+            }) => {
+                w.write_line(&format!(
+                    "::protobuf::rt::write_map_with_cached_sizes::<{}, {}>({}, &{}, os)?;",
+                    key.lib_protobuf_type(&self.customize),
+                    value.lib_protobuf_type(&self.customize),
+                    self.proto_field.number(),
+                    self.self_field()
+                ));
+            }
+            FieldKind::Oneof(..) => unreachable!(),
+        };
+    }
+
+    pub fn write_message_compute_field_size(&self, sum_var: &str, w: &mut CodeWriter) {
+        match self.kind {
+            FieldKind::Singular(..) => {
+                self.write_if_let_self_field_is_some(w, |v, v_type, w| {
+                    match field_type_size(self.proto_type) {
+                        Some(s) => {
+                            let tag_size = self.tag_size();
+                            w.write_line(&format!("{} += {};", sum_var, (s + tag_size) as isize));
+                        }
+                        None => {
+                            self.write_element_size(w, v, v_type, sum_var);
+                        }
+                    };
+                });
+            }
+            FieldKind::Repeated(RepeatedField { packed: false, .. }) => {
+                match field_type_size(self.proto_type) {
+                    Some(s) => {
+                        let tag_size = self.tag_size();
+                        let self_field = self.self_field();
+                        w.write_line(&format!(
+                            "{} += {} * {}.len() as u32;",
+                            sum_var,
+                            (s + tag_size) as isize,
+                            self_field
+                        ));
+                    }
+                    None => {
+                        self.write_for_self_field(w, "value", |w, value_type| {
+                            self.write_element_size(w, "value", value_type, sum_var);
+                        });
+                    }
+                };
+            }
+            FieldKind::Map(MapField {
+                ref key, ref value, ..
+            }) => {
+                w.write_line(&format!(
+                    "{} += {}::rt::compute_map_size::<{}, {}>({}, &{});",
+                    sum_var,
+                    protobuf_crate_path(&self.customize),
+                    key.lib_protobuf_type(&self.customize),
+                    value.lib_protobuf_type(&self.customize),
+                    self.proto_field.number(),
+                    self.self_field()
+                ));
+            }
+            FieldKind::Repeated(RepeatedField { packed: true, .. }) => {
+                self.write_if_self_field_is_not_empty(w, |w| {
+                    let size_expr = self.self_field_vec_packed_size();
+                    w.write_line(&format!("{} += {};", sum_var, size_expr));
+                });
+            }
+            FieldKind::Oneof(..) => unreachable!(),
+        }
+    }
+
+    fn write_message_field_get_singular(&self, w: &mut CodeWriter) {
+        let get_xxx_return_type = self.get_xxx_return_type();
+
+        if self.proto_type == FieldDescriptorProto_Type::TYPE_MESSAGE {
+            let self_field = self.self_field();
+            let ref field_type_name = self.elem().rust_storage_type();
+            w.write_line(&format!(
+                "{}.as_ref().unwrap_or_else(|| {}::default_instance())",
+                self_field,
+                field_type_name.to_code(&self.customize)
+            ));
+        } else {
+            let get_xxx_default_value_rust = self.get_xxx_default_value_rust();
+            let self_field = self.self_field();
+            match self.singular() {
+                &SingularField {
+                    flag: SingularFieldFlag::WithFlag { .. },
+                    ..
+                } => {
+                    if get_xxx_return_type.is_ref() {
+                        let as_option = self.self_field_as_option();
+                        w.match_expr(&as_option.value, |w| {
+                            let v_type = as_option.rust_type.elem_type();
+                            let r_type = self.get_xxx_return_type();
+                            w.case_expr(
+                                "Some(v)",
+                                v_type.into_target(&r_type, "v", &self.customize),
+                            );
+                            let get_xxx_default_value_rust = self.get_xxx_default_value_rust();
+                            w.case_expr("None", get_xxx_default_value_rust);
+                        });
+                    } else {
+                        w.write_line(&format!(
+                            "{}.unwrap_or({})",
+                            self_field, get_xxx_default_value_rust
+                        ));
+                    }
+                }
+                &SingularField {
+                    flag: SingularFieldFlag::WithoutFlag,
+                    ..
+                } => {
+                    w.write_line(self.full_storage_type().into_target(
+                        &get_xxx_return_type,
+                        &self_field,
+                        &self.customize,
+                    ));
+                }
+            }
+        }
+    }
+
+    fn write_message_field_get(&self, w: &mut CodeWriter) {
+        let get_xxx_return_type = self.get_xxx_return_type();
+        let fn_def = format!(
+            "get_{}(&self) -> {}",
+            self.rust_name,
+            get_xxx_return_type.to_code(&self.customize)
+        );
+
+        w.pub_fn(&fn_def, |w| match self.kind {
+            FieldKind::Oneof(OneofField { ref elem, .. }) => {
+                let self_field_oneof = self.self_field_oneof();
+                w.match_expr(self_field_oneof, |w| {
+                    let (refv, vtype) = if !self.elem_type_is_copy() {
+                        ("ref v", elem.rust_storage_type().ref_type())
+                    } else {
+                        ("v", elem.rust_storage_type())
+                    };
+                    w.case_expr(
+                        format!(
+                            "::std::option::Option::Some({}({}))",
+                            self.variant_path(),
+                            refv
+                        ),
+                        vtype.into_target(&get_xxx_return_type, "v", &self.customize),
+                    );
+                    w.case_expr("_", self.get_xxx_default_value_rust());
+                })
+            }
+            FieldKind::Singular(..) => {
+                self.write_message_field_get_singular(w);
+            }
+            FieldKind::Repeated(..) | FieldKind::Map(..) => {
+                let self_field = self.self_field();
+                w.write_line(&format!("&{}", self_field));
+            }
+        });
+    }
+
+    fn has_has(&self) -> bool {
+        match self.kind {
+            FieldKind::Repeated(..) | FieldKind::Map(..) => false,
+            FieldKind::Singular(SingularField {
+                flag: SingularFieldFlag::WithFlag { .. },
+                ..
+            }) => true,
+            FieldKind::Singular(SingularField {
+                flag: SingularFieldFlag::WithoutFlag,
+                ..
+            }) => false,
+            FieldKind::Oneof(..) => true,
+        }
+    }
+
+    fn has_mut(&self) -> bool {
+        match self.kind {
+            FieldKind::Repeated(..) | FieldKind::Map(..) => true,
+            // TODO: string should be public, and mut is not needed
+            FieldKind::Singular(..) | FieldKind::Oneof(..) => !self.elem_type_is_copy(),
+        }
+    }
+
+    fn has_take(&self) -> bool {
+        match self.kind {
+            FieldKind::Repeated(..) | FieldKind::Map(..) => true,
+            // TODO: string should be public, and mut is not needed
+            FieldKind::Singular(..) | FieldKind::Oneof(..) => !self.elem_type_is_copy(),
+        }
+    }
+
+    fn has_name(&self) -> String {
+        format!("has_{}", self.rust_name)
+    }
+
+    fn write_message_field_has(&self, w: &mut CodeWriter) {
+        w.pub_fn(&format!("{}(&self) -> bool", self.has_name()), |w| {
+            if !self.is_oneof() {
+                let self_field_is_some = self.self_field_is_some();
+                w.write_line(self_field_is_some);
+            } else {
+                let self_field_oneof = self.self_field_oneof();
+                w.match_expr(self_field_oneof, |w| {
+                    w.case_expr(
+                        format!("::std::option::Option::Some({}(..))", self.variant_path()),
+                        "true",
+                    );
+                    w.case_expr("_", "false");
+                });
+            }
+        });
+    }
+
+    fn write_message_field_set(&self, w: &mut CodeWriter) {
+        let set_xxx_param_type = self.set_xxx_param_type();
+        w.comment("Param is passed by value, moved");
+        let ref name = self.rust_name;
+        w.pub_fn(
+            &format!(
+                "set_{}(&mut self, v: {})",
+                name,
+                set_xxx_param_type.to_code(&self.customize)
+            ),
+            |w| {
+                if !self.is_oneof() {
+                    self.write_self_field_assign_value(w, "v", &set_xxx_param_type);
+                } else {
+                    let self_field_oneof = self.self_field_oneof();
+                    let v = set_xxx_param_type.into_target(
+                        &self.oneof().rust_type(),
+                        "v",
+                        &self.customize,
+                    );
+                    w.write_line(&format!(
+                        "{} = ::std::option::Option::Some({}({}))",
+                        self_field_oneof,
+                        self.variant_path(),
+                        v
+                    ));
+                }
+            },
+        );
+    }
+
+    fn write_message_field_mut(&self, w: &mut CodeWriter) {
+        let mut_xxx_return_type = self.mut_xxx_return_type();
+        w.comment("Mutable pointer to the field.");
+        if self.is_singular() {
+            w.comment("If field is not initialized, it is initialized with default value first.");
+        }
+        let fn_def = match mut_xxx_return_type {
+            RustType::Ref(ref param) => format!(
+                "mut_{}(&mut self) -> &mut {}",
+                self.rust_name,
+                param.to_code(&self.customize)
+            ),
+            _ => panic!(
+                "not a ref: {}",
+                mut_xxx_return_type.to_code(&self.customize)
+            ),
+        };
+        w.pub_fn(&fn_def, |w| {
+            match self.kind {
+                FieldKind::Repeated(..) | FieldKind::Map(..) => {
+                    let self_field = self.self_field();
+                    w.write_line(&format!("&mut {}", self_field));
+                }
+                FieldKind::Singular(SingularField {
+                    flag: SingularFieldFlag::WithFlag { .. },
+                    ..
+                }) => {
+                    self.write_if_self_field_is_none(w, |w| {
+                        self.write_self_field_assign_default(w);
+                    });
+                    let self_field = self.self_field();
+                    w.write_line(&format!("{}.as_mut().unwrap()", self_field));
+                }
+                FieldKind::Singular(SingularField {
+                    flag: SingularFieldFlag::WithoutFlag,
+                    ..
+                }) => w.write_line(&format!("&mut {}", self.self_field())),
+                FieldKind::Oneof(..) => {
+                    let self_field_oneof = self.self_field_oneof();
+
+                    // if oneof does not contain current field
+                    w.if_let_else_stmt(
+                        &format!("::std::option::Option::Some({}(_))", self.variant_path())[..],
+                        &self_field_oneof[..],
+                        |w| {
+                            // initialize it with default value
+                            w.write_line(&format!(
+                                "{} = ::std::option::Option::Some({}({}));",
+                                self_field_oneof,
+                                self.variant_path(),
+                                self.element_default_value_rust()
+                                    .into_type(self.oneof().rust_type(), &self.customize)
+                                    .value
+                            ));
+                        },
+                    );
+
+                    // extract field
+                    w.match_expr(self_field_oneof, |w| {
+                        w.case_expr(
+                            format!(
+                                "::std::option::Option::Some({}(ref mut v))",
+                                self.variant_path()
+                            ),
+                            "v",
+                        );
+                        w.case_expr("_", "panic!()");
+                    });
+                }
+            }
+        });
+    }
+
+    fn write_message_field_take_oneof(&self, w: &mut CodeWriter) {
+        let take_xxx_return_type = self.take_xxx_return_type();
+
+        // TODO: replace with if let
+        w.write_line(&format!("if self.{}() {{", self.has_name()));
+        w.indented(|w| {
+            let self_field_oneof = self.self_field_oneof();
+            w.match_expr(format!("{}.take()", self_field_oneof), |w| {
+                let value_in_some = self.oneof().rust_type().value("v".to_owned());
+                let converted =
+                    value_in_some.into_type(self.take_xxx_return_type(), &self.customize);
+                w.case_expr(
+                    format!("::std::option::Option::Some({}(v))", self.variant_path()),
+                    &converted.value,
+                );
+                w.case_expr("_", "panic!()");
+            });
+        });
+        w.write_line("} else {");
+        w.indented(|w| {
+            w.write_line(
+                self.elem()
+                    .rust_storage_type()
+                    .default_value_typed(&self.customize)
+                    .into_type(take_xxx_return_type.clone(), &self.customize)
+                    .value,
+            );
+        });
+        w.write_line("}");
+    }
+
+    fn write_message_field_take(&self, w: &mut CodeWriter) {
+        let take_xxx_return_type = self.take_xxx_return_type();
+        w.comment("Take field");
+        w.pub_fn(
+            &format!(
+                "take_{}(&mut self) -> {}",
+                self.rust_name,
+                take_xxx_return_type.to_code(&self.customize)
+            ),
+            |w| match self.kind {
+                FieldKind::Oneof(..) => {
+                    self.write_message_field_take_oneof(w);
+                }
+                FieldKind::Repeated(..) | FieldKind::Map(..) => {
+                    w.write_line(&format!(
+                        "::std::mem::replace(&mut self.{}, {})",
+                        self.rust_name,
+                        take_xxx_return_type.default_value(&self.customize)
+                    ));
+                }
+                FieldKind::Singular(SingularField {
+                    ref elem,
+                    flag: SingularFieldFlag::WithFlag { .. },
+                }) => {
+                    if !elem.is_copy() {
+                        w.write_line(&format!(
+                            "{}.take().unwrap_or_else(|| {})",
+                            self.self_field(),
+                            elem.rust_storage_type().default_value(&self.customize)
+                        ));
+                    } else {
+                        w.write_line(&format!(
+                            "{}.take().unwrap_or({})",
+                            self.self_field(),
+                            self.element_default_value_rust().value
+                        ));
+                    }
+                }
+                FieldKind::Singular(SingularField {
+                    flag: SingularFieldFlag::WithoutFlag,
+                    ..
+                }) => w.write_line(&format!(
+                    "::std::mem::replace(&mut {}, {})",
+                    self.self_field(),
+                    self.full_storage_type().default_value(&self.customize)
+                )),
+            },
+        );
+    }
+
+    pub fn write_message_single_field_accessors(&self, w: &mut CodeWriter) {
+        // TODO: do not generate `get` when !proto2 and !generate_accessors`
+        w.write_line("");
+        self.write_message_field_get(w);
+
+        if !self.generate_accessors {
+            return;
+        }
+
+        let clear_field_func = self.clear_field_func();
+        w.pub_fn(&format!("{}(&mut self)", clear_field_func), |w| {
+            self.write_clear(w);
+        });
+
+        if self.has_has() {
+            w.write_line("");
+            self.write_message_field_has(w);
+        }
+
+        w.write_line("");
+        self.write_message_field_set(w);
+
+        if self.has_mut() {
+            w.write_line("");
+            self.write_message_field_mut(w);
+        }
+
+        if self.has_take() {
+            w.write_line("");
+            self.write_message_field_take(w);
+        }
+    }
+}
+
+pub(crate) fn rust_field_name_for_protobuf_field_name(name: &str) -> RustIdent {
+    if rust::is_rust_keyword(name) {
+        RustIdent::new(&format!("field_{}", name))
+    } else {
+        RustIdent::new(name)
+    }
+}
diff --git a/src/file.rs b/src/file.rs
new file mode 100644
index 0000000..0c21d99
--- /dev/null
+++ b/src/file.rs
@@ -0,0 +1,70 @@
+use crate::rust;
+use crate::rust_name::RustIdent;
+use crate::strx;
+
+// Copy-pasted from libsyntax.
+fn ident_start(c: char) -> bool {
+    (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
+}
+
+// Copy-pasted from libsyntax.
+fn ident_continue(c: char) -> bool {
+    (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'
+}
+
+pub(crate) fn proto_path_to_rust_mod(path: &str) -> RustIdent {
+    let without_dir = strx::remove_to(path, '/');
+    let without_suffix = strx::remove_suffix(without_dir, ".proto");
+
+    let name = without_suffix
+        .chars()
+        .enumerate()
+        .map(|(i, c)| {
+            let valid = if i == 0 {
+                ident_start(c)
+            } else {
+                ident_continue(c)
+            };
+            if valid {
+                c
+            } else {
+                '_'
+            }
+        })
+        .collect::<String>();
+
+    let name = if rust::is_rust_keyword(&name) {
+        format!("{}_pb", name)
+    } else {
+        name
+    };
+    RustIdent::from(name)
+}
+
+#[cfg(test)]
+mod test {
+
+    use super::proto_path_to_rust_mod;
+    use crate::rust_name::RustIdent;
+
+    #[test]
+    fn test_mod_path_proto_ext() {
+        assert_eq!(
+            RustIdent::from("proto"),
+            proto_path_to_rust_mod("proto.proto")
+        );
+    }
+
+    #[test]
+    fn test_mod_path_unknown_ext() {
+        assert_eq!(
+            RustIdent::from("proto_proto3"),
+            proto_path_to_rust_mod("proto.proto3")
+        );
+    }
+
+    #[test]
+    fn test_mod_path_empty_ext() {
+        assert_eq!(RustIdent::from("proto"), proto_path_to_rust_mod("proto"));
+    }
+}
diff --git a/src/file_and_mod.rs b/src/file_and_mod.rs
new file mode 100644
index 0000000..4f4e8c6
--- /dev/null
+++ b/src/file_and_mod.rs
@@ -0,0 +1,9 @@
+use rust_name::RustRelativePath;
+use Customize;
+
+#[allow(dead_code)]
+pub(crate) struct FileAndMod {
+    pub file: String,
+    pub relative_mod: RustRelativePath,
+    pub customize: Customize,
+}
diff --git a/src/file_descriptor.rs b/src/file_descriptor.rs
new file mode 100644
index 0000000..dde8603
--- /dev/null
+++ b/src/file_descriptor.rs
@@ -0,0 +1,5 @@
+use crate::scope::Scope;
+
+pub(crate) fn file_descriptor_proto_expr(_scope: &Scope) -> String {
+    format!("file_descriptor_proto()")
+}
diff --git a/src/float.rs b/src/float.rs
new file mode 100644
index 0000000..78ca622
--- /dev/null
+++ b/src/float.rs
@@ -0,0 +1,67 @@
+use std::f64;
+
+#[derive(Debug)]
+pub enum ProtobufFloatParseError {
+    EmptyString,
+    CannotParseFloat,
+}
+
+pub type ProtobufFloatParseResult<T> = Result<T, ProtobufFloatParseError>;
+
+pub const PROTOBUF_NAN: &str = "nan";
+pub const PROTOBUF_INF: &str = "inf";
+
+/// Format float as in protobuf `.proto` files
+pub fn format_protobuf_float(f: f64) -> String {
+    if f.is_nan() {
+        PROTOBUF_NAN.to_owned()
+    } else if f.is_infinite() {
+        if f > 0.0 {
+            format!("{}", PROTOBUF_INF)
+        } else {
+            format!("-{}", PROTOBUF_INF)
+        }
+    } else {
+        let i = f as i64;
+        if i as f64 == f {
+            // Older rust versions did print float without `.0` suffix
+            format!("{:?}.0", i)
+        } else {
+            // TODO: make sure doesn't lose precision
+            format!("{:?}", f)
+        }
+    }
+}
+
+/// Parse float from `.proto` format
+pub fn parse_protobuf_float(s: &str) -> ProtobufFloatParseResult<f64> {
+    if s.is_empty() {
+        return Err(ProtobufFloatParseError::EmptyString);
+    }
+    if s == PROTOBUF_NAN {
+        return Ok(f64::NAN);
+    }
+    if s == PROTOBUF_INF || s == format!("+{}", PROTOBUF_INF) {
+        return Ok(f64::INFINITY);
+    }
+    if s == format!("-{}", PROTOBUF_INF) {
+        return Ok(f64::NEG_INFINITY);
+    }
+    match s.parse() {
+        Ok(f) => Ok(f),
+        Err(_) => Err(ProtobufFloatParseError::CannotParseFloat),
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_format_protobuf_float() {
+        assert_eq!("10.0", format_protobuf_float(10.0));
+        assert_eq!("-10.0", format_protobuf_float(-10.0));
+        assert_eq!("10.5", format_protobuf_float(10.5));
+        assert_eq!("-10.5", format_protobuf_float(-10.5));
+    }
+}
diff --git a/src/inside.rs b/src/inside.rs
new file mode 100644
index 0000000..2590e9e
--- /dev/null
+++ b/src/inside.rs
@@ -0,0 +1,11 @@
+use Customize;
+
+/// Path to `protobuf` crate, different when `.proto` file is
+/// used inside or outside of protobuf crate.
+pub(crate) fn protobuf_crate_path(customize: &Customize) -> &str {
+    match customize.inside_protobuf {
+        // Can't use `crate::` paths before Rust 1.32.0
+        //Some(true) => "crate",
+        _ => "::protobuf",
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..1f91285
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,277 @@
+//! This crate implement protobuf codegen.
+//!
+//! This crate:
+//! * provides `protoc-gen-rust` plugin for `protoc` command
+//! * implement protobuf codegen
+//!
+//! This crate is not meant to be used directly, in fact, it does not provide any public API
+//! (except for `protoc-gen-rust` binary).
+//!
+//! Code can be generated with either:
+//! * `protoc-gen-rust` binary or
+//! * `protoc-rust` crate (codegen which depends on `protoc` binary for parsing)
+//! * `protobuf-codegen-pure` crate
+
+#![deny(intra_doc_link_resolution_failure)]
+#![deny(missing_docs)]
+
+extern crate protobuf;
+
+use std::collections::hash_map::HashMap;
+use std::fmt::Write as FmtWrite;
+use std::fs::File;
+use std::io;
+use std::io::Write;
+use std::path::Path;
+
+use protobuf::compiler_plugin;
+use protobuf::descriptor::*;
+use protobuf::Message;
+
+mod customize;
+mod enums;
+mod extensions;
+mod field;
+mod file;
+mod file_and_mod;
+mod file_descriptor;
+#[doc(hidden)]
+pub mod float;
+mod inside;
+mod message;
+mod oneof;
+mod protobuf_name;
+mod rust_name;
+mod rust_types_values;
+mod serde;
+mod well_known_types;
+
+pub(crate) mod rust;
+pub(crate) mod scope;
+pub(crate) mod strx;
+pub(crate) mod syntax;
+
+use customize::customize_from_rustproto_for_file;
+#[doc(hidden)]
+pub use customize::Customize;
+
+pub mod code_writer;
+
+use self::code_writer::CodeWriter;
+use self::enums::*;
+use self::extensions::*;
+use self::message::*;
+use file::proto_path_to_rust_mod;
+use inside::protobuf_crate_path;
+use scope::FileScope;
+use scope::RootScope;
+
+fn escape_byte(s: &mut String, b: u8) {
+    if b == b'\n' {
+        write!(s, "\\n").unwrap();
+    } else if b == b'\r' {
+        write!(s, "\\r").unwrap();
+    } else if b == b'\t' {
+        write!(s, "\\t").unwrap();
+    } else if b == b'\\' || b == b'"' {
+        write!(s, "\\{}", b as char).unwrap();
+    } else if b == b'\0' {
+        write!(s, "\\0").unwrap();
+    // ASCII printable except space
+    } else if b > 0x20 && b < 0x7f {
+        write!(s, "{}", b as char).unwrap();
+    } else {
+        write!(s, "\\x{:02x}", b).unwrap();
+    }
+}
+
+fn write_file_descriptor_data(
+    file: &FileDescriptorProto,
+    customize: &Customize,
+    w: &mut CodeWriter,
+) {
+    let fdp_bytes = file.write_to_bytes().unwrap();
+    w.write_line("static file_descriptor_proto_data: &'static [u8] = b\"\\");
+    w.indented(|w| {
+        const MAX_LINE_LEN: usize = 72;
+
+        let mut s = String::new();
+        for &b in &fdp_bytes {
+            let prev_len = s.len();
+            escape_byte(&mut s, b);
+            let truncate = s.len() > MAX_LINE_LEN;
+            if truncate {
+                s.truncate(prev_len);
+            }
+            if truncate || s.len() == MAX_LINE_LEN {
+                write!(s, "\\").unwrap();
+                w.write_line(&s);
+                s.clear();
+            }
+            if truncate {
+                escape_byte(&mut s, b);
+            }
+        }
+        if !s.is_empty() {
+            write!(s, "\\").unwrap();
+            w.write_line(&s);
+            s.clear();
+        }
+    });
+    w.write_line("\";");
+    w.write_line("");
+    w.lazy_static_protobuf_path(
+        "file_descriptor_proto_lazy",
+        &format!(
+            "{}::descriptor::FileDescriptorProto",
+            protobuf_crate_path(customize)
+        ),
+        protobuf_crate_path(customize),
+    );
+    w.write_line("");
+    w.def_fn(
+        "parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto",
+        |w| {
+            w.write_line("::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap()");
+        },
+    );
+    w.write_line("");
+    w.pub_fn(
+        "file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto",
+        |w| {
+            w.unsafe_expr(|w| {
+                w.block("file_descriptor_proto_lazy.get(|| {", "})", |w| {
+                    w.write_line("parse_descriptor_proto()");
+                });
+            });
+        },
+    );
+}
+
+fn gen_file(
+    file: &FileDescriptorProto,
+    _files_map: &HashMap<&str, &FileDescriptorProto>,
+    root_scope: &RootScope,
+    customize: &Customize,
+) -> Option<compiler_plugin::GenResult> {
+    // TODO: use it
+    let mut customize = customize.clone();
+    // options specified in invocation have precedence over options specified in file
+    customize.update_with(&customize_from_rustproto_for_file(file.get_options()));
+
+    let scope = FileScope {
+        file_descriptor: file,
+    }
+    .to_scope();
+    let lite_runtime = customize.lite_runtime.unwrap_or_else(|| {
+        file.get_options().get_optimize_for() == FileOptions_OptimizeMode::LITE_RUNTIME
+    });
+
+    let mut v = Vec::new();
+
+    {
+        let mut w = CodeWriter::new(&mut v);
+
+        // Hack: hard code version number here because Android.bp
+        // rust modules cannot pass it though env variable yet.
+        w.write_generated_by("rust-protobuf", "2.14.0");
+        w.write_line(&format!("//! Generated file from `{}`", file.get_name()));
+
+        w.write_line("");
+        w.write_line("use protobuf::Message as Message_imported_for_functions;");
+        w.write_line("use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions;");
+        if customize.inside_protobuf != Some(true) {
+            w.write_line("");
+            w.write_line("/// Generated files are compatible only with the same version");
+            w.write_line("/// of protobuf runtime.");
+            w.commented(|w| {
+                w.write_line(&format!(
+                    "const _PROTOBUF_VERSION_CHECK: () = {}::{};",
+                    protobuf_crate_path(&customize),
+                    protobuf::VERSION_IDENT
+                ));
+            })
+        }
+
+        for message in &scope.get_messages() {
+            // ignore map entries, because they are not used in map fields
+            if message.map_entry().is_none() {
+                w.write_line("");
+                MessageGen::new(message, &root_scope, &customize).write(&mut w);
+            }
+        }
+        for enum_type in &scope.get_enums() {
+            w.write_line("");
+            EnumGen::new(enum_type, file, &customize, root_scope).write(&mut w);
+        }
+
+        write_extensions(file, &root_scope, &mut w, &customize);
+
+        if !lite_runtime {
+            w.write_line("");
+            write_file_descriptor_data(file, &customize, &mut w);
+        }
+    }
+
+    Some(compiler_plugin::GenResult {
+        name: format!("{}.rs", proto_path_to_rust_mod(file.get_name())),
+        content: v,
+    })
+}
+
+// This function is also used externally by cargo plugin
+// https://github.com/plietar/rust-protobuf-build
+// So be careful changing its signature.
+#[doc(hidden)]
+pub fn gen(
+    file_descriptors: &[FileDescriptorProto],
+    files_to_generate: &[String],
+    customize: &Customize,
+) -> Vec<compiler_plugin::GenResult> {
+    let root_scope = RootScope {
+        file_descriptors: file_descriptors,
+    };
+
+    let mut results: Vec<compiler_plugin::GenResult> = Vec::new();
+    let files_map: HashMap<&str, &FileDescriptorProto> =
+        file_descriptors.iter().map(|f| (f.get_name(), f)).collect();
+
+    let all_file_names: Vec<&str> = file_descriptors.iter().map(|f| f.get_name()).collect();
+
+    for file_name in files_to_generate {
+        let file = files_map.get(&file_name[..]).expect(&format!(
+            "file not found in file descriptors: {:?}, files: {:?}",
+            file_name, all_file_names
+        ));
+        results.extend(gen_file(file, &files_map, &root_scope, customize));
+    }
+    results
+}
+
+#[doc(hidden)]
+pub fn gen_and_write(
+    file_descriptors: &[FileDescriptorProto],
+    files_to_generate: &[String],
+    out_dir: &Path,
+    customize: &Customize,
+) -> io::Result<()> {
+    let results = gen(file_descriptors, files_to_generate, customize);
+
+    for r in &results {
+        let mut file_path = out_dir.to_owned();
+        file_path.push(&r.name);
+        let mut file_writer = File::create(&file_path)?;
+        file_writer.write_all(&r.content)?;
+        file_writer.flush()?;
+    }
+
+    Ok(())
+}
+
+#[doc(hidden)]
+pub fn protoc_gen_rust_main() {
+    compiler_plugin::plugin_main_2(|r| {
+        let customize = Customize::parse_from_parameter(r.parameter).expect("parse options");
+        gen(r.file_descriptors, r.files_to_generate, &customize)
+    });
+}
diff --git a/src/message.rs b/src/message.rs
new file mode 100644
index 0000000..5be3e5f
--- /dev/null
+++ b/src/message.rs
@@ -0,0 +1,562 @@
+use super::code_writer::*;
+use super::customize::customize_from_rustproto_for_message;
+use super::customize::Customize;
+use super::enums::*;
+use super::field::*;
+use super::rust_types_values::*;
+use file_descriptor::file_descriptor_proto_expr;
+use inside::protobuf_crate_path;
+use oneof::OneofGen;
+use oneof::OneofVariantGen;
+use protobuf::descriptor::*;
+use rust_name::RustIdentWithPath;
+use scope::MessageWithScope;
+use scope::RootScope;
+use scope::WithScope;
+use serde;
+
+/// Message info for codegen
+pub(crate) struct MessageGen<'a> {
+    pub message: &'a MessageWithScope<'a>,
+    pub root_scope: &'a RootScope<'a>,
+    type_name: RustIdentWithPath,
+    pub fields: Vec<FieldGen<'a>>,
+    pub lite_runtime: bool,
+    customize: Customize,
+}
+
+impl<'a> MessageGen<'a> {
+    pub fn new(
+        message: &'a MessageWithScope<'a>,
+        root_scope: &'a RootScope<'a>,
+        customize: &Customize,
+    ) -> MessageGen<'a> {
+        let mut customize = customize.clone();
+        customize.update_with(&customize_from_rustproto_for_message(
+            message.message.get_options(),
+        ));
+
+        let fields: Vec<_> = message
+            .fields()
+            .into_iter()
+            .map(|field| FieldGen::parse(field, root_scope, &customize))
+            .collect();
+        let lite_runtime = customize.lite_runtime.unwrap_or_else(|| {
+            message
+                .get_file_descriptor()
+                .get_options()
+                .get_optimize_for()
+                == FileOptions_OptimizeMode::LITE_RUNTIME
+        });
+        MessageGen {
+            message,
+            root_scope,
+            type_name: message.rust_name().into(),
+            fields,
+            lite_runtime,
+            customize,
+        }
+    }
+
+    fn expose_oneof(&self) -> bool {
+        self.customize.expose_oneof.unwrap_or(true)
+    }
+
+    fn oneofs(&'a self) -> Vec<OneofGen<'a>> {
+        self.message
+            .oneofs()
+            .into_iter()
+            .map(|oneof| OneofGen::parse(self, oneof, &self.customize))
+            .collect()
+    }
+
+    fn required_fields(&'a self) -> Vec<&'a FieldGen> {
+        self.fields
+            .iter()
+            .filter(|f| match f.kind {
+                FieldKind::Singular(ref singular) => singular.flag.is_required(),
+                _ => false,
+            })
+            .collect()
+    }
+
+    fn message_fields(&'a self) -> Vec<&'a FieldGen> {
+        self.fields
+            .iter()
+            .filter(|f| f.proto_type == FieldDescriptorProto_Type::TYPE_MESSAGE)
+            .collect()
+    }
+
+    fn fields_except_oneof(&'a self) -> Vec<&'a FieldGen> {
+        self.fields.iter().filter(|f| !f.is_oneof()).collect()
+    }
+
+    fn fields_except_group(&'a self) -> Vec<&'a FieldGen> {
+        self.fields
+            .iter()
+            .filter(|f| f.proto_type != FieldDescriptorProto_Type::TYPE_GROUP)
+            .collect()
+    }
+
+    fn fields_except_oneof_and_group(&'a self) -> Vec<&'a FieldGen> {
+        self.fields
+            .iter()
+            .filter(|f| !f.is_oneof() && f.proto_type != FieldDescriptorProto_Type::TYPE_GROUP)
+            .collect()
+    }
+
+    fn write_match_each_oneof_variant<F>(&self, w: &mut CodeWriter, cb: F)
+    where
+        F: Fn(&mut CodeWriter, &OneofVariantGen, &str, &RustType),
+    {
+        for oneof in self.oneofs() {
+            w.if_let_stmt(
+                "::std::option::Option::Some(ref v)",
+                &format!("self.{}", oneof.oneof.field_name())[..],
+                |w| {
+                    w.match_block("v", |w| {
+                        for variant in oneof.variants_except_group() {
+                            let ref field = variant.field;
+                            let (refv, vtype) = if !field.elem_type_is_copy() {
+                                ("ref v", field.elem().rust_storage_type().ref_type())
+                            } else {
+                                ("v", field.elem().rust_storage_type())
+                            };
+                            w.case_block(format!("&{}({})", variant.path(), refv), |w| {
+                                cb(w, &variant, "v", &vtype);
+                            });
+                        }
+                    });
+                },
+            );
+        }
+    }
+
+    fn write_write_to_with_cached_sizes(&self, w: &mut CodeWriter) {
+        let sig = format!(
+            "write_to_with_cached_sizes(&self, os: &mut {}::CodedOutputStream<'_>) -> {}::ProtobufResult<()>",
+            protobuf_crate_path(&self.customize),
+            protobuf_crate_path(&self.customize),
+        );
+        w.def_fn(&sig, |w| {
+            // To have access to its methods but not polute the name space.
+            for f in self.fields_except_oneof_and_group() {
+                f.write_message_write_field(w);
+            }
+            self.write_match_each_oneof_variant(w, |w, variant, v, v_type| {
+                variant.field.write_write_element(w, "os", v, v_type);
+            });
+            w.write_line("os.write_unknown_fields(self.get_unknown_fields())?;");
+            w.write_line("::std::result::Result::Ok(())");
+        });
+    }
+
+    fn write_get_cached_size(&self, w: &mut CodeWriter) {
+        w.def_fn("get_cached_size(&self) -> u32", |w| {
+            w.write_line("self.cached_size.get()");
+        });
+    }
+
+    fn write_default_instance(&self, w: &mut CodeWriter) {
+        w.def_fn(
+            &format!("default_instance() -> &'static {}", self.type_name),
+            |w| {
+                w.lazy_static_decl_get_simple(
+                    "instance",
+                    &self.type_name.to_string(),
+                    &format!("{}::new", self.type_name),
+                );
+            },
+        );
+    }
+
+    fn write_compute_size(&self, w: &mut CodeWriter) {
+        // Append sizes of messages in the tree to the specified vector.
+        // First appended element is size of self, and then nested message sizes.
+        // in serialization order are appended recursively.");
+        w.comment("Compute sizes of nested messages");
+        // there are unused variables in oneof
+        w.allow(&["unused_variables"]);
+        w.def_fn("compute_size(&self) -> u32", |w| {
+            // To have access to its methods but not polute the name space.
+            w.write_line("let mut my_size = 0;");
+            for field in self.fields_except_oneof_and_group() {
+                field.write_message_compute_field_size("my_size", w);
+            }
+            self.write_match_each_oneof_variant(w, |w, variant, v, vtype| {
+                variant.field.write_element_size(w, v, vtype, "my_size");
+            });
+            w.write_line(&format!(
+                "my_size += {}::rt::unknown_fields_size(self.get_unknown_fields());",
+                protobuf_crate_path(&self.customize)
+            ));
+            w.write_line("self.cached_size.set(my_size);");
+            w.write_line("my_size");
+        });
+    }
+
+    fn write_field_accessors(&self, w: &mut CodeWriter) {
+        for f in self.fields_except_group() {
+            w.write_line("");
+            let reconstruct_def = f.reconstruct_def();
+            w.comment(&(reconstruct_def + ";"));
+            w.write_line("");
+            f.write_message_single_field_accessors(w);
+        }
+    }
+
+    fn write_impl_self(&self, w: &mut CodeWriter) {
+        w.impl_self_block(&self.type_name.to_string(), |w| {
+            // TODO: new should probably be a part of Message trait
+            w.pub_fn(&format!("new() -> {}", self.type_name), |w| {
+                w.write_line("::std::default::Default::default()");
+            });
+
+            self.write_field_accessors(w);
+        });
+    }
+
+    fn write_unknown_fields(&self, w: &mut CodeWriter) {
+        w.def_fn(
+            "get_unknown_fields(&self) -> &::protobuf::UnknownFields",
+            |w| {
+                w.write_line("&self.unknown_fields");
+            },
+        );
+        w.write_line("");
+        w.def_fn(
+            "mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields",
+            |w| {
+                w.write_line("&mut self.unknown_fields");
+            },
+        );
+    }
+
+    fn write_merge_from(&self, w: &mut CodeWriter) {
+        let sig = format!(
+            "merge_from(&mut self, is: &mut {}::CodedInputStream<'_>) -> {}::ProtobufResult<()>",
+            protobuf_crate_path(&self.customize),
+            protobuf_crate_path(&self.customize),
+        );
+        w.def_fn(&sig, |w| {
+            w.while_block("!is.eof()?", |w| {
+                w.write_line(&format!("let (field_number, wire_type) = is.read_tag_unpack()?;"));
+                w.match_block("field_number", |w| {
+                    for f in &self.fields_except_group() {
+                        let number = f.proto_field.number();
+                        w.case_block(number.to_string(), |w| {
+                            f.write_merge_from_field("wire_type", w);
+                        });
+                    }
+                    w.case_block("_", |w| {
+                        w.write_line(&format!("{}::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;", protobuf_crate_path(&self.customize)));
+                    });
+                });
+            });
+            w.write_line("::std::result::Result::Ok(())");
+        });
+    }
+
+    fn write_descriptor_field(&self, fields_var: &str, field: &FieldGen, w: &mut CodeWriter) {
+        let accessor_fn = field.accessor_fn();
+        w.write_line(&format!(
+            "{}.push(::protobuf::reflect::accessor::{}(",
+            fields_var,
+            accessor_fn.sig()
+        ));
+        w.indented(|w| {
+            w.write_line(&format!("\"{}\",", field.proto_field.name()));
+            match accessor_fn.style {
+                AccessorStyle::Lambda => {
+                    w.write_line(&format!(
+                        "|m: &{}| {{ &m.{} }},",
+                        self.type_name, field.rust_name
+                    ));
+                    w.write_line(&format!(
+                        "|m: &mut {}| {{ &mut m.{} }},",
+                        self.type_name, field.rust_name
+                    ));
+                }
+                AccessorStyle::HasGet => {
+                    w.write_line(&format!("{}::has_{},", self.type_name, field.rust_name));
+                    w.write_line(&format!("{}::get_{},", self.type_name, field.rust_name));
+                }
+            }
+        });
+        w.write_line("));");
+    }
+
+    fn write_descriptor_static(&self, w: &mut CodeWriter) {
+        w.def_fn(
+            &format!("descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor"),
+            |w| {
+                w.lazy_static_decl_get(
+                    "descriptor",
+                    "::protobuf::reflect::MessageDescriptor",
+                    |w| {
+                        let fields = self.fields_except_group();
+                        if fields.is_empty() {
+                            w.write_line(&format!("let fields = ::std::vec::Vec::new();"));
+                        } else {
+                            w.write_line(&format!("let mut fields = ::std::vec::Vec::new();"));
+                        }
+                        for field in fields {
+                            self.write_descriptor_field("fields", field, w);
+                        }
+                        w.write_line(&format!(
+                            "::protobuf::reflect::MessageDescriptor::new_pb_name::<{}>(",
+                            self.type_name
+                        ));
+                        w.indented(|w| {
+                            w.write_line(&format!("\"{}\",", self.message.name_to_package()));
+                            w.write_line("fields,");
+                            w.write_line(&file_descriptor_proto_expr(&self.message.scope));
+                        });
+                        w.write_line(")");
+                    },
+                );
+            },
+        );
+    }
+
+    fn write_is_initialized(&self, w: &mut CodeWriter) {
+        w.def_fn(&format!("is_initialized(&self) -> bool"), |w| {
+            // TODO: use single loop
+
+            for f in self.required_fields() {
+                f.write_if_self_field_is_none(w, |w| {
+                    w.write_line("return false;");
+                });
+            }
+
+            for f in self.message_fields() {
+                if let FieldKind::Map(..) = f.kind {
+                    // TODO: check values
+                    continue;
+                }
+
+                // TODO:
+                // if message is declared in this file and has no message fields,
+                // we could skip the check here
+                f.write_for_self_field(w, "v", |w, _t| {
+                    w.if_stmt("!v.is_initialized()", |w| {
+                        w.write_line("return false;");
+                    });
+                });
+            }
+            w.write_line("true");
+        });
+    }
+
+    fn write_impl_message(&self, w: &mut CodeWriter) {
+        w.impl_for_block("::protobuf::Message", &self.type_name.to_string(), |w| {
+            self.write_is_initialized(w);
+            w.write_line("");
+            self.write_merge_from(w);
+            w.write_line("");
+            self.write_compute_size(w);
+            w.write_line("");
+            self.write_write_to_with_cached_sizes(w);
+            w.write_line("");
+            self.write_get_cached_size(w);
+            w.write_line("");
+            self.write_unknown_fields(w);
+            w.write_line("");
+            w.def_fn("as_any(&self) -> &dyn (::std::any::Any)", |w| {
+                w.write_line("self as &dyn (::std::any::Any)");
+            });
+            w.def_fn("as_any_mut(&mut self) -> &mut dyn (::std::any::Any)", |w| {
+                w.write_line("self as &mut dyn (::std::any::Any)");
+            });
+            w.def_fn(
+                "into_any(self: Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)>",
+                |w| {
+                    w.write_line("self");
+                },
+            );
+            w.write_line("");
+            w.def_fn(
+                "descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor",
+                |w| {
+                    w.write_line("Self::descriptor_static()");
+                },
+            );
+            w.write_line("");
+            w.def_fn(&format!("new() -> {}", self.type_name), |w| {
+                w.write_line(&format!("{}::new()", self.type_name));
+            });
+            if !self.lite_runtime {
+                w.write_line("");
+                self.write_descriptor_static(w);
+            }
+            w.write_line("");
+            self.write_default_instance(w);
+        });
+    }
+
+    fn write_impl_value(&self, w: &mut CodeWriter) {
+        w.impl_for_block(
+            "::protobuf::reflect::ProtobufValue",
+            &self.type_name.to_string(),
+            |w| {
+                w.def_fn(
+                    "as_ref(&self) -> ::protobuf::reflect::ReflectValueRef",
+                    |w| w.write_line("::protobuf::reflect::ReflectValueRef::Message(self)"),
+                )
+            },
+        )
+    }
+
+    fn write_impl_show(&self, w: &mut CodeWriter) {
+        w.impl_for_block("::std::fmt::Debug", &self.type_name.to_string(), |w| {
+            w.def_fn(
+                "fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result",
+                |w| {
+                    w.write_line("::protobuf::text_format::fmt(self, f)");
+                },
+            );
+        });
+    }
+
+    fn write_impl_clear(&self, w: &mut CodeWriter) {
+        w.impl_for_block("::protobuf::Clear", &self.type_name.to_string(), |w| {
+            w.def_fn("clear(&mut self)", |w| {
+                for f in self.fields_except_group() {
+                    f.write_clear(w);
+                }
+                w.write_line("self.unknown_fields.clear();");
+            });
+        });
+    }
+
+    #[allow(dead_code)]
+    fn supports_derive_partial_eq(&self) -> bool {
+        // There's stack overflow in the compiler when struct has too many fields
+        // https://github.com/rust-lang/rust/issues/40119
+        self.fields.len() <= 500
+    }
+
+    fn write_struct(&self, w: &mut CodeWriter) {
+        let mut derive = vec!["PartialEq", "Clone", "Default"];
+        if self.lite_runtime {
+            derive.push("Debug");
+        }
+        w.derive(&derive);
+        serde::write_serde_attr(w, &self.customize, "derive(Serialize, Deserialize)");
+        w.pub_struct(&self.type_name.to_string(), |w| {
+            if !self.fields_except_oneof().is_empty() {
+                w.comment("message fields");
+                for field in self.fields_except_oneof() {
+                    if field.proto_type == FieldDescriptorProto_Type::TYPE_GROUP {
+                        w.comment(&format!("{}: <group>", &field.rust_name));
+                    } else {
+                        let vis = if field.expose_field {
+                            Visibility::Public
+                        } else {
+                            match field.kind {
+                                FieldKind::Repeated(..) => Visibility::Default,
+                                FieldKind::Singular(SingularField { ref flag, .. }) => {
+                                    match *flag {
+                                        SingularFieldFlag::WithFlag { .. } => Visibility::Default,
+                                        SingularFieldFlag::WithoutFlag => Visibility::Public,
+                                    }
+                                }
+                                FieldKind::Map(..) => Visibility::Public,
+                                FieldKind::Oneof(..) => unreachable!(),
+                            }
+                        };
+                        w.field_decl_vis(
+                            vis,
+                            &field.rust_name.get(),
+                            &field.full_storage_type().to_code(&self.customize),
+                        );
+                    }
+                }
+            }
+            if !self.oneofs().is_empty() {
+                w.comment("message oneof groups");
+                for oneof in self.oneofs() {
+                    let vis = match self.expose_oneof() {
+                        true => Visibility::Public,
+                        false => Visibility::Default,
+                    };
+                    w.field_decl_vis(
+                        vis,
+                        oneof.oneof.field_name().get(),
+                        &oneof.full_storage_type().to_code(&self.customize),
+                    );
+                }
+            }
+            w.comment("special fields");
+            serde::write_serde_attr(w, &self.customize, "serde(skip)");
+            w.pub_field_decl(
+                "unknown_fields",
+                &format!("{}::UnknownFields", protobuf_crate_path(&self.customize)),
+            );
+            serde::write_serde_attr(w, &self.customize, "serde(skip)");
+            w.pub_field_decl(
+                "cached_size",
+                &format!("{}::CachedSize", protobuf_crate_path(&self.customize)),
+            );
+        });
+    }
+
+    fn write_impl_default_for_amp(&self, w: &mut CodeWriter) {
+        w.impl_args_for_block(
+            &["'a"],
+            "::std::default::Default",
+            &format!("&'a {}", self.type_name),
+            |w| {
+                w.def_fn(&format!("default() -> &'a {}", self.type_name), |w| {
+                    w.write_line(&format!(
+                        "<{} as {}::Message>::default_instance()",
+                        self.type_name,
+                        protobuf_crate_path(&self.customize),
+                    ));
+                });
+            },
+        );
+    }
+
+    pub fn write(&self, w: &mut CodeWriter) {
+        self.write_struct(w);
+
+        w.write_line("");
+        self.write_impl_default_for_amp(w);
+
+        for oneof in self.oneofs() {
+            w.write_line("");
+            oneof.write_enum(w);
+        }
+
+        w.write_line("");
+        self.write_impl_self(w);
+        w.write_line("");
+        self.write_impl_message(w);
+        w.write_line("");
+        self.write_impl_clear(w);
+        if !self.lite_runtime {
+            w.write_line("");
+            self.write_impl_show(w);
+        }
+        w.write_line("");
+        self.write_impl_value(w);
+
+        let mut nested_prefix = self.type_name.to_string();
+        nested_prefix.push_str("_");
+
+        for nested in &self.message.to_scope().get_messages() {
+            // ignore map entries, because they are not used in map fields
+            if nested.map_entry().is_none() {
+                w.write_line("");
+                MessageGen::new(nested, self.root_scope, &self.customize).write(w);
+            }
+        }
+
+        for enum_type in &self.message.to_scope().get_enums() {
+            w.write_line("");
+            let current_file = self.message.get_scope().get_file_descriptor();
+            EnumGen::new(enum_type, current_file, &self.customize, self.root_scope).write(w);
+        }
+    }
+}
diff --git a/src/oneof.rs b/src/oneof.rs
new file mode 100644
index 0000000..82aba7d
--- /dev/null
+++ b/src/oneof.rs
@@ -0,0 +1,195 @@
+//! Oneof-related codegen functions.
+
+use code_writer::CodeWriter;
+use field::FieldElem;
+use field::FieldGen;
+use message::MessageGen;
+use protobuf::descriptor::FieldDescriptorProto_Type;
+use protobuf_name::ProtobufAbsolutePath;
+use rust_name::RustIdent;
+use rust_types_values::RustType;
+use scope::FieldWithContext;
+use scope::OneofVariantWithContext;
+use scope::OneofWithContext;
+use scope::RootScope;
+use scope::WithScope;
+use serde;
+use std::collections::HashSet;
+use Customize;
+
+// oneof one { ... }
+#[derive(Clone)]
+pub(crate) struct OneofField<'a> {
+    pub elem: FieldElem<'a>,
+    pub oneof_rust_field_name: RustIdent,
+    pub oneof_type_name: RustType,
+    pub boxed: bool,
+}
+
+impl<'a> OneofField<'a> {
+    // Detecting recursion: if oneof fields contains a self-reference
+    // or another message which has a reference to self,
+    // put oneof variant into a box.
+    fn need_boxed(field: &FieldWithContext, root_scope: &RootScope, owner_name: &str) -> bool {
+        let mut visited_messages = HashSet::new();
+        let mut fields = vec![field.clone()];
+        while let Some(field) = fields.pop() {
+            if field.field.get_field_type() == FieldDescriptorProto_Type::TYPE_MESSAGE {
+                let message_name = ProtobufAbsolutePath::from(field.field.get_type_name());
+                if !visited_messages.insert(message_name.clone()) {
+                    continue;
+                }
+                if message_name.path == owner_name {
+                    return true;
+                }
+                let message = root_scope.find_message(&message_name);
+                fields.extend(message.fields().into_iter().filter(|f| f.is_oneof()));
+            }
+        }
+        false
+    }
+
+    pub fn parse(
+        oneof: &OneofWithContext<'a>,
+        field: &FieldWithContext<'a>,
+        elem: FieldElem<'a>,
+        root_scope: &RootScope,
+    ) -> OneofField<'a> {
+        let boxed = OneofField::need_boxed(field, root_scope, &oneof.message.name_absolute().path);
+
+        OneofField {
+            elem,
+            boxed,
+            oneof_rust_field_name: oneof.field_name().into(),
+            oneof_type_name: RustType::Oneof(oneof.rust_name().to_string()),
+        }
+    }
+
+    pub fn rust_type(&self) -> RustType {
+        let t = self.elem.rust_storage_type();
+
+        if self.boxed {
+            RustType::Uniq(Box::new(t))
+        } else {
+            t
+        }
+    }
+}
+
+#[derive(Clone)]
+pub(crate) struct OneofVariantGen<'a> {
+    oneof: &'a OneofGen<'a>,
+    variant: OneofVariantWithContext<'a>,
+    oneof_field: OneofField<'a>,
+    pub field: FieldGen<'a>,
+    path: String,
+    customize: Customize,
+}
+
+impl<'a> OneofVariantGen<'a> {
+    fn parse(
+        oneof: &'a OneofGen<'a>,
+        variant: OneofVariantWithContext<'a>,
+        field: &'a FieldGen,
+        _root_scope: &RootScope,
+        customize: Customize,
+    ) -> OneofVariantGen<'a> {
+        OneofVariantGen {
+            oneof,
+            variant: variant.clone(),
+            field: field.clone(),
+            path: format!(
+                "{}::{}",
+                oneof.type_name.to_code(&field.customize),
+                field.rust_name
+            ),
+            oneof_field: OneofField::parse(
+                variant.oneof,
+                &field.proto_field,
+                field.oneof().elem.clone(),
+                oneof.message.root_scope,
+            ),
+            customize,
+        }
+    }
+
+    fn rust_type(&self) -> RustType {
+        self.oneof_field.rust_type()
+    }
+
+    pub fn path(&self) -> String {
+        self.path.clone()
+    }
+}
+
+#[derive(Clone)]
+pub(crate) struct OneofGen<'a> {
+    // Message containing this oneof
+    message: &'a MessageGen<'a>,
+    pub oneof: OneofWithContext<'a>,
+    type_name: RustType,
+    lite_runtime: bool,
+    customize: Customize,
+}
+
+impl<'a> OneofGen<'a> {
+    pub fn parse(
+        message: &'a MessageGen,
+        oneof: OneofWithContext<'a>,
+        customize: &Customize,
+    ) -> OneofGen<'a> {
+        let rust_name = oneof.rust_name();
+        OneofGen {
+            message,
+            oneof,
+            type_name: RustType::Oneof(rust_name.to_string()),
+            lite_runtime: message.lite_runtime,
+            customize: customize.clone(),
+        }
+    }
+
+    pub fn variants_except_group(&'a self) -> Vec<OneofVariantGen<'a>> {
+        self.oneof
+            .variants()
+            .into_iter()
+            .filter_map(|v| {
+                let field = self
+                    .message
+                    .fields
+                    .iter()
+                    .filter(|f| f.proto_field.name() == v.field.get_name())
+                    .next()
+                    .expect(&format!("field not found by name: {}", v.field.get_name()));
+                match field.proto_type {
+                    FieldDescriptorProto_Type::TYPE_GROUP => None,
+                    _ => Some(OneofVariantGen::parse(
+                        self,
+                        v,
+                        field,
+                        self.message.root_scope,
+                        self.customize.clone(),
+                    )),
+                }
+            })
+            .collect()
+    }
+
+    pub fn full_storage_type(&self) -> RustType {
+        RustType::Option(Box::new(self.type_name.clone()))
+    }
+
+    pub fn write_enum(&self, w: &mut CodeWriter) {
+        let derive = vec!["Clone", "PartialEq", "Debug"];
+        w.derive(&derive);
+        serde::write_serde_attr(w, &self.customize, "derive(Serialize, Deserialize)");
+        w.pub_enum(&self.type_name.to_code(&self.customize), |w| {
+            for variant in self.variants_except_group() {
+                w.write_line(&format!(
+                    "{}({}),",
+                    variant.field.rust_name,
+                    &variant.rust_type().to_code(&self.customize)
+                ));
+            }
+        });
+    }
+}
diff --git a/src/protobuf_name.rs b/src/protobuf_name.rs
new file mode 100644
index 0000000..c219394
--- /dev/null
+++ b/src/protobuf_name.rs
@@ -0,0 +1,339 @@
+use std::fmt;
+
+/// Identifier in `.proto` file
+#[derive(Eq, PartialEq, Debug, Clone)]
+pub struct ProtobufIdent(String);
+
+impl ProtobufIdent {
+    #[allow(dead_code)]
+    pub fn new(s: &str) -> ProtobufIdent {
+        assert!(!s.is_empty());
+        assert!(!s.contains("/"));
+        assert!(!s.contains("."));
+        assert!(!s.contains(":"));
+        ProtobufIdent(s.to_owned())
+    }
+
+    pub fn get(&self) -> &str {
+        &self.0
+    }
+}
+
+impl From<&'_ str> for ProtobufIdent {
+    fn from(s: &str) -> Self {
+        ProtobufIdent::new(s)
+    }
+}
+
+impl From<String> for ProtobufIdent {
+    fn from(s: String) -> Self {
+        ProtobufIdent::new(&s)
+    }
+}
+
+impl fmt::Display for ProtobufIdent {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.get(), f)
+    }
+}
+
+#[derive(Debug, Eq, PartialEq, Clone)]
+pub struct ProtobufRelativePath {
+    pub path: String,
+}
+
+#[allow(dead_code)]
+impl ProtobufRelativePath {
+    pub fn empty() -> ProtobufRelativePath {
+        ProtobufRelativePath::new(String::new())
+    }
+
+    pub fn new(path: String) -> ProtobufRelativePath {
+        assert!(!path.starts_with("."));
+
+        ProtobufRelativePath { path }
+    }
+
+    pub fn from_components<I: IntoIterator<Item = ProtobufIdent>>(i: I) -> ProtobufRelativePath {
+        let v: Vec<String> = i.into_iter().map(|c| c.get().to_owned()).collect();
+        ProtobufRelativePath::from(v.join("."))
+    }
+
+    pub fn get(&self) -> &str {
+        &self.path
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.path.is_empty()
+    }
+
+    pub fn into_absolute(self) -> ProtobufAbsolutePath {
+        if self.is_empty() {
+            ProtobufAbsolutePath::root()
+        } else {
+            ProtobufAbsolutePath::from(format!(".{}", self))
+        }
+    }
+
+    fn _last_part(&self) -> Option<&str> {
+        match self.path.rfind('.') {
+            Some(pos) => Some(&self.path[pos + 1..]),
+            None => {
+                if self.path.is_empty() {
+                    None
+                } else {
+                    Some(&self.path)
+                }
+            }
+        }
+    }
+
+    fn parent(&self) -> Option<ProtobufRelativePath> {
+        match self.path.rfind('.') {
+            Some(pos) => Some(ProtobufRelativePath::new(self.path[..pos].to_owned())),
+            None => {
+                if self.path.is_empty() {
+                    None
+                } else {
+                    Some(ProtobufRelativePath::empty())
+                }
+            }
+        }
+    }
+
+    pub fn self_and_parents(&self) -> Vec<ProtobufRelativePath> {
+        let mut tmp = self.clone();
+
+        let mut r = Vec::new();
+
+        r.push(self.clone());
+
+        while let Some(parent) = tmp.parent() {
+            r.push(parent.clone());
+            tmp = parent;
+        }
+
+        r
+    }
+
+    pub fn append(&self, simple: &ProtobufRelativePath) -> ProtobufRelativePath {
+        if self.path.is_empty() {
+            ProtobufRelativePath::from(simple.get())
+        } else {
+            ProtobufRelativePath::new(format!("{}.{}", self.path, simple))
+        }
+    }
+
+    pub fn append_ident(&self, simple: &ProtobufIdent) -> ProtobufRelativePath {
+        self.append(&ProtobufRelativePath::from(simple.clone()))
+    }
+
+    pub fn split_first_rem(&self) -> Option<(ProtobufIdent, ProtobufRelativePath)> {
+        if self.is_empty() {
+            None
+        } else {
+            Some(match self.path.find('.') {
+                Some(dot) => (
+                    ProtobufIdent::from(&self.path[..dot]),
+                    ProtobufRelativePath::new(self.path[dot + 1..].to_owned()),
+                ),
+                None => (
+                    ProtobufIdent::from(self.path.clone()),
+                    ProtobufRelativePath::empty(),
+                ),
+            })
+        }
+    }
+}
+
+impl From<&'_ str> for ProtobufRelativePath {
+    fn from(s: &str) -> ProtobufRelativePath {
+        ProtobufRelativePath::from(s.to_owned())
+    }
+}
+
+impl From<String> for ProtobufRelativePath {
+    fn from(s: String) -> ProtobufRelativePath {
+        ProtobufRelativePath::new(s)
+    }
+}
+
+impl From<ProtobufIdent> for ProtobufRelativePath {
+    fn from(s: ProtobufIdent) -> ProtobufRelativePath {
+        ProtobufRelativePath::from(s.get())
+    }
+}
+
+impl From<Vec<ProtobufIdent>> for ProtobufRelativePath {
+    fn from(s: Vec<ProtobufIdent>) -> ProtobufRelativePath {
+        ProtobufRelativePath::from_components(s.into_iter())
+    }
+}
+
+impl fmt::Display for ProtobufRelativePath {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.path, f)
+    }
+}
+
+#[cfg(test)]
+mod relative_path_test {
+    use super::*;
+
+    #[test]
+    fn parent() {
+        assert_eq!(None, ProtobufRelativePath::empty().parent());
+        assert_eq!(
+            Some(ProtobufRelativePath::empty()),
+            ProtobufRelativePath::new("aaa".to_owned()).parent()
+        );
+        assert_eq!(
+            Some(ProtobufRelativePath::new("abc".to_owned())),
+            ProtobufRelativePath::new("abc.def".to_owned()).parent()
+        );
+        assert_eq!(
+            Some(ProtobufRelativePath::new("abc.def".to_owned())),
+            ProtobufRelativePath::new("abc.def.gh".to_owned()).parent()
+        );
+    }
+
+    #[test]
+    fn last_part() {
+        assert_eq!(None, ProtobufRelativePath::empty()._last_part());
+        assert_eq!(
+            Some("aaa"),
+            ProtobufRelativePath::new("aaa".to_owned())._last_part()
+        );
+        assert_eq!(
+            Some("def"),
+            ProtobufRelativePath::new("abc.def".to_owned())._last_part()
+        );
+        assert_eq!(
+            Some("gh"),
+            ProtobufRelativePath::new("abc.def.gh".to_owned())._last_part()
+        );
+    }
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Hash)]
+pub struct ProtobufAbsolutePath {
+    pub path: String,
+}
+
+impl ProtobufAbsolutePath {
+    fn root() -> ProtobufAbsolutePath {
+        ProtobufAbsolutePath::new(String::new())
+    }
+
+    pub fn new(path: String) -> ProtobufAbsolutePath {
+        assert!(path.is_empty() || path.starts_with("."), path);
+        assert!(!path.ends_with("."), path);
+        ProtobufAbsolutePath { path }
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.path.is_empty()
+    }
+
+    pub fn from_path_without_dot(path: &str) -> ProtobufAbsolutePath {
+        if path.is_empty() {
+            ProtobufAbsolutePath::root()
+        } else {
+            assert!(!path.starts_with("."));
+            assert!(!path.ends_with("."));
+            ProtobufAbsolutePath::new(format!(".{}", path))
+        }
+    }
+
+    #[allow(dead_code)]
+    pub fn from_path_maybe_dot(path: &str) -> ProtobufAbsolutePath {
+        if path.starts_with(".") {
+            ProtobufAbsolutePath::new(path.to_owned())
+        } else {
+            ProtobufAbsolutePath::from_path_without_dot(path)
+        }
+    }
+
+    pub fn push_simple(&mut self, simple: ProtobufIdent) {
+        self.path.push('.');
+        self.path.push_str(simple.get());
+    }
+
+    pub fn push_relative(&mut self, relative: &ProtobufRelativePath) {
+        if !relative.is_empty() {
+            self.path.push('.');
+            self.path.push_str(&relative.path);
+        }
+    }
+
+    pub fn remove_prefix(&self, prefix: &ProtobufAbsolutePath) -> Option<ProtobufRelativePath> {
+        if self.path.starts_with(&prefix.path) {
+            let rem = &self.path[prefix.path.len()..];
+            if rem.is_empty() {
+                return Some(ProtobufRelativePath::empty());
+            }
+            if rem.starts_with('.') {
+                return Some(ProtobufRelativePath::new(rem[1..].to_owned()));
+            }
+        }
+        None
+    }
+}
+
+impl From<&'_ str> for ProtobufAbsolutePath {
+    fn from(s: &str) -> Self {
+        ProtobufAbsolutePath::new(s.to_owned())
+    }
+}
+
+impl From<String> for ProtobufAbsolutePath {
+    fn from(s: String) -> Self {
+        ProtobufAbsolutePath::new(s)
+    }
+}
+
+impl fmt::Display for ProtobufAbsolutePath {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.path, f)
+    }
+}
+
+#[cfg(test)]
+mod absolute_path_test {
+    use super::*;
+
+    #[test]
+    fn absolute_path_push_simple() {
+        let mut foo = ProtobufAbsolutePath::new(".foo".to_owned());
+        foo.push_simple(ProtobufIdent::from("bar"));
+        assert_eq!(ProtobufAbsolutePath::new(".foo.bar".to_owned()), foo);
+
+        let mut foo = ProtobufAbsolutePath::root();
+        foo.push_simple(ProtobufIdent::from("bar"));
+        assert_eq!(ProtobufAbsolutePath::new(".bar".to_owned()), foo);
+    }
+
+    #[test]
+    fn absolute_path_remove_prefix() {
+        assert_eq!(
+            Some(ProtobufRelativePath::empty()),
+            ProtobufAbsolutePath::new(".foo".to_owned())
+                .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned()))
+        );
+        assert_eq!(
+            Some(ProtobufRelativePath::new("bar".to_owned())),
+            ProtobufAbsolutePath::new(".foo.bar".to_owned())
+                .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned()))
+        );
+        assert_eq!(
+            Some(ProtobufRelativePath::new("baz.qux".to_owned())),
+            ProtobufAbsolutePath::new(".foo.bar.baz.qux".to_owned())
+                .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned()))
+        );
+        assert_eq!(
+            None,
+            ProtobufAbsolutePath::new(".foo.barbaz".to_owned())
+                .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned()))
+        );
+    }
+}
diff --git a/src/rust.rs b/src/rust.rs
new file mode 100644
index 0000000..263cba0
--- /dev/null
+++ b/src/rust.rs
@@ -0,0 +1,62 @@
+#[cfg_attr(rustfmt, rustfmt_skip)]
+static RUST_KEYWORDS: &'static [&'static str] = &[
+    "as",
+    "async",
+    "await",
+    "break",
+    "crate",
+    "dyn",
+    "else",
+    "enum",
+    "extern",
+    "false",
+    "fn",
+    "for",
+    "if",
+    "impl",
+    "in",
+    "let",
+    "loop",
+    "match",
+    "mod",
+    "move",
+    "mut",
+    "pub",
+    "ref",
+    "return",
+    "static",
+    "self",
+    "Self",
+    "struct",
+    "super",
+    "true",
+    "trait",
+    "type",
+    "unsafe",
+    "use",
+    "while",
+    "continue",
+    "box",
+    "const",
+    "where",
+    "virtual",
+    "proc",
+    "alignof",
+    "become",
+    "offsetof",
+    "priv",
+    "pure",
+    "sizeof",
+    "typeof",
+    "unsized",
+    "yield",
+    "do",
+    "abstract",
+    "final",
+    "override",
+    "macro",
+];
+
+pub fn is_rust_keyword(ident: &str) -> bool {
+    RUST_KEYWORDS.contains(&ident)
+}
diff --git a/src/rust_name.rs b/src/rust_name.rs
new file mode 100644
index 0000000..234925b
--- /dev/null
+++ b/src/rust_name.rs
@@ -0,0 +1,273 @@
+use std::fmt;
+use std::iter;
+
+/// Valid Rust identifier
+#[derive(Eq, PartialEq, Debug, Clone)]
+pub(crate) struct RustIdent(String);
+
+#[allow(dead_code)]
+impl RustIdent {
+    pub fn new(s: &str) -> RustIdent {
+        assert!(!s.is_empty());
+        assert!(!s.contains("/"), "{}", s);
+        assert!(!s.contains("."), "{}", s);
+        assert!(!s.contains(":"), "{}", s);
+        RustIdent(s.to_owned())
+    }
+
+    pub fn super_ident() -> RustIdent {
+        RustIdent::new("super")
+    }
+
+    pub fn get(&self) -> &str {
+        &self.0
+    }
+
+    pub fn into_string(self) -> String {
+        self.0
+    }
+
+    pub fn to_path(&self) -> RustIdentWithPath {
+        RustIdentWithPath::from(&self.0)
+    }
+}
+
+impl fmt::Display for RustIdent {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.get(), f)
+    }
+}
+
+impl From<&'_ str> for RustIdent {
+    fn from(s: &str) -> Self {
+        RustIdent::new(s)
+    }
+}
+
+impl From<String> for RustIdent {
+    fn from(s: String) -> Self {
+        RustIdent::new(&s)
+    }
+}
+
+impl Into<String> for RustIdent {
+    fn into(self) -> String {
+        self.0
+    }
+}
+
+#[derive(Default, Eq, PartialEq, Debug, Clone)]
+pub(crate) struct RustRelativePath {
+    path: Vec<RustIdent>,
+}
+
+#[allow(dead_code)]
+impl RustRelativePath {
+    pub fn into_path(self) -> RustPath {
+        RustPath {
+            absolute: false,
+            path: self,
+        }
+    }
+
+    pub fn empty() -> RustRelativePath {
+        RustRelativePath { path: Vec::new() }
+    }
+
+    pub fn from_components<I: IntoIterator<Item = RustIdent>>(i: I) -> RustRelativePath {
+        RustRelativePath {
+            path: i.into_iter().collect(),
+        }
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.path.is_empty()
+    }
+
+    pub fn first(&self) -> Option<RustIdent> {
+        self.path.iter().cloned().next()
+    }
+
+    pub fn remove_first(&mut self) -> Option<RustIdent> {
+        if self.path.is_empty() {
+            None
+        } else {
+            Some(self.path.remove(0))
+        }
+    }
+
+    pub fn prepend_ident(&mut self, ident: RustIdent) {
+        self.path.insert(0, ident);
+    }
+
+    pub fn append(mut self, path: RustRelativePath) -> RustRelativePath {
+        for c in path.path {
+            self.path.push(c);
+        }
+        self
+    }
+
+    pub fn push_ident(&mut self, ident: RustIdent) {
+        self.path.push(ident);
+    }
+
+    pub fn _append_ident(mut self, ident: RustIdent) -> RustRelativePath {
+        self.push_ident(ident);
+        self
+    }
+
+    pub fn to_reverse(&self) -> RustRelativePath {
+        RustRelativePath::from_components(
+            iter::repeat(RustIdent::super_ident()).take(self.path.len()),
+        )
+    }
+}
+
+#[derive(Default, Eq, PartialEq, Debug, Clone)]
+pub(crate) struct RustPath {
+    absolute: bool,
+    path: RustRelativePath,
+}
+
+impl fmt::Display for RustRelativePath {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        for (i, c) in self.path.iter().enumerate() {
+            if i != 0 {
+                write!(f, "::")?;
+            }
+            write!(f, "{}", c)?;
+        }
+        Ok(())
+    }
+}
+
+impl From<&'_ str> for RustRelativePath {
+    fn from(s: &str) -> Self {
+        RustRelativePath {
+            path: s.split("::").map(RustIdent::from).collect(),
+        }
+    }
+}
+
+#[allow(dead_code)]
+impl RustPath {
+    pub fn is_absolute(&self) -> bool {
+        self.absolute
+    }
+
+    pub fn is_empty(&self) -> bool {
+        assert!(!self.absolute);
+        self.path.is_empty()
+    }
+
+    pub fn with_ident(self, ident: RustIdent) -> RustIdentWithPath {
+        RustIdentWithPath { path: self, ident }
+    }
+
+    pub fn first(&self) -> Option<RustIdent> {
+        assert!(!self.absolute);
+        self.path.first()
+    }
+
+    pub fn remove_first(&mut self) -> Option<RustIdent> {
+        assert!(!self.absolute);
+        self.path.remove_first()
+    }
+
+    pub fn to_reverse(&self) -> RustPath {
+        assert!(!self.absolute);
+        RustPath {
+            absolute: false,
+            path: self.path.to_reverse(),
+        }
+    }
+
+    pub fn prepend_ident(&mut self, ident: RustIdent) {
+        assert!(!self.absolute);
+        self.path.prepend_ident(ident);
+    }
+
+    pub fn append(self, path: RustPath) -> RustPath {
+        if path.absolute {
+            path
+        } else {
+            RustPath {
+                absolute: self.absolute,
+                path: self.path.append(path.path),
+            }
+        }
+    }
+
+    pub fn append_ident(mut self, ident: RustIdent) -> RustPath {
+        self.path.path.push(ident);
+        self
+    }
+
+    pub fn append_with_ident(self, path: RustIdentWithPath) -> RustIdentWithPath {
+        self.append(path.path).with_ident(path.ident)
+    }
+}
+
+impl From<&'_ str> for RustPath {
+    fn from(s: &str) -> Self {
+        let (s, absolute) = if s.starts_with("::") {
+            (&s[2..], true)
+        } else {
+            (s, false)
+        };
+        RustPath {
+            absolute,
+            path: RustRelativePath::from(s),
+        }
+    }
+}
+
+impl From<String> for RustPath {
+    fn from(s: String) -> Self {
+        RustPath::from(&s[..])
+    }
+}
+
+impl fmt::Display for RustPath {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if self.absolute {
+            write!(f, "::")?;
+        }
+        write!(f, "{}", self.path)
+    }
+}
+
+#[derive(Eq, PartialEq, Debug, Clone)]
+pub(crate) struct RustIdentWithPath {
+    pub path: RustPath,
+    pub ident: RustIdent,
+}
+
+#[allow(dead_code)]
+impl RustIdentWithPath {
+    pub fn new(s: String) -> RustIdentWithPath {
+        let mut path = RustPath::from(s);
+        let ident = path.path.path.pop().unwrap();
+        RustIdentWithPath { path, ident }
+    }
+
+    pub fn prepend_ident(&mut self, ident: RustIdent) {
+        self.path.prepend_ident(ident)
+    }
+
+    pub fn to_path(&self) -> RustPath {
+        self.path.clone().append_ident(self.ident.clone())
+    }
+}
+
+impl<S: Into<String>> From<S> for RustIdentWithPath {
+    fn from(s: S) -> Self {
+        RustIdentWithPath::new(s.into())
+    }
+}
+
+impl fmt::Display for RustIdentWithPath {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.to_path(), f)
+    }
+}
diff --git a/src/rust_types_values.rs b/src/rust_types_values.rs
new file mode 100644
index 0000000..7f32eec
--- /dev/null
+++ b/src/rust_types_values.rs
@@ -0,0 +1,563 @@
+use std::cmp;
+
+use super::well_known_types::is_well_known_type_full;
+use inside::protobuf_crate_path;
+use protobuf::descriptor::*;
+use protobuf_name::ProtobufAbsolutePath;
+use rust_name::RustIdent;
+use scope::RootScope;
+use scope::WithScope;
+use strx::capitalize;
+use Customize;
+
+// Represent subset of rust types used in generated code
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) enum RustType {
+    // integer: signed?, size in bits
+    Int(bool, u32),
+    // param is size in bits
+    Float(u32),
+    Bool,
+    Vec(Box<RustType>),
+    HashMap(Box<RustType>, Box<RustType>),
+    String,
+    // [T], not &[T]
+    Slice(Box<RustType>),
+    // str, not &str
+    Str,
+    Option(Box<RustType>),
+    SingularField(Box<RustType>),
+    SingularPtrField(Box<RustType>),
+    RepeatedField(Box<RustType>),
+    // Box<T>
+    Uniq(Box<RustType>),
+    // &T
+    Ref(Box<RustType>),
+    // protobuf message
+    Message(String),
+    // protobuf enum, not any enum
+    Enum(String, RustIdent),
+    // oneof enum
+    Oneof(String),
+    // bytes::Bytes
+    Bytes,
+    // chars::Chars
+    Chars,
+    // group
+    Group,
+}
+
+impl RustType {
+    #[inline]
+    pub(crate) fn to_code(&self, customize: &Customize) -> String {
+        match *self {
+            RustType::Int(true, bits) => format!("i{}", bits),
+            RustType::Int(false, bits) => format!("u{}", bits),
+            RustType::Float(bits) => format!("f{}", bits),
+            RustType::Bool => format!("bool"),
+            RustType::Vec(ref param) => format!("::std::vec::Vec<{}>", param.to_code(customize)),
+            RustType::HashMap(ref key, ref value) => format!(
+                "::std::collections::HashMap<{}, {}>",
+                key.to_code(customize),
+                value.to_code(customize)
+            ),
+            RustType::String => format!("::std::string::String"),
+            RustType::Slice(ref param) => format!("[{}]", param.to_code(customize)),
+            RustType::Str => format!("str"),
+            RustType::Option(ref param) => {
+                format!("::std::option::Option<{}>", param.to_code(customize))
+            }
+            RustType::SingularField(ref param) => format!(
+                "{}::SingularField<{}>",
+                protobuf_crate_path(customize),
+                param.to_code(customize)
+            ),
+            RustType::SingularPtrField(ref param) => format!(
+                "{}::SingularPtrField<{}>",
+                protobuf_crate_path(customize),
+                param.to_code(customize)
+            ),
+            RustType::RepeatedField(ref param) => format!(
+                "{}::RepeatedField<{}>",
+                protobuf_crate_path(customize),
+                param.to_code(customize)
+            ),
+            RustType::Uniq(ref param) => format!("::std::boxed::Box<{}>", param.to_code(customize)),
+            RustType::Ref(ref param) => format!("&{}", param.to_code(customize)),
+            RustType::Message(ref name)
+            | RustType::Enum(ref name, _)
+            | RustType::Oneof(ref name) => format!("{}", name),
+            RustType::Group => format!("<group>"),
+            RustType::Bytes => format!("::bytes::Bytes"),
+            RustType::Chars => format!("{}::Chars", protobuf_crate_path(customize)),
+        }
+    }
+}
+
+impl RustType {
+    pub fn u8() -> RustType {
+        RustType::Int(false, 8)
+    }
+
+    /// Type is rust primitive?
+    pub fn is_primitive(&self) -> bool {
+        match *self {
+            RustType::Int(..) | RustType::Float(..) | RustType::Bool => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_u8(&self) -> bool {
+        match *self {
+            RustType::Int(false, 8) => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_copy(&self) -> bool {
+        if self.is_primitive() {
+            true
+        } else if let RustType::Enum(..) = *self {
+            true
+        } else {
+            false
+        }
+    }
+
+    fn is_str(&self) -> bool {
+        match *self {
+            RustType::Str => true,
+            _ => false,
+        }
+    }
+
+    fn is_string(&self) -> bool {
+        match *self {
+            RustType::String => true,
+            _ => false,
+        }
+    }
+
+    fn is_slice(&self) -> Option<&RustType> {
+        match *self {
+            RustType::Slice(ref v) => Some(&**v),
+            _ => None,
+        }
+    }
+
+    fn is_slice_u8(&self) -> bool {
+        match self.is_slice() {
+            Some(t) => t.is_u8(),
+            None => false,
+        }
+    }
+
+    fn is_message(&self) -> bool {
+        match *self {
+            RustType::Message(..) => true,
+            _ => false,
+        }
+    }
+
+    fn is_enum(&self) -> bool {
+        match *self {
+            RustType::Enum(..) => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_ref(&self) -> bool {
+        match *self {
+            RustType::Ref(..) => true,
+            _ => false,
+        }
+    }
+
+    // default value for type
+    pub fn default_value(&self, customize: &Customize) -> String {
+        match *self {
+            RustType::Ref(ref t) if t.is_str() => "\"\"".to_string(),
+            RustType::Ref(ref t) if t.is_slice().is_some() => "&[]".to_string(),
+            RustType::Int(..) => "0".to_string(),
+            RustType::Float(..) => "0.".to_string(),
+            RustType::Bool => "false".to_string(),
+            RustType::Vec(..) => "::std::vec::Vec::new()".to_string(),
+            RustType::HashMap(..) => "::std::collections::HashMap::new()".to_string(),
+            RustType::String => "::std::string::String::new()".to_string(),
+            RustType::Bytes => "::bytes::Bytes::new()".to_string(),
+            RustType::Chars => format!("{}::Chars::new()", protobuf_crate_path(customize)),
+            RustType::Option(..) => "::std::option::Option::None".to_string(),
+            RustType::SingularField(..) => {
+                format!("{}::SingularField::none()", protobuf_crate_path(customize))
+            }
+            RustType::SingularPtrField(..) => format!(
+                "{}::SingularPtrField::none()",
+                protobuf_crate_path(customize)
+            ),
+            RustType::RepeatedField(..) => {
+                format!("{}::RepeatedField::new()", protobuf_crate_path(customize))
+            }
+            RustType::Message(ref name) => format!("{}::new()", name),
+            RustType::Ref(ref m) if m.is_message() => match **m {
+                RustType::Message(ref name) => format!("{}::default_instance()", name),
+                _ => unreachable!(),
+            },
+            // Note: default value of enum type may not be equal to default value of field
+            RustType::Enum(ref name, ref default) => format!("{}::{}", name, default),
+            _ => panic!("cannot create default value for: {:?}", *self),
+        }
+    }
+
+    pub fn default_value_typed(self, customize: &Customize) -> RustValueTyped {
+        RustValueTyped {
+            value: self.default_value(customize),
+            rust_type: self,
+        }
+    }
+
+    /// Emit a code to clear a variable `v`
+    pub fn clear(&self, v: &str, customize: &Customize) -> String {
+        match *self {
+            RustType::Option(..) => format!("{} = ::std::option::Option::None", v),
+            RustType::Vec(..)
+            | RustType::Bytes
+            | RustType::String
+            | RustType::RepeatedField(..)
+            | RustType::SingularField(..)
+            | RustType::SingularPtrField(..)
+            | RustType::HashMap(..) => format!("{}.clear()", v),
+            RustType::Chars => format!("::protobuf::Clear::clear(&mut {})", v),
+            RustType::Bool | RustType::Float(..) | RustType::Int(..) | RustType::Enum(..) => {
+                format!("{} = {}", v, self.default_value(customize))
+            }
+            ref ty => panic!("cannot clear type: {:?}", ty),
+        }
+    }
+
+    // wrap value in storage type
+    pub fn wrap_value(&self, value: &str) -> String {
+        match *self {
+            RustType::Option(..) => format!("::std::option::Option::Some({})", value),
+            RustType::SingularField(..) => format!("::protobuf::SingularField::some({})", value),
+            RustType::SingularPtrField(..) => {
+                format!("::protobuf::SingularPtrField::some({})", value)
+            }
+            _ => panic!("not a wrapper type: {:?}", *self),
+        }
+    }
+
+    // expression to convert `v` of type `self` to type `target`
+    pub fn into_target(&self, target: &RustType, v: &str, customize: &Customize) -> String {
+        self.try_into_target(target, v, customize)
+            .expect(&format!("failed to convert {:?} into {:?}", self, target))
+    }
+
+    fn try_into_target(
+        &self,
+        target: &RustType,
+        v: &str,
+        customize: &Customize,
+    ) -> Result<String, ()> {
+        match (self, target) {
+            (x, y) if x == y => return Ok(format!("{}", v)),
+            (&RustType::Ref(ref x), y) if **x == *y => return Ok(format!("*{}", v)),
+            (x, &RustType::Uniq(ref y)) if *x == **y => {
+                return Ok(format!("::std::boxed::Box::new({})", v))
+            }
+            (&RustType::Uniq(ref x), y) if **x == *y => return Ok(format!("*{}", v)),
+            (&RustType::String, &RustType::Ref(ref t)) if **t == RustType::Str => {
+                return Ok(format!("&{}", v))
+            }
+            (&RustType::Chars, &RustType::Ref(ref t)) if **t == RustType::Str => {
+                return Ok(format!("&{}", v))
+            }
+            (&RustType::Ref(ref t1), &RustType::Ref(ref t2)) if t1.is_string() && t2.is_str() => {
+                return Ok(format!("&{}", v))
+            }
+            (&RustType::Ref(ref t1), &RustType::String)
+                if match **t1 {
+                    RustType::Str => true,
+                    _ => false,
+                } =>
+            {
+                return Ok(format!("{}.to_owned()", v))
+            }
+            (&RustType::Ref(ref t1), &RustType::Chars)
+                if match **t1 {
+                    RustType::Str => true,
+                    _ => false,
+                    // TODO: from_static
+                } =>
+            {
+                return Ok(format!(
+                    "<{}::Chars as ::std::convert::From<_>>::from({}.to_owned())",
+                    protobuf_crate_path(customize),
+                    v
+                ))
+            }
+            (&RustType::Ref(ref t1), &RustType::Vec(ref t2))
+                if match (&**t1, &**t2) {
+                    (&RustType::Slice(ref x), ref y) => **x == **y,
+                    _ => false,
+                } =>
+            {
+                return Ok(format!("{}.to_vec()", v))
+            }
+            (&RustType::Ref(ref t1), &RustType::Bytes) if t1.is_slice_u8() => {
+                return Ok(format!(
+                    "<::bytes::Bytes as ::std::convert::From<_>>::from({}.to_vec())",
+                    v
+                ))
+            }
+            (&RustType::Vec(ref x), &RustType::Ref(ref t))
+                if match **t {
+                    RustType::Slice(ref y) => x == y,
+                    _ => false,
+                } =>
+            {
+                return Ok(format!("&{}", v))
+            }
+            (&RustType::Bytes, &RustType::Ref(ref t))
+                if match **t {
+                    RustType::Slice(ref y) => **y == RustType::u8(),
+                    _ => false,
+                } =>
+            {
+                return Ok(format!("&{}", v))
+            }
+            (&RustType::Ref(ref t1), &RustType::Ref(ref t2))
+                if match (&**t1, &**t2) {
+                    (&RustType::Vec(ref x), &RustType::Slice(ref y)) => x == y,
+                    _ => false,
+                } =>
+            {
+                return Ok(format!("&{}", v))
+            }
+            (&RustType::Enum(..), &RustType::Int(true, 32)) => return Ok(format!("{}.value()", v)),
+            (&RustType::Ref(ref t), &RustType::Int(true, 32)) if t.is_enum() => {
+                return Ok(format!("{}.value()", v))
+            }
+            _ => (),
+        };
+
+        if let &RustType::Ref(ref s) = self {
+            if let Ok(conv) = s.try_into_target(target, v, customize) {
+                return Ok(conv);
+            }
+        }
+
+        Err(())
+    }
+
+    /// Type to view data of this type
+    pub fn ref_type(&self) -> RustType {
+        RustType::Ref(Box::new(match self {
+            &RustType::String | &RustType::Chars => RustType::Str,
+            &RustType::Vec(ref p) | &RustType::RepeatedField(ref p) => RustType::Slice(p.clone()),
+            &RustType::Bytes => RustType::Slice(Box::new(RustType::u8())),
+            &RustType::Message(ref p) => RustType::Message(p.clone()),
+            x => panic!("no ref type for {:?}", x),
+        }))
+    }
+
+    pub fn elem_type(&self) -> RustType {
+        match self {
+            &RustType::Option(ref ty) => (**ty).clone(),
+            x => panic!("cannot get elem type of {:?}", x),
+        }
+    }
+
+    // type of `v` in `for v in xxx`
+    pub fn iter_elem_type(&self) -> RustType {
+        match self {
+            &RustType::Vec(ref ty)
+            | &RustType::Option(ref ty)
+            | &RustType::RepeatedField(ref ty)
+            | &RustType::SingularField(ref ty)
+            | &RustType::SingularPtrField(ref ty) => RustType::Ref(ty.clone()),
+            x => panic!("cannot iterate {:?}", x),
+        }
+    }
+
+    pub fn value(self, value: String) -> RustValueTyped {
+        RustValueTyped {
+            value: value,
+            rust_type: self,
+        }
+    }
+}
+
+/// Representation of an expression in code generator: text and type
+pub(crate) struct RustValueTyped {
+    pub value: String,
+    pub rust_type: RustType,
+}
+
+impl RustValueTyped {
+    pub fn into_type(&self, target: RustType, customize: &Customize) -> RustValueTyped {
+        let target_value = self.rust_type.into_target(&target, &self.value, customize);
+        RustValueTyped {
+            value: target_value,
+            rust_type: target,
+        }
+    }
+
+    pub fn boxed(self, customize: &Customize) -> RustValueTyped {
+        self.into_type(RustType::Uniq(Box::new(self.rust_type.clone())), customize)
+    }
+}
+
+// protobuf type name for protobuf base type
+pub fn protobuf_name(field_type: FieldDescriptorProto_Type) -> &'static str {
+    match field_type {
+        FieldDescriptorProto_Type::TYPE_DOUBLE => "double",
+        FieldDescriptorProto_Type::TYPE_FLOAT => "float",
+        FieldDescriptorProto_Type::TYPE_INT32 => "int32",
+        FieldDescriptorProto_Type::TYPE_INT64 => "int64",
+        FieldDescriptorProto_Type::TYPE_UINT32 => "uint32",
+        FieldDescriptorProto_Type::TYPE_UINT64 => "uint64",
+        FieldDescriptorProto_Type::TYPE_SINT32 => "sint32",
+        FieldDescriptorProto_Type::TYPE_SINT64 => "sint64",
+        FieldDescriptorProto_Type::TYPE_FIXED32 => "fixed32",
+        FieldDescriptorProto_Type::TYPE_FIXED64 => "fixed64",
+        FieldDescriptorProto_Type::TYPE_SFIXED32 => "sfixed32",
+        FieldDescriptorProto_Type::TYPE_SFIXED64 => "sfixed64",
+        FieldDescriptorProto_Type::TYPE_BOOL => "bool",
+        FieldDescriptorProto_Type::TYPE_STRING => "string",
+        FieldDescriptorProto_Type::TYPE_BYTES => "bytes",
+        FieldDescriptorProto_Type::TYPE_ENUM => "enum",
+        FieldDescriptorProto_Type::TYPE_MESSAGE => "message",
+        FieldDescriptorProto_Type::TYPE_GROUP => "group",
+    }
+}
+
+// rust type for protobuf base type
+pub(crate) fn rust_name(field_type: FieldDescriptorProto_Type) -> RustType {
+    match field_type {
+        FieldDescriptorProto_Type::TYPE_DOUBLE => RustType::Float(64),
+        FieldDescriptorProto_Type::TYPE_FLOAT => RustType::Float(32),
+        FieldDescriptorProto_Type::TYPE_INT32 => RustType::Int(true, 32),
+        FieldDescriptorProto_Type::TYPE_INT64 => RustType::Int(true, 64),
+        FieldDescriptorProto_Type::TYPE_UINT32 => RustType::Int(false, 32),
+        FieldDescriptorProto_Type::TYPE_UINT64 => RustType::Int(false, 64),
+        FieldDescriptorProto_Type::TYPE_SINT32 => RustType::Int(true, 32),
+        FieldDescriptorProto_Type::TYPE_SINT64 => RustType::Int(true, 64),
+        FieldDescriptorProto_Type::TYPE_FIXED32 => RustType::Int(false, 32),
+        FieldDescriptorProto_Type::TYPE_FIXED64 => RustType::Int(false, 64),
+        FieldDescriptorProto_Type::TYPE_SFIXED32 => RustType::Int(true, 32),
+        FieldDescriptorProto_Type::TYPE_SFIXED64 => RustType::Int(true, 64),
+        FieldDescriptorProto_Type::TYPE_BOOL => RustType::Bool,
+        FieldDescriptorProto_Type::TYPE_STRING => RustType::String,
+        FieldDescriptorProto_Type::TYPE_BYTES => RustType::Vec(Box::new(RustType::Int(false, 8))),
+        FieldDescriptorProto_Type::TYPE_ENUM
+        | FieldDescriptorProto_Type::TYPE_GROUP
+        | FieldDescriptorProto_Type::TYPE_MESSAGE => {
+            panic!("there is no rust name for {:?}", field_type)
+        }
+    }
+}
+
+fn file_last_component(file: &str) -> &str {
+    let bs = file.rfind('\\').map(|i| i + 1).unwrap_or(0);
+    let fs = file.rfind('/').map(|i| i + 1).unwrap_or(0);
+    &file[cmp::max(fs, bs)..]
+}
+
+#[cfg(test)]
+#[test]
+fn test_file_last_component() {
+    assert_eq!("ab.proto", file_last_component("ab.proto"));
+    assert_eq!("ab.proto", file_last_component("xx/ab.proto"));
+    assert_eq!("ab.proto", file_last_component("xx\\ab.proto"));
+    assert_eq!("ab.proto", file_last_component("yy\\xx\\ab.proto"));
+}
+
+fn is_descriptor_proto(file: &FileDescriptorProto) -> bool {
+    file.get_package() == "google.protobuf"
+        && file_last_component(file.get_name()) == "descriptor.proto"
+}
+
+pub(crate) fn type_name_to_rust_relative(
+    type_name: &ProtobufAbsolutePath,
+    file: &FileDescriptorProto,
+    subm: bool,
+    root_scope: &RootScope,
+) -> String {
+    let message_or_enum = root_scope.find_message_or_enum(type_name);
+    if message_or_enum.get_scope().get_file_descriptor().get_name() == file.get_name() {
+        // field type is a message or enum declared in the same file
+        if subm {
+            format!("super::{}", message_or_enum.rust_name())
+        } else {
+            format!("{}", message_or_enum.rust_name())
+        }
+    } else if let Some(name) = is_well_known_type_full(&type_name.path) {
+        // Well-known types are included in rust-protobuf library
+        // https://developers.google.com/protocol-buffers/docs/reference/google.protobuf
+        format!("::protobuf::well_known_types::{}", name)
+    } else if is_descriptor_proto(message_or_enum.get_file_descriptor()) {
+        // Messages defined in descriptor.proto
+        format!(
+            "::protobuf::descriptor::{}",
+            message_or_enum.name_to_package()
+        )
+    } else {
+        if subm {
+            format!("super::super::{}", message_or_enum.rust_fq_name())
+        } else {
+            format!("super::{}", message_or_enum.rust_fq_name())
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum PrimitiveTypeVariant {
+    Default,
+    Carllerche,
+}
+
+pub enum _CarllercheBytesType {
+    Bytes,
+    Chars,
+}
+
+// ProtobufType trait name
+pub enum ProtobufTypeGen {
+    Primitive(FieldDescriptorProto_Type, PrimitiveTypeVariant),
+    Message(String),
+    Enum(String),
+}
+
+impl ProtobufTypeGen {
+    pub fn rust_type(&self, customize: &Customize) -> String {
+        match self {
+            &ProtobufTypeGen::Primitive(t, PrimitiveTypeVariant::Default) => format!(
+                "::protobuf::types::ProtobufType{}",
+                capitalize(protobuf_name(t))
+            ),
+            &ProtobufTypeGen::Primitive(
+                FieldDescriptorProto_Type::TYPE_BYTES,
+                PrimitiveTypeVariant::Carllerche,
+            ) => format!(
+                "{}::types::ProtobufTypeCarllercheBytes",
+                protobuf_crate_path(customize)
+            ),
+            &ProtobufTypeGen::Primitive(
+                FieldDescriptorProto_Type::TYPE_STRING,
+                PrimitiveTypeVariant::Carllerche,
+            ) => format!(
+                "{}::types::ProtobufTypeCarllercheChars",
+                protobuf_crate_path(customize)
+            ),
+            &ProtobufTypeGen::Primitive(.., PrimitiveTypeVariant::Carllerche) => unreachable!(),
+            &ProtobufTypeGen::Message(ref name) => format!(
+                "{}::types::ProtobufTypeMessage<{}>",
+                protobuf_crate_path(customize),
+                name
+            ),
+            &ProtobufTypeGen::Enum(ref name) => {
+                format!("::protobuf::types::ProtobufTypeEnum<{}>", name)
+            }
+        }
+    }
+}
diff --git a/src/scope.rs b/src/scope.rs
new file mode 100644
index 0000000..87faf1f
--- /dev/null
+++ b/src/scope.rs
@@ -0,0 +1,554 @@
+use crate::field::rust_field_name_for_protobuf_field_name;
+use crate::file::proto_path_to_rust_mod;
+use crate::protobuf_name::ProtobufAbsolutePath;
+use crate::protobuf_name::ProtobufIdent;
+use crate::protobuf_name::ProtobufRelativePath;
+use crate::rust;
+use crate::rust_name::RustIdent;
+use crate::rust_name::RustIdentWithPath;
+use crate::syntax::Syntax;
+use protobuf::descriptor::DescriptorProto;
+use protobuf::descriptor::EnumDescriptorProto;
+use protobuf::descriptor::EnumValueDescriptorProto;
+use protobuf::descriptor::FieldDescriptorProto;
+use protobuf::descriptor::FileDescriptorProto;
+use protobuf::descriptor::OneofDescriptorProto;
+
+pub(crate) struct RootScope<'a> {
+    pub file_descriptors: &'a [FileDescriptorProto],
+}
+
+impl<'a> RootScope<'a> {
+    fn packages(&'a self) -> Vec<FileScope<'a>> {
+        self.file_descriptors
+            .iter()
+            .map(|fd| FileScope {
+                file_descriptor: fd,
+            })
+            .collect()
+    }
+
+    // find enum by fully qualified name
+    pub fn _find_enum(&'a self, fqn: &ProtobufAbsolutePath) -> EnumWithScope<'a> {
+        match self.find_message_or_enum(fqn) {
+            MessageOrEnumWithScope::Enum(e) => e,
+            _ => panic!("not an enum: {}", fqn),
+        }
+    }
+
+    // find message by fully qualified name
+    pub fn find_message(&'a self, fqn: &ProtobufAbsolutePath) -> MessageWithScope<'a> {
+        match self.find_message_or_enum(fqn) {
+            MessageOrEnumWithScope::Message(m) => m,
+            _ => panic!("not a message: {}", fqn),
+        }
+    }
+
+    // find message or enum by fully qualified name
+    pub fn find_message_or_enum(
+        &'a self,
+        fqn: &ProtobufAbsolutePath,
+    ) -> MessageOrEnumWithScope<'a> {
+        assert!(!fqn.is_empty());
+        self.packages()
+            .into_iter()
+            .flat_map(|p| p.find_message_or_enum_abs(fqn))
+            .next()
+            .expect(&format!("enum not found by name: {}", fqn))
+    }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct FileScope<'a> {
+    pub file_descriptor: &'a FileDescriptorProto,
+}
+
+impl<'a> FileScope<'a> {
+    fn get_package(&self) -> ProtobufAbsolutePath {
+        ProtobufRelativePath::from(self.file_descriptor.get_package()).into_absolute()
+    }
+
+    pub fn syntax(&self) -> Syntax {
+        Syntax::parse(self.file_descriptor.get_syntax())
+    }
+
+    pub fn to_scope(&self) -> Scope<'a> {
+        Scope {
+            file_scope: self.clone(),
+            path: Vec::new(),
+        }
+    }
+
+    fn find_message_or_enum(
+        &self,
+        name: &ProtobufRelativePath,
+    ) -> Option<MessageOrEnumWithScope<'a>> {
+        self.find_messages_and_enums()
+            .into_iter()
+            .filter(|e| e.protobuf_name_to_package() == *name)
+            .next()
+    }
+
+    fn find_message_or_enum_abs(
+        &self,
+        name: &ProtobufAbsolutePath,
+    ) -> Option<MessageOrEnumWithScope<'a>> {
+        match name.remove_prefix(&self.get_package()) {
+            Some(ref rem) => self.find_message_or_enum(rem),
+            None => None,
+        }
+    }
+
+    // find all enums in given file descriptor
+    pub fn _find_enums(&self) -> Vec<EnumWithScope<'a>> {
+        let mut r = Vec::new();
+
+        self.to_scope().walk_scopes(|scope| {
+            r.extend(scope.get_enums());
+        });
+
+        r
+    }
+
+    // find all messages in given file descriptor
+    pub fn _find_messages(&self) -> Vec<MessageWithScope<'a>> {
+        let mut r = Vec::new();
+
+        self.to_scope().walk_scopes(|scope| {
+            r.extend(scope.get_messages());
+        });
+
+        r
+    }
+
+    // find all messages and enums in given file descriptor
+    pub fn find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> {
+        let mut r = Vec::new();
+
+        self.to_scope().walk_scopes(|scope| {
+            r.extend(scope.get_messages_and_enums());
+        });
+
+        r
+    }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct Scope<'a> {
+    pub file_scope: FileScope<'a>,
+    pub path: Vec<&'a DescriptorProto>,
+}
+
+impl<'a> Scope<'a> {
+    pub fn get_file_descriptor(&self) -> &'a FileDescriptorProto {
+        self.file_scope.file_descriptor
+    }
+
+    // get message descriptors in this scope
+    fn get_message_descriptors(&self) -> &'a [DescriptorProto] {
+        if self.path.is_empty() {
+            &self.file_scope.file_descriptor.get_message_type()
+        } else {
+            &self.path.last().unwrap().get_nested_type()
+        }
+    }
+
+    // get enum descriptors in this scope
+    fn get_enum_descriptors(&self) -> &'a [EnumDescriptorProto] {
+        if self.path.is_empty() {
+            &self.file_scope.file_descriptor.get_enum_type()
+        } else {
+            &self.path.last().unwrap().get_enum_type()
+        }
+    }
+
+    // get messages with attached scopes in this scope
+    pub fn get_messages(&self) -> Vec<MessageWithScope<'a>> {
+        self.get_message_descriptors()
+            .iter()
+            .map(|m| MessageWithScope {
+                scope: self.clone(),
+                message: m,
+            })
+            .collect()
+    }
+
+    // get enums with attached scopes in this scope
+    pub fn get_enums(&self) -> Vec<EnumWithScope<'a>> {
+        self.get_enum_descriptors()
+            .iter()
+            .map(|e| EnumWithScope {
+                scope: self.clone(),
+                en: e,
+            })
+            .collect()
+    }
+
+    // get messages and enums with attached scopes in this scope
+    pub fn get_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> {
+        self.get_messages()
+            .into_iter()
+            .map(|m| MessageOrEnumWithScope::Message(m))
+            .chain(
+                self.get_enums()
+                    .into_iter()
+                    .map(|m| MessageOrEnumWithScope::Enum(m)),
+            )
+            .collect()
+    }
+
+    // nested scopes, i. e. scopes of nested messages
+    fn nested_scopes(&self) -> Vec<Scope<'a>> {
+        self.get_message_descriptors()
+            .iter()
+            .map(|m| {
+                let mut nested = self.clone();
+                nested.path.push(m);
+                nested
+            })
+            .collect()
+    }
+
+    fn walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F) {
+        (*callback)(self);
+
+        for nested in self.nested_scopes() {
+            nested.walk_scopes_impl(callback);
+        }
+    }
+
+    // apply callback for this scope and all nested scopes
+    fn walk_scopes<F>(&self, mut callback: F)
+    where
+        F: FnMut(&Scope<'a>),
+    {
+        self.walk_scopes_impl(&mut callback);
+    }
+
+    pub fn prefix(&self) -> String {
+        if self.path.is_empty() {
+            "".to_string()
+        } else {
+            let v: Vec<&'a str> = self.path.iter().map(|m| m.get_name()).collect();
+            let mut r = v.join(".");
+            r.push_str(".");
+            r
+        }
+    }
+
+    pub fn protobuf_path_to_file(&self) -> ProtobufRelativePath {
+        ProtobufRelativePath::from_components(
+            self.path.iter().map(|m| ProtobufIdent::from(m.get_name())),
+        )
+    }
+
+    pub fn protobuf_absolute_path(&self) -> ProtobufAbsolutePath {
+        let mut r = self.file_scope.get_package();
+        r.push_relative(&self.protobuf_path_to_file());
+        r
+    }
+
+    // rust type name prefix for this scope
+    pub fn rust_prefix(&self) -> String {
+        self.prefix().replace(".", "_")
+    }
+}
+
+pub(crate) trait WithScope<'a> {
+    fn get_scope(&self) -> &Scope<'a>;
+
+    fn get_file_descriptor(&self) -> &'a FileDescriptorProto {
+        self.get_scope().get_file_descriptor()
+    }
+
+    // message or enum name
+    fn get_name(&self) -> ProtobufIdent;
+
+    fn escape_prefix(&self) -> &'static str;
+
+    fn name_to_package(&self) -> String {
+        let mut r = self.get_scope().prefix();
+        r.push_str(self.get_name().get());
+        r
+    }
+
+    fn protobuf_name_to_package(&self) -> ProtobufRelativePath {
+        let r = self.get_scope().protobuf_path_to_file();
+        r.append_ident(&ProtobufIdent::from(self.get_name()))
+    }
+
+    /// Return absolute name starting with dot
+    fn name_absolute(&self) -> ProtobufAbsolutePath {
+        let mut path = self.get_scope().protobuf_absolute_path();
+        path.push_simple(self.get_name());
+        path
+    }
+
+    // rust type name of this descriptor
+    fn rust_name(&self) -> RustIdent {
+        let mut r = self.get_scope().rust_prefix();
+        // Only escape if prefix is not empty
+        if r.is_empty() && rust::is_rust_keyword(self.get_name().get()) {
+            r.push_str(self.escape_prefix());
+        }
+        r.push_str(self.get_name().get());
+        RustIdent::from(r)
+    }
+
+    // fully-qualified name of this type
+    fn rust_fq_name(&self) -> String {
+        format!(
+            "{}::{}",
+            proto_path_to_rust_mod(self.get_scope().get_file_descriptor().get_name()),
+            self.rust_name()
+        )
+    }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct MessageWithScope<'a> {
+    pub scope: Scope<'a>,
+    pub message: &'a DescriptorProto,
+}
+
+impl<'a> WithScope<'a> for MessageWithScope<'a> {
+    fn get_scope(&self) -> &Scope<'a> {
+        &self.scope
+    }
+
+    fn escape_prefix(&self) -> &'static str {
+        "message_"
+    }
+
+    fn get_name(&self) -> ProtobufIdent {
+        ProtobufIdent::from(self.message.get_name())
+    }
+}
+
+impl<'a> MessageWithScope<'a> {
+    pub fn into_scope(mut self) -> Scope<'a> {
+        self.scope.path.push(self.message);
+        self.scope
+    }
+
+    pub fn to_scope(&self) -> Scope<'a> {
+        self.clone().into_scope()
+    }
+
+    pub fn fields(&self) -> Vec<FieldWithContext<'a>> {
+        self.message
+            .get_field()
+            .iter()
+            .map(|f| FieldWithContext {
+                field: f,
+                message: self.clone(),
+            })
+            .collect()
+    }
+
+    pub fn oneofs(&self) -> Vec<OneofWithContext<'a>> {
+        self.message
+            .get_oneof_decl()
+            .iter()
+            .enumerate()
+            .map(|(index, oneof)| OneofWithContext {
+                message: self.clone(),
+                oneof: oneof,
+                index: index as u32,
+            })
+            .collect()
+    }
+
+    pub fn oneof_by_index(&self, index: u32) -> OneofWithContext<'a> {
+        self.oneofs().swap_remove(index as usize)
+    }
+
+    /// Pair of (key, value) if this message is map entry
+    pub fn map_entry(&'a self) -> Option<(FieldWithContext<'a>, FieldWithContext<'a>)> {
+        if self.message.get_options().get_map_entry() {
+            let key = self
+                .fields()
+                .into_iter()
+                .find(|f| f.field.get_number() == 1)
+                .unwrap();
+            let value = self
+                .fields()
+                .into_iter()
+                .find(|f| f.field.get_number() == 2)
+                .unwrap();
+            Some((key, value))
+        } else {
+            None
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct EnumWithScope<'a> {
+    pub scope: Scope<'a>,
+    pub en: &'a EnumDescriptorProto,
+}
+
+impl<'a> EnumWithScope<'a> {
+    pub fn values(&self) -> Vec<EnumValueWithContext<'a>> {
+        self.en
+            .get_value()
+            .iter()
+            .map(|v| EnumValueWithContext {
+                en: self.clone(),
+                proto: v,
+            })
+            .collect()
+    }
+
+    // find enum value by protobuf name
+    pub fn value_by_name(&self, name: &str) -> EnumValueWithContext<'a> {
+        self.values()
+            .into_iter()
+            .find(|v| v.proto.get_name() == name)
+            .unwrap()
+    }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct EnumValueWithContext<'a> {
+    pub en: EnumWithScope<'a>,
+    pub proto: &'a EnumValueDescriptorProto,
+}
+
+impl<'a> EnumValueWithContext<'a> {
+    pub fn rust_name(&self) -> RustIdent {
+        let mut r = String::new();
+        if rust::is_rust_keyword(self.proto.get_name()) {
+            r.push_str("value_");
+        }
+        r.push_str(self.proto.get_name());
+        RustIdent::new(&r)
+    }
+}
+
+impl<'a> WithScope<'a> for EnumWithScope<'a> {
+    fn get_scope(&self) -> &Scope<'a> {
+        &self.scope
+    }
+
+    fn escape_prefix(&self) -> &'static str {
+        "enum_"
+    }
+
+    fn get_name(&self) -> ProtobufIdent {
+        ProtobufIdent::from(self.en.get_name())
+    }
+}
+
+pub(crate) enum MessageOrEnumWithScope<'a> {
+    Message(MessageWithScope<'a>),
+    Enum(EnumWithScope<'a>),
+}
+
+impl<'a> WithScope<'a> for MessageOrEnumWithScope<'a> {
+    fn get_scope(&self) -> &Scope<'a> {
+        match self {
+            &MessageOrEnumWithScope::Message(ref m) => m.get_scope(),
+            &MessageOrEnumWithScope::Enum(ref e) => e.get_scope(),
+        }
+    }
+
+    fn escape_prefix(&self) -> &'static str {
+        match self {
+            &MessageOrEnumWithScope::Message(ref m) => m.escape_prefix(),
+            &MessageOrEnumWithScope::Enum(ref e) => e.escape_prefix(),
+        }
+    }
+
+    fn get_name(&self) -> ProtobufIdent {
+        match self {
+            &MessageOrEnumWithScope::Message(ref m) => m.get_name(),
+            &MessageOrEnumWithScope::Enum(ref e) => e.get_name(),
+        }
+    }
+}
+
+#[derive(Clone)]
+pub(crate) struct FieldWithContext<'a> {
+    pub field: &'a FieldDescriptorProto,
+    pub message: MessageWithScope<'a>,
+}
+
+impl<'a> FieldWithContext<'a> {
+    pub fn is_oneof(&self) -> bool {
+        self.field.has_oneof_index()
+    }
+
+    pub fn oneof(&self) -> Option<OneofWithContext<'a>> {
+        if self.is_oneof() {
+            Some(
+                self.message
+                    .oneof_by_index(self.field.get_oneof_index() as u32),
+            )
+        } else {
+            None
+        }
+    }
+
+    pub fn number(&self) -> u32 {
+        self.field.get_number() as u32
+    }
+
+    /// Shortcut
+    pub fn name(&self) -> &str {
+        self.field.get_name()
+    }
+
+    pub fn rust_name(&self) -> RustIdent {
+        rust_field_name_for_protobuf_field_name(self.name())
+    }
+
+    // From field to file root
+    pub fn _containing_messages(&self) -> Vec<&'a DescriptorProto> {
+        let mut r = Vec::new();
+        r.push(self.message.message);
+        r.extend(self.message.scope.path.iter().rev());
+        r
+    }
+}
+
+#[derive(Clone)]
+pub(crate) struct OneofVariantWithContext<'a> {
+    pub oneof: &'a OneofWithContext<'a>,
+    pub field: &'a FieldDescriptorProto,
+}
+
+#[derive(Clone)]
+pub(crate) struct OneofWithContext<'a> {
+    pub oneof: &'a OneofDescriptorProto,
+    pub index: u32,
+    pub message: MessageWithScope<'a>,
+}
+
+impl<'a> OneofWithContext<'a> {
+    pub fn field_name(&'a self) -> RustIdent {
+        return rust_field_name_for_protobuf_field_name(self.oneof.get_name());
+    }
+
+    // rust type name of enum
+    pub fn rust_name(&self) -> RustIdentWithPath {
+        RustIdentWithPath::from(format!(
+            "{}_oneof_{}",
+            self.message.rust_name(),
+            self.oneof.get_name()
+        ))
+    }
+
+    pub fn variants(&'a self) -> Vec<OneofVariantWithContext<'a>> {
+        self.message
+            .fields()
+            .iter()
+            .filter(|f| f.field.has_oneof_index() && f.field.get_oneof_index() == self.index as i32)
+            .map(|f| OneofVariantWithContext {
+                oneof: self,
+                field: &f.field,
+            })
+            .collect()
+    }
+}
diff --git a/src/serde.rs b/src/serde.rs
new file mode 100644
index 0000000..f799611
--- /dev/null
+++ b/src/serde.rs
@@ -0,0 +1,9 @@
+use code_writer::CodeWriter;
+use Customize;
+
+/// Write serde attr according to specified codegen option.
+pub fn write_serde_attr(w: &mut CodeWriter, customize: &Customize, attr: &str) {
+    if customize.serde_derive.unwrap_or(false) {
+        w.write_line(&format!("#[cfg_attr(feature = \"with-serde\", {})]", attr));
+    }
+}
diff --git a/src/strx.rs b/src/strx.rs
new file mode 100644
index 0000000..e822bf8
--- /dev/null
+++ b/src/strx.rs
@@ -0,0 +1,54 @@
+pub fn remove_to<'s>(s: &'s str, c: char) -> &'s str {
+    match s.rfind(c) {
+        Some(pos) => &s[(pos + 1)..],
+        None => s,
+    }
+}
+
+pub fn remove_suffix<'s>(s: &'s str, suffix: &str) -> &'s str {
+    if !s.ends_with(suffix) {
+        s
+    } else {
+        &s[..(s.len() - suffix.len())]
+    }
+}
+
+pub fn capitalize(s: &str) -> String {
+    if s.is_empty() {
+        return String::new();
+    }
+    let mut char_indices = s.char_indices();
+    char_indices.next().unwrap();
+    match char_indices.next() {
+        None => s.to_uppercase(),
+        Some((i, _)) => s[..i].to_uppercase() + &s[i..],
+    }
+}
+
+#[cfg(test)]
+mod test {
+
+    use super::capitalize;
+    use super::remove_suffix;
+    use super::remove_to;
+
+    #[test]
+    fn test_remove_to() {
+        assert_eq!("aaa", remove_to("aaa", '.'));
+        assert_eq!("bbb", remove_to("aaa.bbb", '.'));
+        assert_eq!("ccc", remove_to("aaa.bbb.ccc", '.'));
+    }
+
+    #[test]
+    fn test_remove_suffix() {
+        assert_eq!("bbb", remove_suffix("bbbaaa", "aaa"));
+        assert_eq!("aaa", remove_suffix("aaa", "bbb"));
+    }
+
+    #[test]
+    fn test_capitalize() {
+        assert_eq!("", capitalize(""));
+        assert_eq!("F", capitalize("f"));
+        assert_eq!("Foo", capitalize("foo"));
+    }
+}
diff --git a/src/syntax.rs b/src/syntax.rs
new file mode 100644
index 0000000..d075063
--- /dev/null
+++ b/src/syntax.rs
@@ -0,0 +1,15 @@
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum Syntax {
+    PROTO2,
+    PROTO3,
+}
+
+impl Syntax {
+    pub fn parse(s: &str) -> Self {
+        match s {
+            "" | "proto2" => Syntax::PROTO2,
+            "proto3" => Syntax::PROTO3,
+            _ => panic!("unsupported syntax value: {:?}", s),
+        }
+    }
+}
diff --git a/src/well_known_types.rs b/src/well_known_types.rs
new file mode 100644
index 0000000..6264947
--- /dev/null
+++ b/src/well_known_types.rs
@@ -0,0 +1,63 @@
+static NAMES: &'static [&'static str] = &[
+    "Any",
+    "Api",
+    "BoolValue",
+    "BytesValue",
+    "DoubleValue",
+    "Duration",
+    "Empty",
+    "Enum",
+    "EnumValue",
+    "Field",
+    // TODO: dotted names
+    "Field.Cardinality",
+    "Field.Kind",
+    "FieldMask",
+    "FloatValue",
+    "Int32Value",
+    "Int64Value",
+    "ListValue",
+    "Method",
+    "Mixin",
+    "NullValue",
+    "Option",
+    "SourceContext",
+    "StringValue",
+    "Struct",
+    "Syntax",
+    "Timestamp",
+    "Type",
+    "UInt32Value",
+    "UInt64Value",
+    "Value",
+];
+
+fn is_well_known_type(name: &str) -> bool {
+    NAMES.iter().any(|&n| n == name)
+}
+
+pub fn is_well_known_type_full(name: &str) -> Option<&str> {
+    if let Some(dot) = name.rfind('.') {
+        if &name[..dot] == ".google.protobuf" && is_well_known_type(&name[dot + 1..]) {
+            Some(&name[dot + 1..])
+        } else {
+            None
+        }
+    } else {
+        None
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_is_well_known_type_full() {
+        assert_eq!(
+            Some("BoolValue"),
+            is_well_known_type_full(".google.protobuf.BoolValue")
+        );
+        assert_eq!(None, is_well_known_type_full(".google.protobuf.Fgfg"));
+    }
+}