summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederick Mayle <fmayle@google.com>2024-01-17 16:07:22 -0800
committerFrederick Mayle <fmayle@google.com>2024-01-17 16:07:22 -0800
commit94c81f2ff34ad3a1f26107090df5264561d6df0c (patch)
tree2de2dd96e000c74dce71759c9d2fccc38648bfc5
parentc6f20e5b30cc35de6429971c43baf8593cb022a8 (diff)
downloadp9_wire_format_derive-94c81f2ff34ad3a1f26107090df5264561d6df0c.tar.gz
Import 'p9_wire_format_derive' crateupstream
Request Document: go/android-rust-importing-crates For CL Reviewers: go/android3p#cl-review For Build Team: go/ab-third-party-imports Bug: 317282804 Test: n/a Change-Id: I64a776ae4bafc25c19780a5831e8f254bb7c1bb1
-rw-r--r--.cargo_vcs_info.json6
-rw-r--r--Cargo.toml32
-rw-r--r--Cargo.toml.orig16
-rw-r--r--LICENSE27
-rw-r--r--METADATA19
-rw-r--r--MODULE_LICENSE_BSD_LIKE0
-rw-r--r--OWNERS3
-rw-r--r--README.md19
-rw-r--r--src/lib.rs307
9 files changed, 429 insertions, 0 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..fe5f8f1
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+ "git": {
+ "sha1": "68f2a1caea21b7707f5c6a992fe5e71f2e89513a"
+ },
+ "path_in_vcs": "p9_wire_format_derive"
+} \ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..3c7a2ea
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,32 @@
+# 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 are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+name = "p9_wire_format_derive"
+version = "0.2.3"
+authors = ["The ChromiumOS Authors"]
+description = "Supporting proc-macro for the `p9` crate."
+readme = "README.md"
+license = "BSD-3-Clause"
+repository = "https://github.com/google/rust-p9"
+resolver = "2"
+
+[lib]
+proc-macro = true
+
+[dependencies.proc-macro2]
+version = "^1"
+
+[dependencies.quote]
+version = "^1"
+
+[dependencies.syn]
+version = "^1"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..d2676bb
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,16 @@
+[package]
+name = "p9_wire_format_derive"
+version = "0.2.3"
+authors = ["The ChromiumOS Authors"]
+license = "BSD-3-Clause"
+description = "Supporting proc-macro for the `p9` crate."
+repository = "https://github.com/google/rust-p9"
+readme = "../README.md"
+
+[dependencies]
+syn = "^1"
+quote = "^1"
+proc-macro2 = "^1"
+
+[lib]
+proc-macro = true
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f6d41c6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+// Copyright 2017 The ChromiumOS Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..00ab429
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,19 @@
+name: "p9_wire_format_derive"
+description: "Supporting proc-macro for the `p9` crate."
+third_party {
+ identifier {
+ type: "crates.io"
+ value: "https://crates.io/crates/p9_wire_format_derive"
+ }
+ identifier {
+ type: "Archive"
+ value: "https://static.crates.io/crates/p9_wire_format_derive/p9_wire_format_derive-0.2.3.crate"
+ }
+ version: "0.2.3"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2024
+ month: 1
+ day: 17
+ }
+}
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/OWNERS b/OWNERS
new file mode 100644
index 0000000..41179fc
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 688011
+include platform/prebuilts/rust:main:/OWNERS
+fmayle@google.com
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..52cd4e6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,19 @@
+# p9 - Server implementation of the [9p] file system protocol
+
+This directory contains the protocol definition and a server implementation of the [9p] file system
+protocol.
+
+- [wire_format_derive] - A [procedural macro] that derives the serialization and de-serialization
+ implementation for a struct into the [9p] wire format.
+- [src/protocol] - Defines all the messages used in the [9p] protocol. Also implements serialization
+ and de-serialization for some base types (integers, strings, vectors) that form the foundation of
+ all [9p] messages. Wire format implementations for all other messages are derived using the
+ `wire_format_derive` macro.
+- [src/server.rs] - Implements a full [9p] server, carrying out file system requests on behalf of
+ clients.
+
+[9p]: http://man.cat-v.org/plan_9/5/intro
+[procedural macro]: https://doc.rust-lang.org/proc_macro/index.html
+[src/protocol]: src/protocol/
+[src/server.rs]: src/server.rs
+[wire_format_derive]: wire_format_derive/
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..bc39147
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,307 @@
+// Copyright 2018 The ChromiumOS Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Derives a 9P wire format encoding for a struct by recursively calling
+//! `WireFormat::encode` or `WireFormat::decode` on the fields of the struct.
+//! This is only intended to be used from within the `p9` crate.
+
+#![recursion_limit = "256"]
+
+extern crate proc_macro;
+extern crate proc_macro2;
+
+#[macro_use]
+extern crate quote;
+
+#[macro_use]
+extern crate syn;
+
+use proc_macro2::Span;
+use proc_macro2::TokenStream;
+use syn::spanned::Spanned;
+use syn::Data;
+use syn::DeriveInput;
+use syn::Fields;
+use syn::Ident;
+
+/// The function that derives the actual implementation.
+#[proc_macro_derive(P9WireFormat)]
+pub fn p9_wire_format(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let input = parse_macro_input!(input as DeriveInput);
+ p9_wire_format_inner(input).into()
+}
+
+fn p9_wire_format_inner(input: DeriveInput) -> TokenStream {
+ if !input.generics.params.is_empty() {
+ return quote! {
+ compile_error!("derive(P9WireFormat) does not support generic parameters");
+ };
+ }
+
+ let container = input.ident;
+
+ let byte_size_impl = byte_size_sum(&input.data);
+ let encode_impl = encode_wire_format(&input.data);
+ let decode_impl = decode_wire_format(&input.data, &container);
+
+ let scope = format!("wire_format_{}", container).to_lowercase();
+ let scope = Ident::new(&scope, Span::call_site());
+ quote! {
+ mod #scope {
+ extern crate std;
+ use self::std::io;
+ use self::std::result::Result::Ok;
+
+ use super::#container;
+
+ use protocol::WireFormat;
+
+ impl WireFormat for #container {
+ fn byte_size(&self) -> u32 {
+ #byte_size_impl
+ }
+
+ fn encode<W: io::Write>(&self, _writer: &mut W) -> io::Result<()> {
+ #encode_impl
+ }
+
+ fn decode<R: io::Read>(_reader: &mut R) -> io::Result<Self> {
+ #decode_impl
+ }
+ }
+ }
+ }
+}
+
+// Generate code that recursively calls byte_size on every field in the struct.
+fn byte_size_sum(data: &Data) -> TokenStream {
+ if let Data::Struct(ref data) = *data {
+ if let Fields::Named(ref fields) = data.fields {
+ let fields = fields.named.iter().map(|f| {
+ let field = &f.ident;
+ let span = field.span();
+ quote_spanned! {span=>
+ WireFormat::byte_size(&self.#field)
+ }
+ });
+
+ quote! {
+ 0 #(+ #fields)*
+ }
+ } else {
+ unimplemented!();
+ }
+ } else {
+ unimplemented!();
+ }
+}
+
+// Generate code that recursively calls encode on every field in the struct.
+fn encode_wire_format(data: &Data) -> TokenStream {
+ if let Data::Struct(ref data) = *data {
+ if let Fields::Named(ref fields) = data.fields {
+ let fields = fields.named.iter().map(|f| {
+ let field = &f.ident;
+ let span = field.span();
+ quote_spanned! {span=>
+ WireFormat::encode(&self.#field, _writer)?;
+ }
+ });
+
+ quote! {
+ #(#fields)*
+
+ Ok(())
+ }
+ } else {
+ unimplemented!();
+ }
+ } else {
+ unimplemented!();
+ }
+}
+
+// Generate code that recursively calls decode on every field in the struct.
+fn decode_wire_format(data: &Data, container: &Ident) -> TokenStream {
+ if let Data::Struct(ref data) = *data {
+ if let Fields::Named(ref fields) = data.fields {
+ let values = fields.named.iter().map(|f| {
+ let field = &f.ident;
+ let span = field.span();
+ quote_spanned! {span=>
+ let #field = WireFormat::decode(_reader)?;
+ }
+ });
+
+ let members = fields.named.iter().map(|f| {
+ let field = &f.ident;
+ quote! {
+ #field: #field,
+ }
+ });
+
+ quote! {
+ #(#values)*
+
+ Ok(#container {
+ #(#members)*
+ })
+ }
+ } else {
+ unimplemented!();
+ }
+ } else {
+ unimplemented!();
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn byte_size() {
+ let input: DeriveInput = parse_quote! {
+ struct Item {
+ ident: u32,
+ with_underscores: String,
+ other: u8,
+ }
+ };
+
+ let expected = quote! {
+ 0
+ + WireFormat::byte_size(&self.ident)
+ + WireFormat::byte_size(&self.with_underscores)
+ + WireFormat::byte_size(&self.other)
+ };
+
+ assert_eq!(byte_size_sum(&input.data).to_string(), expected.to_string());
+ }
+
+ #[test]
+ fn encode() {
+ let input: DeriveInput = parse_quote! {
+ struct Item {
+ ident: u32,
+ with_underscores: String,
+ other: u8,
+ }
+ };
+
+ let expected = quote! {
+ WireFormat::encode(&self.ident, _writer)?;
+ WireFormat::encode(&self.with_underscores, _writer)?;
+ WireFormat::encode(&self.other, _writer)?;
+ Ok(())
+ };
+
+ assert_eq!(
+ encode_wire_format(&input.data).to_string(),
+ expected.to_string(),
+ );
+ }
+
+ #[test]
+ fn decode() {
+ let input: DeriveInput = parse_quote! {
+ struct Item {
+ ident: u32,
+ with_underscores: String,
+ other: u8,
+ }
+ };
+
+ let container = Ident::new("Item", Span::call_site());
+ let expected = quote! {
+ let ident = WireFormat::decode(_reader)?;
+ let with_underscores = WireFormat::decode(_reader)?;
+ let other = WireFormat::decode(_reader)?;
+ Ok(Item {
+ ident: ident,
+ with_underscores: with_underscores,
+ other: other,
+ })
+ };
+
+ assert_eq!(
+ decode_wire_format(&input.data, &container).to_string(),
+ expected.to_string(),
+ );
+ }
+
+ #[test]
+ fn end_to_end() {
+ let input: DeriveInput = parse_quote! {
+ struct Niijima_先輩 {
+ a: u8,
+ b: u16,
+ c: u32,
+ d: u64,
+ e: String,
+ f: Vec<String>,
+ g: Nested,
+ }
+ };
+
+ let expected = quote! {
+ mod wire_format_niijima_先輩 {
+ extern crate std;
+ use self::std::io;
+ use self::std::result::Result::Ok;
+
+ use super::Niijima_先輩;
+
+ use protocol::WireFormat;
+
+ impl WireFormat for Niijima_先輩 {
+ fn byte_size(&self) -> u32 {
+ 0
+ + WireFormat::byte_size(&self.a)
+ + WireFormat::byte_size(&self.b)
+ + WireFormat::byte_size(&self.c)
+ + WireFormat::byte_size(&self.d)
+ + WireFormat::byte_size(&self.e)
+ + WireFormat::byte_size(&self.f)
+ + WireFormat::byte_size(&self.g)
+ }
+
+ fn encode<W: io::Write>(&self, _writer: &mut W) -> io::Result<()> {
+ WireFormat::encode(&self.a, _writer)?;
+ WireFormat::encode(&self.b, _writer)?;
+ WireFormat::encode(&self.c, _writer)?;
+ WireFormat::encode(&self.d, _writer)?;
+ WireFormat::encode(&self.e, _writer)?;
+ WireFormat::encode(&self.f, _writer)?;
+ WireFormat::encode(&self.g, _writer)?;
+ Ok(())
+ }
+ fn decode<R: io::Read>(_reader: &mut R) -> io::Result<Self> {
+ let a = WireFormat::decode(_reader)?;
+ let b = WireFormat::decode(_reader)?;
+ let c = WireFormat::decode(_reader)?;
+ let d = WireFormat::decode(_reader)?;
+ let e = WireFormat::decode(_reader)?;
+ let f = WireFormat::decode(_reader)?;
+ let g = WireFormat::decode(_reader)?;
+ Ok(Niijima_先輩 {
+ a: a,
+ b: b,
+ c: c,
+ d: d,
+ e: e,
+ f: f,
+ g: g,
+ })
+ }
+ }
+ }
+ };
+
+ assert_eq!(
+ p9_wire_format_inner(input).to_string(),
+ expected.to_string(),
+ );
+ }
+}