├── .gitignore ├── rustfmt.toml ├── rust ├── src │ ├── reflect │ │ ├── impls.rs │ │ ├── private.rs │ │ ├── names.rs │ │ ├── view.rs │ │ ├── tuple.rs │ │ └── mod.rs │ ├── proto │ │ ├── mod.rs │ │ ├── plugin.proto │ │ ├── pz.proto │ │ ├── pz.pz │ │ └── plugin.pz │ ├── lib.rs │ ├── scalar.rs │ ├── debug.rs │ ├── rep │ │ ├── iter.rs │ │ ├── eq.rs │ │ ├── index.rs │ │ └── mod.rs │ ├── arena.rs │ ├── opt.rs │ ├── macros.rs │ └── tdp │ │ └── mod.rs ├── build.rs ├── plugin │ ├── Cargo.toml │ └── src │ │ ├── rust │ │ ├── fields │ │ │ ├── submsg.rs │ │ │ ├── str.rs │ │ │ ├── scalar.rs │ │ │ └── mod.rs │ │ ├── names.rs │ │ ├── enum.rs │ │ ├── mod.rs │ │ └── choice.rs │ │ ├── lib.rs │ │ └── emit.rs ├── Cargo.toml └── tests │ ├── proto │ └── test.pz │ └── tdp.rs ├── rust-toolchain.toml ├── Cargo.toml ├── pzc ├── src │ ├── lib.rs │ ├── ir │ │ ├── mod.rs │ │ └── to_proto.rs │ ├── syn │ │ ├── mod.rs │ │ └── parse.rs │ └── main.rs ├── Cargo.toml └── tests │ └── frontend.rs ├── .devcontainer ├── devcontainer.json ├── scripts │ └── install_protoc.sh └── Dockerfile ├── README.md ├── bootstrap.sh └── .github └── workflows └── rust.yml /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 80 2 | tab_spaces = 2 -------------------------------------------------------------------------------- /rust/src/reflect/impls.rs: -------------------------------------------------------------------------------- 1 | //! Impls of various tra 2 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.80.1" 3 | profile = "default" 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = ["rust", "rust/plugin", "pzc"] 4 | -------------------------------------------------------------------------------- /pzc/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The pz compiler. 2 | 3 | pub mod ir; 4 | pub mod syn; 5 | pub use pz::prost; 6 | -------------------------------------------------------------------------------- /rust/build.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | fn main() -> io::Result<()> { 4 | prost_build::compile_protos( 5 | &["src/proto/pz.proto", "src/proto/plugin.proto"], 6 | &["src/proto"], 7 | )?; 8 | Ok(()) 9 | } 10 | -------------------------------------------------------------------------------- /rust/src/proto/mod.rs: -------------------------------------------------------------------------------- 1 | // Generated code for bootstrapping. 2 | 3 | include!(concat!(env!("OUT_DIR"), "/pz.rs")); 4 | 5 | pub mod plugin { 6 | include!(concat!(env!("OUT_DIR"), "/pz.plugin.rs")); 7 | } 8 | 9 | #[path = "lib.pz.rs"] 10 | pub mod z; 11 | -------------------------------------------------------------------------------- /rust/plugin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pz_plugins" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | pz = { path = ".." } 8 | 9 | # Use this to break dependency loops. 10 | # pz = { git = "https://github.com/mcy/pz.git" } 11 | 12 | heck = "0.4.1" 13 | -------------------------------------------------------------------------------- /rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pz" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | prost = "0.13.2" 8 | 9 | [dependencies.bumpalo] 10 | version = "3.12.1" 11 | features = ["collections"] 12 | 13 | [dev-dependencies] 14 | googletest = "0.5.0" 15 | unindent = "0.2.1" 16 | 17 | [build-dependencies] 18 | prost-build = "0.13.2" -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. 2 | { 3 | "name": "pz", 4 | "build": { 5 | "dockerfile": "Dockerfile", 6 | "args": {} 7 | }, 8 | "customizations": { 9 | "vscode": { 10 | "settings": { 11 | "[rust]": { 12 | "editor.formatOnSave": true 13 | } 14 | }, 15 | "extensions": [ 16 | "GitHub.copilot", 17 | "rust-lang.rust-analyzer" 18 | ] 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.devcontainer/scripts/install_protoc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | PROTOC_VERSION=22.3 4 | PROTOC_HOST=https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION} 5 | PROTOC_ARCH=x86_64 6 | if [ "$(uname -m)" = "aarch64" ]; then 7 | PROTOC_ARCH=aarch_64 8 | fi 9 | 10 | PROTOC_ZIP=protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip 11 | 12 | curl -OL ${PROTOC_HOST}/${PROTOC_ZIP} && \ 13 | unzip -o ${PROTOC_ZIP} -d /usr/local bin/protoc && \ 14 | unzip -o ${PROTOC_ZIP} -d /usr/local 'include/*' && \ 15 | rm -f ${PROTOC_ZIP} 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pz 2 | 3 | Protobuf with Pizzazz 4 | 5 | `pz` is an experiment I started shortly after leaving the Protobuf team to 6 | explore a new IDL for Protobuf-compatible files. 7 | 8 | ## Contributing 9 | 10 | This project uses [Dev Containers](https://containers.dev) and VS Code to 11 | provide a deterministic development environment for contributors. 12 | 13 | ### Prerequisites 14 | 15 | You'll need a way to run Docker containers on your host workstation (or use 16 | GitHub Codespaces). If you're using MacOS, we recommend 17 | [Colima](https://github.com/abiosoft/colima). 18 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -x 3 | set -e 4 | cd $(dirname $0) 5 | 6 | build() { 7 | rt=$1; shift 8 | out=$1; shift 9 | 10 | cp $out $out.bck 11 | 12 | set -e 13 | cargo run -p pzc -- \ 14 | --plugin=rust \ 15 | --output-dir=$(dirname $out) \ 16 | --rust.rt-crate $rt \ 17 | --rust.package-prefix pz \ 18 | $@ 19 | 20 | if [[ -z $NOBUILD ]]; then 21 | set +e 22 | cargo build 23 | fi 24 | if [[ $? != 0 ]]; then 25 | mv $out.bck $out 26 | else 27 | rm $out.bck 28 | fi 29 | } 30 | 31 | build crate rust/src/proto/lib.pz.rs rust/src/proto/*.pz 32 | build pz rust/tests/proto/lib.pz.rs rust/tests/proto/*.pz -------------------------------------------------------------------------------- /pzc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pzc" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | pz = { path = "../rust" } 8 | pz_plugins = { path = "../rust/plugin" } 9 | 10 | # Use this to break dependency loops. 11 | # pz = { git = "https://github.com/mcy/pz.git" } 12 | 13 | ilex = "0.6.0" 14 | heck = "0.4.1" 15 | 16 | [dependencies.bumpalo] 17 | version = "3.12.1" 18 | features = ["collections"] 19 | 20 | [dependencies.clap] 21 | version = "4.2.4" 22 | features = ["derive", "string"] 23 | 24 | [dependencies.annotate-snippets] 25 | version = "0.9.1" 26 | features = ["color"] 27 | 28 | [dev-dependencies] 29 | googletest = "0.5.0" 30 | unindent = "0.2.1" -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/devcontainers/base:debian-11 2 | 3 | # Run as non-root. 4 | USER vscode 5 | 6 | # Install Rust & Go toolchains (latest & stable). 7 | RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile complete && \ 8 | curl -sSf https://raw.githubusercontent.com/owenthereal/goup/master/install.sh | sh -s -- '--skip-prompt' 9 | 10 | # Source the envs into bashrc, and establish the gobin path. 11 | ENV PATH $PATH:/home/vscode/.go/current/bin:/home/vscode/.cargo/bin 12 | ENV GOBIN /home/vscode/.go/bin 13 | 14 | # Install protoscope. 15 | RUN go install github.com/protocolbuffers/protoscope/cmd/protoscope...@latest 16 | 17 | # Install protoc. 18 | COPY --chown=vscode:vscode ./scripts/install_protoc.sh /home/vscode/install_protoc.sh 19 | RUN chmod +x /home/vscode/install_protoc.sh && sudo /home/vscode/install_protoc.sh 20 | -------------------------------------------------------------------------------- /rust/plugin/src/rust/fields/submsg.rs: -------------------------------------------------------------------------------- 1 | // Field codegen for submessage fields. 2 | 3 | use crate::emit::SourceWriter; 4 | use crate::rust::fields::GenFieldImpl; 5 | use crate::Field; 6 | 7 | pub struct Singular; 8 | impl GenFieldImpl for Singular { 9 | fn in_storage_init(&self, _: Field, w: &mut SourceWriter) { 10 | w.write( 11 | " 12 | $name: $None, 13 | ", 14 | ); 15 | } 16 | 17 | fn in_debug(&self, _: Field, w: &mut SourceWriter) { 18 | w.write( 19 | r#" 20 | if let $Some(value) = self.${name}_or() { 21 | if count != 0 { debug.comma(false)?; } 22 | debug.field("$raw_name")?; 23 | value.__debug(debug)?; 24 | count += 1; 25 | } 26 | "#, 27 | ); 28 | } 29 | } 30 | 31 | pub struct Repeated; 32 | impl GenFieldImpl for Repeated { 33 | fn in_storage_init(&self, _: Field, w: &mut SourceWriter) { 34 | w.write( 35 | " 36 | $name: __z::AVec::new(), 37 | ", 38 | ); 39 | } 40 | 41 | fn in_debug(&self, _: Field, w: &mut SourceWriter) { 42 | w.write( 43 | r#" 44 | for value in self.$name() { 45 | if count != 0 { debug.comma(false)?; } 46 | debug.field("$raw_name")?; 47 | value.__debug(debug)?; 48 | count += 1; 49 | } 50 | "#, 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /rust/plugin/src/rust/fields/str.rs: -------------------------------------------------------------------------------- 1 | // Field codegen for string fields. 2 | 3 | use crate::emit::SourceWriter; 4 | use crate::rust::fields::GenFieldImpl; 5 | use crate::Field; 6 | 7 | pub struct Singular; 8 | impl GenFieldImpl for Singular { 9 | fn in_storage_init(&self, _: Field, w: &mut SourceWriter) { 10 | w.write( 11 | " 12 | $name: __z::RawStr::new(), 13 | ", 14 | ); 15 | } 16 | 17 | fn in_debug(&self, _: Field, w: &mut SourceWriter) { 18 | w.write( 19 | r#" 20 | if let $Some(value) = self.${name}_or() { 21 | if count != 0 { debug.comma(false)?; } 22 | debug.field("$raw_name")?; 23 | debug.write_debug(value); 24 | count += 1; 25 | } 26 | "#, 27 | ); 28 | } 29 | } 30 | 31 | pub struct Repeated; 32 | impl GenFieldImpl for Repeated { 33 | fn in_storage_init(&self, _: Field, w: &mut SourceWriter) { 34 | w.write( 35 | " 36 | $name: __z::AVec::new(), 37 | ", 38 | ); 39 | } 40 | 41 | fn in_debug(&self, _: Field, w: &mut SourceWriter) { 42 | w.write( 43 | r#" 44 | if !self.$name().is_empty() { 45 | if count != 0 { debug.comma(false)?; } 46 | debug.field("$raw_name")?; 47 | debug.iter(self.$name())?; 48 | count += 1; 49 | } 50 | "#, 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /rust/src/proto/plugin.proto: -------------------------------------------------------------------------------- 1 | // 2 | 3 | syntax = "proto2"; 4 | package pz.plugin; 5 | 6 | import "pz.proto"; 7 | 8 | message Request { 9 | oneof value { 10 | AboutRequest about = 1; 11 | CodegenRequest codegen = 2; 12 | } 13 | } 14 | 15 | message Response { 16 | oneof value { 17 | AboutResponse about = 1; 18 | CodegenResponse codegen = 2; 19 | } 20 | } 21 | 22 | message AboutRequest {} 23 | 24 | message AboutResponse { 25 | message Option { 26 | optional string name = 1; 27 | optional string help = 2; 28 | } 29 | 30 | optional string name = 1; 31 | optional string version = 2; 32 | repeated Option options = 10; 33 | } 34 | 35 | message CodegenRequest { 36 | optional pz.Bundle bundle = 1; 37 | repeated uint32 requested_indices = 2; 38 | 39 | map options = 3; 40 | optional bool debug = 4; 41 | } 42 | 43 | message CodegenResponse { 44 | message File { 45 | optional string path = 1; 46 | optional bytes content = 2; 47 | } 48 | 49 | repeated File files = 1; 50 | repeated Diagnostic report = 2; 51 | } 52 | 53 | message Diagnostic { 54 | enum Kind { 55 | ERROR = 0; 56 | WARNING = 1; 57 | } 58 | 59 | message Snippet { 60 | optional uint32 span = 1; 61 | optional string message = 2; 62 | optional bool is_remark = 3; 63 | } 64 | 65 | optional Kind kind = 1; 66 | optional string message = 2; 67 | repeated Snippet snippets = 3; 68 | repeated string notes = 4; 69 | } -------------------------------------------------------------------------------- /rust/src/proto/pz.proto: -------------------------------------------------------------------------------- 1 | // 2 | 3 | syntax = "proto2"; 4 | package pz; 5 | 6 | message Bundle { 7 | repeated Type types = 1; 8 | repeated string packages = 2; 9 | 10 | message ForeignType { 11 | optional string name = 1; 12 | optional uint32 package = 2; 13 | } 14 | repeated ForeignType foreign_types = 3; 15 | } 16 | 17 | message Type { 18 | enum Kind { 19 | MESSAGE = 0; 20 | STRUCT = 1; 21 | CHOICE = 2; 22 | ENUM = 3; 23 | } 24 | 25 | message Attrs { 26 | optional string deprecated = 1; 27 | 28 | repeated string docs = 100; 29 | } 30 | 31 | optional string name = 1; 32 | optional uint32 package = 2; 33 | optional Kind kind = 3; 34 | optional uint32 declared_in = 4; 35 | 36 | repeated Field fields = 10; 37 | repeated uint32 nesteds = 11; 38 | optional Attrs attrs = 12; 39 | 40 | optional uint32 span = 20; 41 | } 42 | 43 | message Field { 44 | enum Type { 45 | NONE = 0; 46 | 47 | I32 = 1; 48 | U32 = 2; 49 | F32 = 3; 50 | I64 = 4; 51 | U64 = 5; 52 | F64 = 6; 53 | 54 | BOOL = 7; 55 | STRING = 8; 56 | 57 | TYPE = 9; 58 | FOREIGN = 10; 59 | } 60 | 61 | message Attrs { 62 | optional string deprecated = 1; 63 | 64 | repeated string docs = 100; 65 | } 66 | 67 | optional string name = 1; 68 | optional int32 number = 2; 69 | optional bool is_repeated = 3; 70 | optional Type type = 4; 71 | optional uint32 type_index = 5; 72 | 73 | optional Attrs attrs = 10; 74 | 75 | optional uint32 span = 20; 76 | } -------------------------------------------------------------------------------- /rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! `pz` Runtime 2 | //! 3 | //! This crate provides runtime support for generated Rust code from `.pz` 4 | //! files. 5 | 6 | mod arena; 7 | mod debug; 8 | 9 | mod tdp; 10 | pub use crate::tdp::parse::Error; 11 | 12 | pub mod reflect; 13 | pub use crate::reflect::Message; 14 | pub use crate::reflect::Mut; 15 | pub use crate::reflect::Ref; 16 | pub use crate::reflect::Type; 17 | 18 | mod rep; 19 | pub use crate::rep::Repeated; 20 | pub use crate::rep::Slice; 21 | pub use crate::rep::SliceMut; 22 | 23 | mod str; 24 | pub use crate::str::Str; 25 | pub use crate::str::StrBuf; 26 | pub use crate::str::String; 27 | 28 | mod opt; 29 | pub use crate::opt::OptMut; 30 | 31 | mod scalar; 32 | pub use crate::scalar::ScalarMut; 33 | 34 | mod macros; 35 | 36 | pub mod proto; 37 | 38 | pub extern crate prost; 39 | 40 | /// A serialization format for a [`Message`]. 41 | pub enum Codec { 42 | /// The Protobuf wire format, with pz's own twists. 43 | Protobuf, 44 | // TODO: Json, Textproto, 45 | } 46 | 47 | #[doc(hidden)] 48 | pub mod __z { 49 | pub use std; 50 | 51 | pub enum Void {} 52 | 53 | pub mod tdp { 54 | pub use crate::tdp::*; 55 | } 56 | 57 | pub mod macros { 58 | pub use crate::macros::*; 59 | } 60 | 61 | pub use crate::arena::*; 62 | pub use crate::debug::Debug; 63 | pub use crate::str::private::Storage as RawStr; 64 | 65 | pub use crate::reflect::names::*; 66 | pub use crate::reflect::private::*; 67 | 68 | pub use crate::seal::*; 69 | } 70 | 71 | pub(crate) mod seal { 72 | pub struct Seal; 73 | pub trait Sealed {} 74 | impl Sealed for Seal {} 75 | } 76 | -------------------------------------------------------------------------------- /rust/tests/proto/test.pz: -------------------------------------------------------------------------------- 1 | @edition = "2023" 2 | package pz.test 3 | 4 | // Tests everything in the language. 5 | 6 | message TestAll { 7 | 1. opt_i32: i32 8 | 2. opt_i64: i64 9 | 3. opt_u32: u32 10 | 4. opt_u64: u64 11 | 5. opt_f32: f32 12 | 6. opt_f64: f64 13 | 7. opt_str: str 14 | 8. opt_bool: bool 15 | 16 | 10. opt_recursive: TestAll 17 | 18 | message Nested { 19 | 1. a: i32 20 | 2. b: repeated str 21 | } 22 | 11. opt_nested: Nested 23 | 12. opt_choice: TestAll2 24 | 25 | 21. rep_i32: repeated i32 26 | 22. rep_i64: repeated i64 27 | 23. rep_u32: repeated u32 28 | 24. rep_u64: repeated u64 29 | 25. rep_f32: repeated f32 30 | 26. rep_f64: repeated f64 31 | 27. rep_str: repeated str 32 | 28. rep_bool: repeated bool 33 | 34 | 30. rep_recursive: repeated TestAll 35 | 31. rep_nested: repeated Nested 36 | 32. rep_choice: repeated TestAll2 37 | } 38 | 39 | choice TestAll2 { 40 | 1. opt_i32: i32 41 | 2. opt_i64: i64 42 | 3. opt_u32: u32 43 | 4. opt_u64: u64 44 | 5. opt_f32: f32 45 | 6. opt_f64: f64 46 | 7. opt_str: str 47 | 8. opt_bool: bool 48 | 49 | 10. opt_recursive: TestAll 50 | 51 | 11. opt_nested: pz.test.TestAll.Nested 52 | 12. opt_choice: TestAll2 53 | 54 | 21. rep_i32: repeated i32 55 | 22. rep_i64: repeated i64 56 | 23. rep_u32: repeated u32 57 | 24. rep_u64: repeated u64 58 | 25. rep_f32: repeated f32 59 | 26. rep_f64: repeated f64 60 | 27. rep_str: repeated str 61 | 28. rep_bool: repeated bool 62 | 63 | 30. rep_recursive: repeated TestAll 64 | 31. rep_nested: repeated pz.test.TestAll.Nested 65 | 32. rep_choice: repeated TestAll2 66 | } -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | on: 3 | push: 4 | branches: [main] 5 | pull_request: 6 | branches: [main] 7 | 8 | env: 9 | CARGO_TERM_COLOR: always 10 | NIGHTLY: 'nightly-2024-08-30' 11 | 12 | jobs: 13 | bootstrap: 14 | name: Check Bootstrap 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Install protoc 20 | uses: arduino/setup-protoc@v3 21 | 22 | - name: Run bootstrap 23 | run: ./bootstrap.sh 24 | 25 | - name: Check for diffs 26 | run: git --no-pager diff --exit-code 27 | 28 | lint: 29 | name: Check Linting 30 | runs-on: ubuntu-latest 31 | steps: 32 | - uses: actions/checkout@v2 33 | 34 | - name: Install protoc 35 | uses: arduino/setup-protoc@v3 36 | 37 | - name: Check format 38 | run: cargo fmt -- --check --files-with-diff 39 | 40 | - name: Check clippy lints 41 | run: cargo clippy --all-targets --verbose 42 | 43 | build_and_test: 44 | name: Build and Test (Rust) 45 | runs-on: ubuntu-latest 46 | steps: 47 | - uses: actions/checkout@v2 48 | 49 | - name: Install protoc 50 | uses: arduino/setup-protoc@v3 51 | 52 | - name: Build with default settings 53 | run: | 54 | cargo build -v 55 | cargo build --release -v 56 | 57 | - name: Build docs 58 | run: cargo doc --verbose 59 | 60 | - name: Run tests 61 | run: cargo test --verbose 62 | 63 | miri: 64 | name: Build and Test (MIRI) 65 | runs-on: ubuntu-latest 66 | steps: 67 | - uses: actions/checkout@v2 68 | 69 | - name: Install protoc 70 | uses: arduino/setup-protoc@v3 71 | 72 | - name: Install Miri 73 | run: rustup +$NIGHTLY component add miri 74 | 75 | - name: Run tests under Miri 76 | run: cargo +$NIGHTLY miri test -p pz -------------------------------------------------------------------------------- /rust/src/reflect/private.rs: -------------------------------------------------------------------------------- 1 | //! Private items of reflection traits. 2 | 3 | use std::ptr::NonNull; 4 | 5 | use crate::arena::AVec; 6 | use crate::arena::RawArena; 7 | use crate::reflect::Mut; 8 | use crate::reflect::Ref; 9 | use crate::reflect::Views; 10 | use crate::seal::Sealed; 11 | use crate::tdp; 12 | use crate::tdp::Opaque; 13 | 14 | pub trait Type: Views { 15 | /// The actual underlying storage type for this type. This is used in 16 | /// the implementation of repeated fields. 17 | #[doc(hidden)] 18 | type __Storage; 19 | 20 | /// Constructs a view out of a pointer to storage for this type. 21 | /// 22 | /// # Safety 23 | /// 24 | /// The pointer must be dereferenceable for this type. 25 | #[doc(hidden)] 26 | unsafe fn __ref<'a, S: Sealed>( 27 | _: S, 28 | ptr: NonNull>, 29 | ) -> Ref<'a, Self>; 30 | 31 | /// Constructs a view out of a pointer to storage for this type. 32 | /// 33 | /// # Safety 34 | /// 35 | /// The pointer must be uniquely dereferenceable for this type. 36 | #[doc(hidden)] 37 | unsafe fn __mut<'a, S: Sealed>( 38 | _: S, 39 | ptr: NonNull>, 40 | arena: RawArena, 41 | ) -> Mut<'a, Self>; 42 | 43 | /// Resizes storage for a repeated field for this type. 44 | /// 45 | /// # Safety 46 | /// 47 | /// The arena vector must be dereferenceable and belong to the given arena. 48 | #[doc(hidden)] 49 | unsafe fn __resize( 50 | _: S, 51 | vec: &mut AVec>, 52 | new_len: usize, 53 | arena: RawArena, 54 | ) { 55 | vec.resize(new_len, arena) 56 | } 57 | } 58 | 59 | pub trait Message: Views { 60 | /// TDP metadata for this message. 61 | #[doc(hidden)] 62 | const __TDP: tdp::Desc; 63 | 64 | #[doc(hidden)] 65 | fn __is_null(&self, _: impl Sealed) -> bool; 66 | #[doc(hidden)] 67 | fn __raw(_: impl Sealed, ptr: Ref) -> Opaque; 68 | #[doc(hidden)] 69 | fn __arena(_: impl Sealed, ptr: &mut Mut) -> RawArena; 70 | } 71 | -------------------------------------------------------------------------------- /rust/plugin/src/rust/names.rs: -------------------------------------------------------------------------------- 1 | //! Naming helper functions. 2 | 3 | use std::fmt; 4 | 5 | use crate::emit; 6 | use crate::Field; 7 | use crate::Type; 8 | 9 | const INESCAPABLE_KWS: &[&str] = &["crate", "self", "super", "Self"]; 10 | 11 | const KWS: &[&str] = &[ 12 | "as", "break", "const", "continue", "crate", "else", "enum", "extern", 13 | "false", "pub fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", 14 | "move", "mut", "pub", "ref", "return", "self", "Self", "static", "struct", 15 | "super", "trait", "true", "type", "unsafe", "use", "where", "while", "async", 16 | "await", "dyn", "abstract", "become", "box", "do", "final", "macro", 17 | "override", "priv", "typeof", "unsized", "virtual", "yield", "try", 18 | ]; 19 | 20 | pub fn ident(name: impl fmt::Display) -> impl fmt::Display { 21 | emit::display(move |f| { 22 | let name = name.to_string(); 23 | if INESCAPABLE_KWS.contains(&name.as_str()) { 24 | write!(f, "{name}_") 25 | } else if KWS.contains(&name.as_str()) { 26 | write!(f, "r#{name}") 27 | } else { 28 | f.write_str(name.as_str()) 29 | } 30 | }) 31 | } 32 | 33 | pub fn type_name(ty: Type) -> impl fmt::Display + '_ { 34 | emit::display(move |f| { 35 | f.write_str("__")?; 36 | for component in ty.package().split(".") { 37 | f.write_fmt(format_args!("::{}", ident(component)))?; 38 | } 39 | 40 | f.write_fmt(format_args!("::{}", ident(&ty.name().replace('.', "_")))) 41 | }) 42 | } 43 | 44 | pub fn type_ident(ty: Type) -> impl fmt::Display + '_ { 45 | emit::display(move |f| { 46 | f.write_fmt(format_args!("{}", ident(&ty.name().replace('.', "_")))) 47 | }) 48 | } 49 | 50 | pub fn field_name_type_name(field: Field) -> impl fmt::Display + '_ { 51 | emit::display(move |f| { 52 | write!( 53 | f, 54 | "__field_{}__{}", 55 | type_ident(field.parent()), 56 | field.name() 57 | ) 58 | }) 59 | } 60 | 61 | pub fn deprecated(reason: Option<&str>) -> impl fmt::Display + '_ { 62 | emit::display(move |f| match reason { 63 | Some(value) => write!(f, "#[deprecated = {value:?}]"), 64 | _ => Ok(()), 65 | }) 66 | } 67 | -------------------------------------------------------------------------------- /rust/plugin/src/rust/fields/scalar.rs: -------------------------------------------------------------------------------- 1 | // Field codegen for scalar fields. 2 | 3 | use std::fmt; 4 | 5 | use crate::emit; 6 | use crate::emit::SourceWriter; 7 | use crate::rust::fields::GenFieldImpl; 8 | use crate::rust::fields::TypeEnum; 9 | use crate::rust::names; 10 | use crate::Field; 11 | 12 | fn scalar_default(field: Field) -> impl fmt::Display + '_ { 13 | emit::display(move |f| match field.ty() { 14 | (TypeEnum::I32, _) => f.write_str("0"), 15 | (TypeEnum::U32, _) => f.write_str("0"), 16 | (TypeEnum::F32, _) => f.write_str("0.0"), 17 | (TypeEnum::I64, _) => f.write_str("0"), 18 | (TypeEnum::U64, _) => f.write_str("0"), 19 | (TypeEnum::F64, _) => f.write_str("0.0"), 20 | (TypeEnum::Bool, _) => f.write_str("false"), 21 | (TypeEnum::Type, Some(e)) => { 22 | write!(f, "{}::new()", names::type_name(e)) 23 | } 24 | (t, _) => panic!("non-scalar type: {t:?}"), 25 | }) 26 | } 27 | 28 | pub struct Singular; 29 | impl GenFieldImpl for Singular { 30 | fn in_storage_init(&self, field: Field, w: &mut SourceWriter) { 31 | w.emit( 32 | vars! { default: scalar_default(field) }, 33 | " 34 | ${#name}: $default, 35 | ", 36 | ); 37 | } 38 | 39 | fn in_debug(&self, _: Field, w: &mut SourceWriter) { 40 | w.write( 41 | r#" 42 | if let $Some(value) = self.${name}_or() { 43 | if count != 0 { debug.comma(false)?; } 44 | debug.field("$raw_name")?; 45 | debug.write_debug(value); 46 | count += 1; 47 | } 48 | "#, 49 | ); 50 | } 51 | } 52 | 53 | pub struct Repeated; 54 | impl GenFieldImpl for Repeated { 55 | fn in_storage_init(&self, field: Field, w: &mut SourceWriter) { 56 | w.emit( 57 | vars! { name: names::ident(field.name()) }, 58 | " 59 | $name: __z::AVec::new(), 60 | ", 61 | ); 62 | } 63 | 64 | fn in_debug(&self, _: Field, w: &mut SourceWriter) { 65 | w.write( 66 | r#" 67 | if !self.$name().is_empty() { 68 | if count != 0 { debug.comma(false)?; } 69 | debug.field("$raw_name")?; 70 | debug.iter(self.$name())?; 71 | count += 1; 72 | } 73 | "#, 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /rust/src/reflect/names.rs: -------------------------------------------------------------------------------- 1 | //! Support for compile-time field name reflection. 2 | 3 | use crate::seal::Sealed; 4 | 5 | /// Constructs an opaque field name key. 6 | /// 7 | /// This macro may be used in either type or expression position. The type 8 | /// `field!(my_field)` always unifies with itself, no matter where the macro 9 | /// is expanded. This is used by static reflection for doing type-level lookup 10 | /// of field information (e.g. via [`Field`]). 11 | /// 12 | /// In expression position, this macro expands to a ZST value of the 13 | /// corresponding type. 14 | /// 15 | /// The field name may be either an identifier or a string literal. 16 | /// 17 | /// [`Field`]: crate::reflect::Field 18 | #[macro_export] 19 | macro_rules! field { 20 | ($name:literal) => { 21 | $crate::__z::FnvName::<{ $crate::__z::fnv1($name.as_bytes()) }> 22 | }; 23 | ($name:ident) => { 24 | $crate::__z::FnvName::< 25 | { $crate::__z::fnv1(::std::stringify!($name).as_bytes()) }, 26 | > 27 | }; 28 | } 29 | 30 | /// Constructs a tuple of [`field!()`] values. 31 | /// 32 | /// `fields!(a, b, c)` expands to `(field!(a), field!(b), field!(c))`. 33 | #[macro_export] 34 | macro_rules! fields { 35 | ($($name:literal),* $(,)?) => { 36 | ($(field!($name),)*) 37 | }; 38 | ($($name:ident),* $(,)?) => { 39 | ($(field!($name),)*) 40 | }; 41 | } 42 | 43 | /// A field name. 44 | /// 45 | /// Types that implement `Name` can be generated using [`field!()`]. 46 | pub trait Name: Copy { 47 | fn __do_not_implement(_: impl Sealed); 48 | } 49 | impl Name for FnvName { 50 | fn __do_not_implement(_: impl Sealed) {} 51 | } 52 | 53 | // Currently, it is intended to be used as `Name::<{fnv1("my_field")}>`, which 54 | // is a type that can be used to key into things that do field lookup in a 55 | // message type. 56 | #[derive(Copy, Clone)] 57 | pub struct FnvName; 58 | 59 | /// Computes 128-bit FNV-1 of `bytes`. 60 | pub const fn fnv1(bytes: &[u8]) -> u128 { 61 | const BASIS: u128 = 0x0000000001000000000000000000013b; 62 | const PRIME: u128 = 0x6c62272e07bb014262b821756295c58d; 63 | 64 | let mut hash = BASIS; 65 | let mut i = 0; 66 | while i < bytes.len() { 67 | hash = hash.wrapping_mul(PRIME); 68 | hash ^= bytes[i] as u128; 69 | i += 1; 70 | } 71 | 72 | hash 73 | } 74 | -------------------------------------------------------------------------------- /rust/src/scalar.rs: -------------------------------------------------------------------------------- 1 | //! Types for scalars. 2 | 3 | use std::ptr::NonNull; 4 | 5 | use crate::arena::RawArena; 6 | use crate::reflect::private; 7 | use crate::reflect::Mut; 8 | use crate::reflect::MutView; 9 | use crate::reflect::Opt; 10 | use crate::reflect::Ref; 11 | use crate::reflect::RefView; 12 | use crate::reflect::Set; 13 | use crate::reflect::Type; 14 | use crate::reflect::Views; 15 | use crate::seal::Sealed; 16 | 17 | /// A mutator view for a scalar type, like `i32` or an enum. 18 | /// 19 | /// This is a custom type rather than an `&mut T` to account for layout 20 | /// optimizations (such as packing). 21 | pub struct ScalarMut<'a, T> { 22 | ptr: &'a mut T, 23 | } 24 | 25 | impl<'a, T: Copy> ScalarMut<'a, T> { 26 | #[doc(hidden)] 27 | pub fn __wrap(ptr: &'a mut T) -> Self { 28 | Self { ptr } 29 | } 30 | 31 | /// Reads out the value that this mutator view refers to. 32 | pub fn get(&self) -> T { 33 | *self.ptr 34 | } 35 | 36 | /// Sets the value this mutator view refers to. 37 | pub fn set(&mut self, val: T) { 38 | *self.ptr = val; 39 | } 40 | } 41 | 42 | impl<'a, T: Copy + Type> MutView<'a> for ScalarMut<'a, T> 43 | where 44 | T: for<'b> Views = T, Mut<'b> = ScalarMut<'b, T>>, 45 | { 46 | type Target = T; 47 | 48 | fn as_ref(&self) -> Ref { 49 | self.get() 50 | } 51 | 52 | fn into_ref(self) -> Ref<'a, T> { 53 | self.get() 54 | } 55 | 56 | fn as_mut(&mut self) -> Mut { 57 | ScalarMut { ptr: self.ptr } 58 | } 59 | } 60 | 61 | macro_rules! impl_scalar { 62 | ($($T:ty),*) => {$( 63 | impl private::Type for $T { 64 | type __Storage = Self; 65 | 66 | unsafe fn __ref<'a, S: Sealed>(_: S, ptr: NonNull) -> Ref<'a, Self> { 67 | ptr.read() 68 | } 69 | 70 | unsafe fn __mut<'a, S: Sealed>( 71 | _: S, 72 | mut ptr: NonNull, 73 | _: RawArena, 74 | ) -> Mut<'a, Self> { 75 | ScalarMut { ptr: ptr.as_mut() } 76 | } 77 | } 78 | 79 | impl Views for $T { 80 | type Ref<'a> = Self; 81 | type Mut<'a> = ScalarMut<'a, Self>; 82 | } 83 | 84 | impl RefView<'_> for $T { 85 | type Target = Self; 86 | 87 | fn as_ref(&self) -> Self { 88 | *self 89 | } 90 | } 91 | 92 | impl Set<$T> for $T { 93 | fn apply_to(self, mut m: Mut<$T>) { 94 | m.set(self) 95 | } 96 | } 97 | 98 | impl Set> for $T { 99 | fn apply_to(self, m: Mut>) { 100 | m.into_inner().set(self) 101 | } 102 | } 103 | )*}; 104 | } 105 | 106 | impl_scalar!(i32, i64, u32, u64, f32, f64, bool); 107 | -------------------------------------------------------------------------------- /rust/src/debug.rs: -------------------------------------------------------------------------------- 1 | //! Debug printing helpers. 2 | 3 | use std::fmt; 4 | use std::fmt::Write; 5 | 6 | pub struct Debug<'a, 'b> { 7 | fmt: &'a mut fmt::Formatter<'b>, 8 | indent: usize, 9 | open_brace: bool, 10 | } 11 | 12 | impl<'a, 'b> Debug<'a, 'b> { 13 | pub fn new(fmt: &'a mut fmt::Formatter<'b>) -> Self { 14 | Self { 15 | fmt, 16 | indent: 0, 17 | open_brace: false, 18 | } 19 | } 20 | 21 | fn new_line(&mut self, include_space: bool) -> fmt::Result { 22 | if !self.fmt.alternate() { 23 | if include_space { 24 | return Ok(()); 25 | } 26 | return self.fmt.write_char(' '); 27 | } 28 | 29 | self.fmt.write_char('\n')?; 30 | for _ in 0..self.indent { 31 | self.fmt.write_char(' ')?; 32 | } 33 | 34 | Ok(()) 35 | } 36 | 37 | pub fn start_block(&mut self) -> fmt::Result { 38 | self.indent += 2; 39 | self.open_brace = true; 40 | self.fmt.write_char('{') 41 | } 42 | 43 | pub fn end_block(&mut self) -> fmt::Result { 44 | self.indent -= 2; 45 | if !self.open_brace { 46 | self.new_line(true)?; 47 | } 48 | self.open_brace = false; 49 | self.fmt.write_char('}') 50 | } 51 | 52 | pub fn field(&mut self, name: &str) -> fmt::Result { 53 | self.open_brace = false; 54 | self.new_line(true)?; 55 | write!(self.fmt, "{name}: ") 56 | } 57 | 58 | pub fn write_debug(&mut self, val: impl fmt::Debug) -> fmt::Result { 59 | write!(self.fmt, "{val:?}") 60 | } 61 | 62 | pub fn comma(&mut self, is_last: bool) -> fmt::Result { 63 | if !is_last || self.fmt.alternate() { 64 | self.fmt.write_char(',')?; 65 | } 66 | 67 | Ok(()) 68 | } 69 | 70 | pub fn iter( 71 | &mut self, 72 | values: impl IntoIterator, 73 | ) -> fmt::Result { 74 | let iter = values.into_iter(); 75 | if iter.size_hint().1.filter(|&n| n <= 8).is_some() { 76 | self.fmt.write_char('[')?; 77 | for (i, v) in iter.enumerate() { 78 | if i != 0 { 79 | self.fmt.write_str(", ")?; 80 | } 81 | v.fmt(self.fmt)?; 82 | } 83 | self.fmt.write_char(']')?; 84 | return Ok(()); 85 | } 86 | 87 | self.fmt.write_char('[')?; 88 | self.indent += 2; 89 | for (i, v) in iter.enumerate() { 90 | if i != 0 { 91 | self.comma(false)?; 92 | self.new_line(false)?; 93 | } else { 94 | self.new_line(true)?; 95 | } 96 | v.fmt(self.fmt)?; 97 | } 98 | self.comma(true)?; 99 | self.indent -= 2; 100 | self.new_line(false)?; 101 | self.fmt.write_char(']')?; 102 | 103 | Ok(()) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /rust/src/reflect/view.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use crate::seal::Seal; 4 | use crate::seal::Sealed; 5 | 6 | /// A type that has generalized view types. 7 | /// 8 | /// A view is like a reference, but does not carry all of the semantics of a 9 | /// reference. For example, `View` is just an `i32`, not a reference. 10 | /// 11 | /// Views can also carry additional information for a given type. For example, 12 | /// mutable views for message types carry around an arena, for allocating new 13 | /// submessages. 14 | pub trait Views: 'static + Sized { 15 | /// The shared view type, analogous to a shared reference. 16 | type Ref<'a>: RefView<'a, Target = Self> + fmt::Debug; 17 | 18 | /// The mutable view type, analogous to a mutable reference. 19 | type Mut<'a>: MutView<'a, Target = Self>; 20 | } 21 | 22 | /// Selects [`Ref`] or [`Mut`] based on a type parameter. 23 | /// 24 | /// The `Which` parameter must implement the [`Select`] trait, which is only 25 | /// implemented by [`SelectRef`] and [`SelectMut`]. 26 | pub type View<'a, T, Which> = ::View<'a, T, Seal>; 27 | 28 | /// Shorthand for [`Views::Ref`]. 29 | pub type Ref<'a, T> = ::Ref<'a>; 30 | 31 | /// Shorthand for [`Views::Mut`]. 32 | pub type Mut<'a, T> = ::Mut<'a>; 33 | 34 | /// A view-like type, analogous to a shared reference. 35 | pub trait RefView<'a>: Copy + Default { 36 | type Target: Views + ?Sized; 37 | 38 | /// Shortens this view's lifetime, analogous to reborrowing. 39 | /// 40 | /// In general, this function is only necessary in generic code; all view 41 | /// types are already covariant. 42 | fn as_ref(&self) -> Ref; 43 | } 44 | 45 | /// A mutator-like type, analogous to a mutable reference. 46 | pub trait MutView<'a> { 47 | type Target: Views + ?Sized; 48 | 49 | /// Shortens this view's lifetime, analogous to reborrowing. 50 | /// 51 | /// In general, this function is only necessary in generic code; all view 52 | /// types are already covariant. 53 | fn as_ref(&self) -> Ref; 54 | 55 | /// Consumes this mutator, converting it into an immutable view. 56 | /// 57 | /// Unlike `as_view()`, calling this function preserves the lifetime of the 58 | /// input mutator. 59 | fn into_ref(self) -> Ref<'a, Self::Target>; 60 | 61 | /// Shortens this mutator's lifetime, analogous to reborrowing. 62 | /// 63 | /// Use this function to create a temporary copy of this mutator, allowing 64 | /// for multiple mutation operations in sequence. 65 | fn as_mut(&mut self) -> Mut; 66 | } 67 | 68 | /// A selector for use with [`View`]. 69 | pub trait Select: Sealed { 70 | #[doc(hidden)] 71 | type View<'a, T: Views, S: Sealed>; 72 | } 73 | 74 | /// A [`Select`] that selects a proxied type's view. 75 | #[derive(Copy, Clone)] 76 | pub struct SelectRef(()); 77 | impl Sealed for SelectRef {} 78 | impl Select for SelectRef { 79 | type View<'a, T: Views, S: Sealed> = T::Ref<'a>; 80 | } 81 | 82 | /// A [`Select`] that selects a proxied type's mutator. 83 | #[derive(Copy, Clone)] 84 | pub struct SelectMut(()); 85 | impl Sealed for SelectMut {} 86 | impl Select for SelectMut { 87 | type View<'a, T: Views, S: Sealed> = T::Mut<'a>; 88 | } 89 | -------------------------------------------------------------------------------- /rust/plugin/src/rust/enum.rs: -------------------------------------------------------------------------------- 1 | //! Enum codegen. 2 | 3 | use crate::emit::SourceWriter; 4 | use crate::rust::names::deprecated; 5 | use crate::rust::names::ident; 6 | use crate::Type; 7 | 8 | pub fn emit(ty: Type, w: &mut SourceWriter) { 9 | w.emit( 10 | vars! { 11 | "Enum::Variants": |w| for field in ty.fields() { 12 | w.emit( 13 | vars! { 14 | Name: ident(&heck::AsPascalCase(field.name()).to_string()), 15 | NUMBER: field.number().unwrap(), 16 | deprecated: deprecated( 17 | field.proto().attrs.as_ref().and_then(|a| a.deprecated.as_deref())), 18 | }, 19 | r" 20 | $deprecated 21 | pub const $Name: Self = Self($NUMBER); 22 | " 23 | ); 24 | }, 25 | debug_arms: |w| for field in ty.fields() { 26 | w.emit( 27 | vars! { 28 | Name: ident(&heck::AsPascalCase(field.name()).to_string()), 29 | }, 30 | r#" 31 | Self::$Name => __s::write!(fmt, "$Name"), 32 | "#, 33 | ); 34 | }, 35 | "DEFAULT": match ty.fields().next() { 36 | Some(f) => f.number().unwrap(), 37 | _ => 0, 38 | }, 39 | }, 40 | r#" 41 | /// enum `$package.$Name` 42 | $deprecated 43 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 44 | #[repr(transparent)] 45 | pub struct $Ident(pub __s::primitive::i32); 46 | 47 | impl $Type { 48 | ${Enum::Variants} 49 | 50 | pub const fn new() -> Self { 51 | Self($DEFAULT) 52 | } 53 | } 54 | 55 | impl $Default for $Type { 56 | fn default() -> Self { 57 | Self($DEFAULT) 58 | } 59 | } 60 | 61 | impl __z::Type for $Type { 62 | type __Storage = Self; 63 | 64 | unsafe fn __ref<'a, S: __z::Sealed>(_: S, ptr: $NonNull) -> __rt::Ref<'a, Self> { 65 | ptr.read() 66 | } 67 | 68 | unsafe fn __mut<'a, S: __z::Sealed>( 69 | _: S, 70 | mut ptr: $NonNull, 71 | _: __z::RawArena, 72 | ) -> __rt::Mut<'a, Self> { 73 | __rt::ScalarMut::__wrap(ptr.as_mut()) 74 | } 75 | } 76 | 77 | impl __r::Views for $Type { 78 | type Ref<'a> = Self; 79 | type Mut<'a> = __rt::ScalarMut<'a, Self>; 80 | } 81 | 82 | impl __r::RefView<'_> for $Type { 83 | type Target = Self; 84 | 85 | fn as_ref(&self) -> Self { 86 | *self 87 | } 88 | } 89 | 90 | impl __r::Set<$Type> for $Type { 91 | fn apply_to(self, mut m: __r::Mut<$Type>) { 92 | m.set(self) 93 | } 94 | } 95 | 96 | impl __r::Set<__r::Opt<$Type>> for $Type { 97 | fn apply_to(self, m: __r::Mut<__r::Opt<$Type>>) { 98 | m.into_inner().set(self) 99 | } 100 | } 101 | 102 | impl $fmt::Debug for $Type { 103 | fn fmt(&self, fmt: &mut $fmt::Formatter) -> $fmt::Result { 104 | match *self { 105 | $debug_arms 106 | Self(n) => __s::write!(fmt, "$package.$Name({n})"), 107 | } 108 | } 109 | } 110 | "#, 111 | ); 112 | w.new_line(); 113 | } 114 | -------------------------------------------------------------------------------- /rust/src/rep/iter.rs: -------------------------------------------------------------------------------- 1 | //! Iterator implementations. 2 | 3 | use std::marker::PhantomData; 4 | use std::ptr::NonNull; 5 | 6 | use crate::arena::RawArena; 7 | use crate::rep::Elem; 8 | use crate::rep::Repeated; 9 | use crate::rep::Slice; 10 | use crate::rep::SliceMut; 11 | use crate::seal::Seal; 12 | use crate::Mut; 13 | use crate::Ref; 14 | use crate::Type; 15 | 16 | pub struct Iter<'a, T: Type + ?Sized> { 17 | start: NonNull>, 18 | end: NonNull>, 19 | _ph: PhantomData<&'a T>, 20 | } 21 | 22 | impl<'a, T: Type + ?Sized> Iterator for Iter<'a, T> { 23 | type Item = Ref<'a, T>; 24 | 25 | fn next(&mut self) -> Option { 26 | if self.start == self.end { 27 | return None; 28 | } 29 | let ptr = self.start; 30 | unsafe { 31 | self.start = ptr.add(1); 32 | Some(T::__ref(Seal, ptr)) 33 | } 34 | } 35 | 36 | fn size_hint(&self) -> (usize, Option) { 37 | let len = unsafe { self.end.offset_from(self.start) } as usize; 38 | (len, Some(len)) 39 | } 40 | } 41 | 42 | pub struct IterMut<'a, T: Type + ?Sized> { 43 | start: NonNull>, 44 | end: NonNull>, 45 | arena: RawArena, 46 | _ph: PhantomData<&'a mut T>, 47 | } 48 | 49 | impl<'a, T: Type + ?Sized> Iterator for IterMut<'a, T> { 50 | type Item = Mut<'a, T>; 51 | 52 | fn next(&mut self) -> Option { 53 | if self.start == self.end { 54 | return None; 55 | } 56 | let ptr = self.start; 57 | unsafe { 58 | self.start = ptr.add(1); 59 | Some(T::__mut(Seal, ptr, self.arena)) 60 | } 61 | } 62 | 63 | fn size_hint(&self) -> (usize, Option) { 64 | let len = unsafe { self.end.offset_from(self.start) } as usize; 65 | (len, Some(len)) 66 | } 67 | } 68 | 69 | impl<'a, T: Type + ?Sized> IntoIterator for &'a Slice<'_, T> { 70 | type Item = Ref<'a, T>; 71 | type IntoIter = Iter<'a, T>; 72 | 73 | fn into_iter(self) -> Self::IntoIter { 74 | (*self).into_iter() 75 | } 76 | } 77 | 78 | impl<'a, T: Type + ?Sized> IntoIterator for Slice<'a, T> { 79 | type Item = Ref<'a, T>; 80 | type IntoIter = Iter<'a, T>; 81 | 82 | fn into_iter(self) -> Self::IntoIter { 83 | Iter { 84 | start: self.ptr, 85 | end: unsafe { self.ptr.add(self.len) }, 86 | _ph: PhantomData, 87 | } 88 | } 89 | } 90 | 91 | impl<'a, T: Type + ?Sized> IntoIterator for &'a SliceMut<'_, T> { 92 | type Item = Ref<'a, T>; 93 | type IntoIter = Iter<'a, T>; 94 | 95 | fn into_iter(self) -> Self::IntoIter { 96 | self.iter() 97 | } 98 | } 99 | 100 | impl<'a, T: Type + ?Sized> IntoIterator for &'a mut SliceMut<'_, T> { 101 | type Item = Mut<'a, T>; 102 | type IntoIter = IterMut<'a, T>; 103 | 104 | fn into_iter(self) -> Self::IntoIter { 105 | self.iter_mut() 106 | } 107 | } 108 | 109 | impl<'a, T: Type + ?Sized> IntoIterator for SliceMut<'a, T> { 110 | type Item = Mut<'a, T>; 111 | type IntoIter = IterMut<'a, T>; 112 | 113 | fn into_iter(self) -> Self::IntoIter { 114 | IterMut { 115 | start: self.slice.ptr, 116 | end: unsafe { self.slice.ptr.add(self.slice.len) }, 117 | arena: self.arena, 118 | _ph: PhantomData, 119 | } 120 | } 121 | } 122 | 123 | impl<'a, T: Type + ?Sized> IntoIterator for &'a Repeated<'_, T> { 124 | type Item = Ref<'a, T>; 125 | type IntoIter = Iter<'a, T>; 126 | 127 | fn into_iter(self) -> Self::IntoIter { 128 | self.iter() 129 | } 130 | } 131 | 132 | impl<'a, T: Type + ?Sized> IntoIterator for &'a mut Repeated<'_, T> { 133 | type Item = Mut<'a, T>; 134 | type IntoIter = IterMut<'a, T>; 135 | 136 | fn into_iter(self) -> Self::IntoIter { 137 | self.iter_mut() 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /rust/src/proto/pz.pz: -------------------------------------------------------------------------------- 1 | @edition = "2023" 2 | package pz 3 | 4 | /// A bundle, i.e., a collection of types and associated metadata. 5 | /// 6 | /// This type is a sort of Protobuf object code. 7 | message Bundle { 8 | /// Types in this bundle. 9 | 1. types: repeated Type 10 | 11 | /// Packages that this bundle defines or depends on. 12 | 2. packages: repeated str 13 | 14 | /// Foreign types referred to by fields in this bundle. 15 | 3. foreign_types: repeated ForeignType 16 | message ForeignType { 17 | /// The name of the relocated type. 18 | 1. name: str 19 | 20 | /// An index into `Bundle.packages`. 21 | 2. #package: u32 22 | } 23 | } 24 | 25 | /// A type declaration. 26 | message Type { 27 | /// The name of types type. If this is a nested type, it will be 28 | /// period-delimited, e.g. `Foo.Bar` is `Bar` nested in `Foo`. 29 | 1. name: str 30 | 31 | /// The package this type belongs to. 32 | /// 33 | /// This is an index into `Bundle.types`. 34 | 2. #package: u32 35 | 36 | 37 | /// The kind of declaration this is. 38 | 3. kind: Kind 39 | enum Kind { 40 | 0. MESSAGE 41 | 1. STRUCT 42 | 2. CHOICE 43 | 3. ENUM 44 | } 45 | 46 | /// The type this type is nested in, if present. 47 | /// 48 | /// This is an index into `Bundle.types`. 49 | 4. declared_in: u32 50 | 51 | /// This type's fields. 52 | 10. fields: repeated Field 53 | 54 | /// Types that are nested in this type. 55 | /// 56 | /// This is an index into `Bundle.types`. 57 | 11. nesteds: repeated u32 58 | 59 | /// Known attributes on this type. 60 | 12. attrs: Attrs 61 | message Attrs { 62 | /// If set, this indicates that this type is deprecated; the value 63 | /// of this field is the reason. 64 | 1. deprecated: str 65 | 66 | /// The contents of every `///` comment attached to the type. 67 | 100. docs: repeated str 68 | } 69 | 70 | /// The source code span this type came from, if any. This is an opaque value 71 | /// that can only be interpreted with respect to a particular plugin 72 | /// invocation. 73 | 20. span: u32 74 | } 75 | 76 | /// A type's field. 77 | message Field { 78 | /// This field's name. This is always a single identifier. 79 | 1. name: str 80 | /// The field number. May not be present for some type kinds (e.g. structs). 81 | 2. number: i32 82 | 83 | /// Whether this is a repeated field. 84 | 3. is_repeated: bool 85 | 86 | /// The field's type. 87 | /// 88 | /// The interpretation of `type_index` depends on the value of this field. 89 | /// 90 | /// TODO(mcyoung): this might make more sense as a `choice`. 91 | 4. type: Type 92 | enum Type { 93 | /// Indicates that this field has no type, such as the case for enum 94 | /// fields. 95 | 0. NONE 96 | 97 | 1. I32 98 | 2. U32 99 | 3. F32 100 | 4. I64 101 | 5. U64 102 | 6. F64 103 | 104 | 7. BOOL 105 | 8. STRING 106 | 107 | 9. TYPE 108 | 10. FOREIGN 109 | } 110 | 111 | /// An index into `Bundle.types` or `Bundle.foreign_types`. 112 | /// 113 | /// When `type` is `Type.TYPE`, this means it refers to a type defined in 114 | /// this bundle, which can be found by looking at the `types` field. If it 115 | /// is `Type.FOREIGN`, it is a type defined in another bundle, listed under 116 | /// `Bundle.foreign_types`. 117 | 5. type_index: u32 118 | 119 | /// Known attributes on this field. 120 | 10. attrs: Attrs 121 | message Attrs { 122 | /// If set, this indicates that this field is deprecated; the value 123 | /// of this field is the reason. 124 | 1. deprecated: str 125 | 126 | /// The contents of every `///` comment attached to the field. 127 | 100. docs: repeated str 128 | } 129 | 130 | /// The source code span this field came from, if any. This is an opaque value 131 | /// that can only be interpreted with respect to a particular plugin 132 | /// invocation. 133 | 20. span: u32 134 | } -------------------------------------------------------------------------------- /pzc/src/ir/mod.rs: -------------------------------------------------------------------------------- 1 | //! Intermediate representation for semantic analysis. 2 | 3 | use std::cell::Cell; 4 | use std::cell::RefCell; 5 | use std::collections::HashMap; 6 | use std::fmt; 7 | 8 | use bumpalo::collections::Vec as AVec; 9 | 10 | use pz::proto; 11 | 12 | use crate::syn; 13 | 14 | mod resolve; 15 | mod to_proto; 16 | 17 | pub use resolve::ResolveCtx; 18 | 19 | pub struct Bundle<'ast, 'rcx> { 20 | types: RefCell>>, 21 | } 22 | 23 | impl Bundle<'_, '_> { 24 | pub fn to_proto( 25 | &self, 26 | icx: &ilex::Context, 27 | ) -> (proto::Bundle, HashMap) { 28 | to_proto::to_proto(self, icx) 29 | } 30 | } 31 | 32 | #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] 33 | pub struct TypeName<'rcx> { 34 | pub package: &'rcx str, 35 | pub name: &'rcx str, 36 | } 37 | 38 | impl fmt::Display for TypeName<'_> { 39 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 40 | if self.package.is_empty() { 41 | f.write_str(self.name) 42 | } else { 43 | write!(f, "{}.{}", self.package, self.name) 44 | } 45 | } 46 | } 47 | 48 | pub struct Type<'ast, 'rcx> { 49 | name: Cell>, 50 | kind: Cell, 51 | decl: Option<&'ast syn::Decl<'ast>>, 52 | fields: RefCell>>, 53 | nesteds: RefCell>>, 54 | parent: Cell>>, 55 | attrs: proto::r#type::Attrs, 56 | } 57 | 58 | impl<'ast, 'rcx> Type<'ast, 'rcx> { 59 | pub fn name(&self) -> TypeName<'rcx> { 60 | self.name.get() 61 | } 62 | 63 | pub fn kind(&self) -> syn::DeclKind { 64 | self.kind.get() 65 | } 66 | 67 | pub fn decl(&self) -> Option<&'ast syn::Decl<'ast>> { 68 | self.decl 69 | } 70 | 71 | pub fn parent(&self) -> Option<&'rcx Type<'ast, 'rcx>> { 72 | self.parent.get() 73 | } 74 | 75 | pub fn field( 76 | &self, 77 | index: usize, 78 | body: impl FnOnce(&Field<'ast, 'rcx>) -> R, 79 | ) -> Option { 80 | self.fields.borrow().get(index).map(body) 81 | } 82 | 83 | pub fn fields(&self, body: impl FnOnce(&[Field<'ast, 'rcx>]) -> R) -> R { 84 | body(&self.fields.borrow()) 85 | } 86 | 87 | pub fn nested( 88 | &self, 89 | index: usize, 90 | body: impl FnOnce(&'rcx Type<'ast, 'rcx>) -> R, 91 | ) -> Option { 92 | self.nesteds.borrow().get(index).map(|x| body(x)) 93 | } 94 | 95 | pub fn nesteds( 96 | &self, 97 | body: impl FnOnce(&[&'rcx Type<'ast, 'rcx>]) -> R, 98 | ) -> R { 99 | body(&self.nesteds.borrow()) 100 | } 101 | } 102 | 103 | pub struct Field<'ast, 'rcx> { 104 | name: Cell<&'rcx str>, 105 | parent: &'rcx Type<'ast, 'rcx>, 106 | 107 | decl: Option<&'ast syn::Field<'ast>>, 108 | ty: Cell>>, 109 | number: Cell>, 110 | attrs: proto::field::Attrs, 111 | } 112 | 113 | impl<'ast, 'rcx> Field<'ast, 'rcx> { 114 | pub fn name(&self) -> &'rcx str { 115 | self.name.get() 116 | } 117 | 118 | pub fn decl(&self) -> Option<&'ast syn::Field<'ast>> { 119 | self.decl 120 | } 121 | 122 | pub fn ty(&self) -> Option> { 123 | self.ty.get() 124 | } 125 | 126 | pub fn number(&self) -> Option { 127 | self.number.get() 128 | } 129 | 130 | pub fn parent(&self) -> &'rcx Type<'ast, 'rcx> { 131 | self.parent 132 | } 133 | } 134 | 135 | #[derive(Copy, Clone)] 136 | pub struct FieldType<'ast, 'rcx> { 137 | is_repeated: bool, 138 | kind: FieldTypeKind<'ast, 'rcx>, 139 | } 140 | 141 | impl<'ast, 'rcx> FieldType<'ast, 'rcx> { 142 | pub fn is_repeated(&self) -> bool { 143 | self.is_repeated 144 | } 145 | 146 | pub fn kind(&self) -> FieldTypeKind<'ast, 'rcx> { 147 | self.kind 148 | } 149 | } 150 | 151 | #[derive(Copy, Clone)] 152 | pub enum FieldTypeKind<'ast, 'rcx> { 153 | I32, 154 | U32, 155 | F32, 156 | I64, 157 | U64, 158 | F64, 159 | Bool, 160 | String, 161 | Type(&'rcx Type<'ast, 'rcx>), 162 | } 163 | -------------------------------------------------------------------------------- /rust/src/reflect/tuple.rs: -------------------------------------------------------------------------------- 1 | //! Implementations of reflection traits for tuples. 2 | 3 | #![allow(non_snake_case)] 4 | 5 | use crate::reflect::Message; 6 | use crate::reflect::Mut; 7 | use crate::reflect::MutView; 8 | use crate::reflect::Ref; 9 | use crate::reflect::RefView; 10 | use crate::reflect::Selector; 11 | use crate::reflect::Views; 12 | use crate::seal::Seal; 13 | use crate::seal::Sealed; 14 | 15 | /// Bitmasks used for calculating disjointness. 16 | #[derive(Clone, Copy)] 17 | pub struct Mask { 18 | disjoint: bool, 19 | bits: [u128; 256], 20 | } 21 | 22 | impl Mask { 23 | /// Creates a new empty mask. 24 | pub(crate) const fn empty() -> Mask { 25 | Mask { 26 | disjoint: true, 27 | bits: [0; 256], 28 | } 29 | } 30 | 31 | /// Creates a new mask with a single bit set. 32 | pub(crate) const fn single(idx: usize) -> Mask { 33 | let mut new = Self::empty(); 34 | new.bits[idx / 128] |= 1 << (idx % 128); 35 | new 36 | } 37 | 38 | /// Merges two masks. 39 | pub(crate) const fn merge(masks: &[&Mask]) -> Mask { 40 | if masks.is_empty() { 41 | return Mask::empty(); 42 | } 43 | 44 | let mut new = *masks[0]; 45 | let mut i = 1; 46 | while i < masks.len() { 47 | let next = masks[i]; 48 | new.disjoint &= next.disjoint; 49 | 50 | let mut j = 0; 51 | while j < new.bits.len() { 52 | let a = new.bits[i]; 53 | let b = next.bits[i]; 54 | 55 | new.disjoint &= (a & b) == 0; 56 | new.bits[i] = a | b; 57 | 58 | j += 1; 59 | } 60 | 61 | i += 1; 62 | } 63 | 64 | new 65 | } 66 | } 67 | 68 | impl Views for () { 69 | type Ref<'a> = (); 70 | type Mut<'a> = (); 71 | } 72 | impl RefView<'_> for () { 73 | type Target = (); 74 | fn as_ref(&self) {} 75 | } 76 | impl MutView<'_> for () { 77 | type Target = (); 78 | fn as_ref(&self) {} 79 | fn into_ref(self) {} 80 | fn as_mut(&mut self) {} 81 | } 82 | 83 | impl Selector for () { 84 | type Type = (); 85 | const DISJOINT: bool = true; 86 | const __M: Mask = Mask::empty(); 87 | 88 | fn get(_: Ref) -> Ref<()> {} 89 | unsafe fn get_mut_unchecked<'a>( 90 | _: impl Sealed, 91 | _: &mut Mut, 92 | ) -> Mut<'a, ()> { 93 | } 94 | } 95 | 96 | macro_rules! tuples { 97 | ($($($T:ident),*;)*) => {$( 98 | impl<$($T: Views,)*> Views for ($($T,)*) { 99 | type Ref<'a> = ($(Ref<'a, $T>,)*); 100 | type Mut<'a> = ($(Mut<'a, $T>,)*); 101 | } 102 | impl<'a, $($T: RefView<'a>,)*> RefView<'a> for ($($T,)*) { 103 | type Target = ($($T::Target,)*); 104 | fn as_ref(&self) -> Ref { 105 | let ($($T,)*) = self; 106 | ($($T.as_ref(),)*) 107 | } 108 | } 109 | impl<'a, $($T: MutView<'a>,)*> MutView<'a> for ($($T,)*) { 110 | type Target = ($($T::Target,)*); 111 | fn as_ref(&self) -> Ref { 112 | let ($($T,)*) = self; 113 | ($($T.as_ref(),)*) 114 | } 115 | fn into_ref(self) -> Ref<'a, Self::Target> { 116 | let ($($T,)*) = self; 117 | ($($T.into_ref(),)*) 118 | } 119 | 120 | fn as_mut(&mut self) -> Mut { 121 | let ($($T,)*) = self; 122 | ($($T.as_mut(),)*) 123 | } 124 | } 125 | 126 | impl,)*> Selector for ($($T,)*) { 127 | type Type = ($($T::Type,)*); 128 | 129 | const DISJOINT: bool = Self::__M.disjoint; 130 | const __M: Mask = Mask::merge(&[$(&$T::__M,)*]); 131 | 132 | fn get(message: Ref) -> Ref { 133 | ($($T::get(message),)*) 134 | } 135 | 136 | #[doc(hidden)] 137 | unsafe fn get_mut_unchecked<'a>( 138 | _: impl Sealed, 139 | message: &mut Mut, 140 | ) -> Mut<'a, Self::Type> { 141 | ($($T::get_mut_unchecked(Seal, message),)*) 142 | } 143 | } 144 | )*}; 145 | } 146 | 147 | tuples! { 148 | T0; 149 | T0, T1; 150 | T0, T1, T2; 151 | T0, T1, T2, T3; 152 | T0, T1, T2, T3, T4; 153 | T0, T1, T2, T3, T4, T5; 154 | T0, T1, T2, T3, T4, T5, T6; 155 | T0, T1, T2, T3, T4, T5, T6, T7; 156 | T0, T1, T2, T3, T4, T5, T6, T7, T8; 157 | T0, T1, T2, T3, T4, T5, T6, T7, T8, T9; 158 | T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10; 159 | T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11; 160 | } 161 | -------------------------------------------------------------------------------- /pzc/src/ir/to_proto.rs: -------------------------------------------------------------------------------- 1 | //! Serializes an IR bundle into a proto. 2 | 3 | use std::collections::HashMap; 4 | 5 | use ilex::Spanned; 6 | use pz::proto; 7 | 8 | use crate::ir; 9 | use crate::syn; 10 | 11 | pub fn to_proto( 12 | bundle: &ir::Bundle, 13 | icx: &ilex::Context, 14 | ) -> (proto::Bundle, HashMap) { 15 | let mut num2span = HashMap::new(); 16 | let mut counter = 0; 17 | 18 | let mut proto = proto::Bundle::default(); 19 | 20 | let mut pkg_to_idx = HashMap::new(); 21 | let mut ty_to_idx = HashMap::new(); 22 | let mut foreign_to_idx = HashMap::new(); 23 | 24 | // First, materialize all of the types in the type array. 25 | for (i, &ty) in bundle.types.borrow().iter().enumerate() { 26 | ty_to_idx.insert(ty as *const ir::Type, i); 27 | 28 | let &mut pkg = pkg_to_idx.entry(ty.name().package).or_insert_with(|| { 29 | proto.packages.push(ty.name().package.to_string()); 30 | proto.packages.len() - 1 31 | }); 32 | 33 | proto.types.push(proto::Type { 34 | name: Some(ty.name().name.to_string()), 35 | package: Some(pkg as u32), 36 | kind: match ty.kind() { 37 | syn::DeclKind::Message => Some(proto::r#type::Kind::Message as i32), 38 | syn::DeclKind::Struct => Some(proto::r#type::Kind::Struct as i32), 39 | syn::DeclKind::Choice => Some(proto::r#type::Kind::Choice as i32), 40 | syn::DeclKind::Enum => Some(proto::r#type::Kind::Enum as i32), 41 | }, 42 | span: Some(0), 43 | attrs: Some(ty.attrs.clone()), 44 | 45 | ..Default::default() 46 | }); 47 | } 48 | 49 | // Now, resolve fields and parent relations. 50 | for (&ty, proto_ty) in bundle.types.borrow().iter().zip(&mut proto.types) { 51 | if let Some(parent) = ty.parent() { 52 | proto_ty.declared_in = 53 | Some(ty_to_idx[&(parent as *const ir::Type)] as u32); 54 | } 55 | 56 | ty.nesteds(|tys| { 57 | for &ty in tys { 58 | proto_ty 59 | .nesteds 60 | .push(ty_to_idx[&(ty as *const ir::Type)] as u32) 61 | } 62 | }); 63 | 64 | ty.fields(|fs| { 65 | for field in fs { 66 | let kind = field.ty().map(|t| match t.kind { 67 | ir::FieldTypeKind::I32 => proto::field::Type::I32, 68 | ir::FieldTypeKind::U32 => proto::field::Type::U32, 69 | ir::FieldTypeKind::F32 => proto::field::Type::F32, 70 | ir::FieldTypeKind::I64 => proto::field::Type::I64, 71 | ir::FieldTypeKind::U64 => proto::field::Type::U64, 72 | ir::FieldTypeKind::F64 => proto::field::Type::F64, 73 | ir::FieldTypeKind::Bool => proto::field::Type::Bool, 74 | ir::FieldTypeKind::String => proto::field::Type::String, 75 | ir::FieldTypeKind::Type(ty) if ty.decl().is_some() => { 76 | proto::field::Type::Type 77 | } 78 | ir::FieldTypeKind::Type(..) => proto::field::Type::Foreign, 79 | } as i32); 80 | 81 | let type_index = field.ty().and_then(|t| match t.kind { 82 | ir::FieldTypeKind::Type(ty) if ty.decl().is_some() => { 83 | Some(ty_to_idx[&(ty as *const ir::Type)] as u32) 84 | } 85 | ir::FieldTypeKind::Type(ty) => { 86 | let &mut pkg = 87 | pkg_to_idx.entry(ty.name().package).or_insert_with(|| { 88 | proto.packages.push(ty.name().package.to_string()); 89 | proto.packages.len() - 1 90 | }); 91 | 92 | let &mut idx = 93 | foreign_to_idx.entry(ty.name()).or_insert_with(|| { 94 | proto.foreign_types.push(proto::bundle::ForeignType { 95 | name: Some(ty.name().name.to_string()), 96 | package: Some(pkg as u32), 97 | }); 98 | proto.foreign_types.len() - 1 99 | }); 100 | Some(idx as u32) 101 | } 102 | _ => None, 103 | }); 104 | 105 | proto_ty.fields.push(proto::Field { 106 | name: Some(field.name().to_string()), 107 | number: field.number(), 108 | is_repeated: field.ty().map(|t| t.is_repeated()), 109 | r#type: kind, 110 | type_index, 111 | span: field.decl().map(|f| { 112 | let next = counter; 113 | counter += 1; 114 | num2span.insert(next, f.span(icx)); 115 | next 116 | }), 117 | attrs: Some(field.attrs.clone()), 118 | }) 119 | } 120 | }); 121 | } 122 | 123 | (proto, num2span) 124 | } 125 | -------------------------------------------------------------------------------- /rust/src/proto/plugin.pz: -------------------------------------------------------------------------------- 1 | @edition = "2023" 2 | package pz.plugin 3 | 4 | import pz { Bundle } 5 | 6 | /// A request to a plugin. 7 | /// 8 | /// When a plugin is executed, a message of this type is sent to it over stdin. 9 | choice Request { 10 | 1. about: AboutRequest 11 | 2. codegen: CodegenRequest 12 | } 13 | 14 | /// A response from a plugin. 15 | /// 16 | /// When a plugin is executed, the plugin driver expects a message of this type 17 | /// to be written to stdout. 18 | choice Response { 19 | 1. about: AboutResponse 20 | 2. codegen: CodegenResponse 21 | } 22 | 23 | /// The preflight negotiation request, used to learn information about the 24 | /// plugin. 25 | message AboutRequest {} 26 | 27 | /// The negotiation response, which allows a plugin to describe itself. 28 | message AboutResponse { 29 | /// The name of this plugin. This is only used for identification purposes. 30 | 1. name: str 31 | /// The version of this plugin. This is shown to users. 32 | 2. version: str 33 | 34 | /// Command-line options that the plugin understands. 35 | 10. options: repeated Option 36 | message Option { 37 | /// The name of the option. This is added to the CLI flags the parser can 38 | /// parse, namespaced under this plugin. For example, if the plugin "foo" 39 | /// has an option named "bar", it is set at the command line as `--foo.bar`. 40 | 1. name: str 41 | 42 | /// Help text for this option to show on the command line. 43 | 2. help: str 44 | } 45 | } 46 | 47 | /// A code generation request sent to a plugin. 48 | message CodegenRequest { 49 | /// A bundle containing all of the relevant definitions for this request. 50 | /// 51 | /// By construction, this bundle will not contain any foreign references. 52 | 1. bundle: Bundle 53 | 54 | /// A list of indices into `bundle.types` that refer to types that 55 | /// should be code-generated. 56 | 2. requested_indices: repeated u32 57 | 58 | /// Command line options passed into the compiler, which were requested in 59 | /// the `AboutResponse`. 60 | /// 61 | /// Options requested in `AboutResponse` will not be present if they were not 62 | /// explicitly passed on the command line. 63 | 3. options: repeated Option 64 | message Option { 65 | /// The name of the option, as specified in `AboutResponse.options`. 66 | 1. name: str 67 | /// The value of the option. 68 | 2. value: str 69 | } 70 | 71 | /// Whether to run the plugin in "debug mode". 72 | 4. debug: bool 73 | } 74 | 75 | /// A code generation response from a plugin. 76 | message CodegenResponse { 77 | /// The output of code generation as a list of files. 78 | /// 79 | /// The driver will output these files relative to the output directory. 80 | 1. files: repeated File 81 | message File { 82 | 1. path: str 83 | 2. content: str 84 | } 85 | 86 | /// Diagnostics that the driver should render. 87 | 2. report: repeated Diagnostic 88 | } 89 | 90 | /// A diagnostic, essentially a structured log line from the plugin. 91 | message Diagnostic { 92 | /// The kind of diagnostic this is. 93 | 1. kind: Kind 94 | enum Kind { 95 | /// Something went wrong and we couldn't generate code correctly. 96 | 0. ERROR 97 | 98 | /// Something looked bad, but code generation succeeded. 99 | 1. WARNING 100 | } 101 | 102 | /// A message to display to the user. 103 | /// 104 | /// The rendering framework prefers this to be a single declarative sentence 105 | /// that is not capitalized and has no ending period. 106 | 2. msg: str 107 | 108 | /// A list of snippets of input source code that are relevant to the 109 | /// diagnostic. 110 | 3. snippets: repeated Snippet 111 | message Snippet { 112 | /// An ID refering to a location in the input. Messages in `pz.pz` may 113 | /// contain a span that can be used to refer to the corresponding syntactic 114 | /// structure in a snippet. There is no way to turn a span into line and 115 | /// column information directly; this is done by the driver. 116 | 1. span: u32 117 | 118 | /// An optional message to display in the snippet (e.g. next to the 119 | /// underline portion of the code). 120 | /// 121 | /// It should be in the same style as Diagnostic.message. 122 | 2. #message: str 123 | 124 | /// Whether this is a "remark", which is additional information related to 125 | /// a problem that isn't the direct cause. This is rendered slightly 126 | /// differently. 127 | 3. is_remark: bool 128 | } 129 | 130 | /// A list of notes to append at the end of the diagnostic after the snippets. 131 | /// 132 | /// They should be in the same style as Diagnostic.message. 133 | 4. notes: repeated str 134 | } -------------------------------------------------------------------------------- /rust/src/arena.rs: -------------------------------------------------------------------------------- 1 | //! Arena support. 2 | 3 | #![allow(clippy::missing_safety_doc)] 4 | 5 | use std::alloc::Layout; 6 | use std::ptr; 7 | use std::ptr::NonNull; 8 | use std::slice; 9 | 10 | use crate::tdp::Opaque; 11 | 12 | #[derive(Copy, Clone)] 13 | pub struct RawArena { 14 | bump: NonNull, 15 | } 16 | 17 | impl RawArena { 18 | #[allow(clippy::new_without_default)] 19 | pub fn new() -> Self { 20 | unsafe { 21 | Self { 22 | bump: NonNull::new_unchecked(Box::leak(Box::new(bumpalo::Bump::new()))), 23 | } 24 | } 25 | } 26 | 27 | pub fn alloc(&self, layout: Layout) -> NonNull { 28 | unsafe { self.bump.as_ref() }.alloc_layout(layout) 29 | } 30 | 31 | pub unsafe fn destroy(&self) { 32 | let _ = Box::from_raw(self.bump.as_ptr()); 33 | } 34 | } 35 | 36 | #[repr(C)] 37 | pub struct AVec { 38 | // This is intentionally the first value, so that in Hazzer we can specify 39 | // "clear the first eight bytes" to clear a repeated field without trashing 40 | // its internal pointer. 41 | len: usize, 42 | 43 | // Option so that all-zeros is a valid representation. 44 | ptr: Option>, 45 | cap: usize, 46 | } 47 | 48 | // This type is Copy so we can put it inside of a union; it has no destructor. 49 | impl Copy for AVec {} 50 | impl Clone for AVec { 51 | fn clone(&self) -> Self { 52 | *self 53 | } 54 | } 55 | 56 | impl Default for AVec { 57 | fn default() -> Self { 58 | Self::new() 59 | } 60 | } 61 | 62 | impl AVec { 63 | pub const fn new() -> AVec { 64 | Self { 65 | ptr: None, 66 | cap: 0, 67 | len: 0, 68 | } 69 | } 70 | 71 | pub fn as_ptr(&self) -> Option> { 72 | self.ptr 73 | } 74 | 75 | pub fn as_raw_ptr(&self) -> *mut T { 76 | self.ptr.map(NonNull::as_ptr).unwrap_or(ptr::null_mut()) 77 | } 78 | 79 | #[allow(clippy::len_without_is_empty)] 80 | pub fn len(&self) -> usize { 81 | self.len 82 | } 83 | 84 | pub fn cap(&self) -> usize { 85 | self.cap 86 | } 87 | 88 | pub unsafe fn set_len(&mut self, len: usize) { 89 | debug_assert!(self.cap >= len); 90 | self.len = len 91 | } 92 | 93 | pub unsafe fn as_slice(&self) -> &[T] { 94 | slice::from_raw_parts( 95 | self.as_ptr().unwrap_or(NonNull::dangling()).as_ptr(), 96 | self.len, 97 | ) 98 | } 99 | 100 | pub unsafe fn as_mut_slice(&mut self) -> &mut [T] { 101 | slice::from_raw_parts_mut( 102 | self.as_ptr().unwrap_or(NonNull::dangling()).as_ptr(), 103 | self.len, 104 | ) 105 | } 106 | 107 | pub fn add(&mut self, arena: RawArena) -> &mut T { 108 | self.resize(self.len() + 1, arena); 109 | unsafe { self.as_mut_slice().last_mut().unwrap_unchecked() } 110 | } 111 | 112 | pub fn push(&mut self, value: T, arena: RawArena) { 113 | *self.add(arena) = value; 114 | } 115 | 116 | pub fn resize(&mut self, new_len: usize, arena: RawArena) { 117 | if new_len > self.cap { 118 | let cap = if new_len.is_power_of_two() { 119 | new_len 120 | } else { 121 | new_len.checked_next_power_of_two().unwrap() 122 | }; 123 | 124 | self.grow(Some(cap), arena); 125 | } 126 | unsafe { 127 | self.set_len(new_len); 128 | } 129 | } 130 | 131 | pub fn grow(&mut self, new_cap: Option, arena: RawArena) { 132 | let old_cap = self.cap; 133 | self.cap = new_cap.unwrap_or(self.cap * 2).max(self.cap * 2); 134 | if self.cap < 16 { 135 | self.cap = 16; 136 | } 137 | 138 | let new_ptr = arena 139 | .alloc(Layout::array::(self.cap).unwrap()) 140 | .cast::(); 141 | 142 | unsafe { 143 | if let Some(old_ptr) = self.as_ptr() { 144 | new_ptr.copy_from_nonoverlapping(old_ptr, old_cap); 145 | } 146 | new_ptr.add(old_cap).write_bytes(0, self.cap - old_cap); 147 | } 148 | 149 | self.ptr = Some(new_ptr); 150 | } 151 | } 152 | 153 | impl AVec> { 154 | pub fn resize_msg( 155 | &mut self, 156 | new_len: usize, 157 | arena: RawArena, 158 | layout: Layout, 159 | ) { 160 | if new_len > self.cap { 161 | let cap = if new_len.is_power_of_two() { 162 | new_len 163 | } else { 164 | new_len.checked_next_power_of_two().unwrap() 165 | }; 166 | 167 | self.grow(Some(cap), arena); 168 | } 169 | 170 | while self.len < new_len { 171 | unsafe { 172 | let ptr = self.as_ptr().unwrap().add(self.len).as_mut(); 173 | if ptr.is_none() { 174 | *ptr = Some(arena.alloc(layout)); 175 | } 176 | dbg!(ptr.unwrap_unchecked()).write_bytes(0, layout.size()); 177 | } 178 | 179 | self.len += 1; 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /pzc/tests/frontend.rs: -------------------------------------------------------------------------------- 1 | //! Integration tests for the frontend, which consist of executing the pz 2 | //! compiler as a subprocess. 3 | 4 | use std::env; 5 | use std::fs; 6 | use std::path::PathBuf; 7 | use std::process; 8 | use std::process::Command; 9 | use std::sync::atomic::AtomicU32; 10 | 11 | use pz::proto::z::Bundle; 12 | use pz::Codec; 13 | 14 | #[test] 15 | fn empty_file() { 16 | let output = run_pz( 17 | &[( 18 | "test.pz", 19 | &text( 20 | " 21 | @edition = 2023 22 | package test 23 | ", 24 | ), 25 | )], 26 | &["test.pz"], 27 | ); 28 | 29 | assert_eq!(output.exit_code, 0); 30 | let bundle = 31 | dbg!( 32 | Bundle::parse(Codec::Protobuf, &mut output.bundle.as_slice()).unwrap() 33 | ); 34 | assert!(bundle.types().is_empty()); 35 | } 36 | 37 | #[test] 38 | fn intra_dependency() { 39 | let output = run_pz( 40 | &[ 41 | ( 42 | "dep.pz", 43 | &text( 44 | " 45 | @edition = 2023 46 | package test.dep 47 | 48 | message Foo {} 49 | ", 50 | ), 51 | ), 52 | ( 53 | "test.pz", 54 | &text( 55 | " 56 | @edition = 2023 57 | package test 58 | 59 | import test.dep { Foo as Rename } 60 | 61 | message Bar { 62 | 1. foo1: Rename 63 | 2. foo2: test.dep.Foo 64 | } 65 | ", 66 | ), 67 | ), 68 | ], 69 | &["test.pz", "dep.pz"], 70 | ); 71 | 72 | assert_eq!(output.exit_code, 0); 73 | let bundle = 74 | dbg!( 75 | Bundle::parse(Codec::Protobuf, &mut output.bundle.as_slice()).unwrap() 76 | ); 77 | assert_eq!(bundle.types_at(0).name(), "Bar"); 78 | assert_eq!(bundle.types_at(1).name(), "Foo"); 79 | } 80 | 81 | #[test] 82 | fn extra_dependency() { 83 | let output = run_pz( 84 | &[( 85 | "dep.pz", 86 | &text( 87 | " 88 | @edition = 2023 89 | package test.dep 90 | 91 | message Foo {} 92 | ", 93 | ), 94 | )], 95 | &["dep.pz"], 96 | ); 97 | assert_eq!(output.exit_code, 0); 98 | 99 | let output = run_pz( 100 | &[ 101 | ("dep.pb", &output.bundle), 102 | ( 103 | "test.pz", 104 | &text( 105 | " 106 | @edition = 2023 107 | package test 108 | 109 | import test.dep { Foo as Rename } 110 | 111 | message Bar { 112 | 1. foo1: Rename 113 | 2. foo2: test.dep.Foo 114 | } 115 | ", 116 | ), 117 | ), 118 | ], 119 | &["--extern=dep.pb", "test.pz"], 120 | ); 121 | 122 | assert_eq!(output.exit_code, 0); 123 | let bundle = 124 | dbg!( 125 | Bundle::parse(Codec::Protobuf, &mut output.bundle.as_slice()).unwrap() 126 | ); 127 | assert_eq!(bundle.types_at(0).name(), "Bar"); 128 | } 129 | 130 | #[allow(unused)] 131 | struct PzExit { 132 | bundle: Vec, 133 | stderr: String, 134 | exit_code: i32, 135 | } 136 | 137 | fn text(lit: &str) -> Vec { 138 | unindent::unindent(lit).to_string().into() 139 | } 140 | 141 | fn run_pz(filesystem: &[(&str, &[u8])], cli: &[&str]) -> PzExit { 142 | static RUN_COUNT: AtomicU32 = AtomicU32::new(0); 143 | let tmpdir = PathBuf::from(format!( 144 | "/tmp/pz.frontend.{}.{}", 145 | process::id(), 146 | RUN_COUNT.fetch_add(1, std::sync::atomic::Ordering::SeqCst) 147 | )); 148 | 149 | struct Erase(PathBuf); 150 | impl Drop for Erase { 151 | fn drop(&mut self) { 152 | fs::remove_dir_all(&self.0).unwrap(); 153 | } 154 | } 155 | let _erase = Erase(tmpdir.clone()); 156 | 157 | for (name, contents) in filesystem { 158 | let path = tmpdir.join(name); 159 | fs::create_dir_all(path.parent().unwrap()).unwrap(); 160 | fs::write(path, contents).unwrap() 161 | } 162 | 163 | let mut exe = env::current_exe().unwrap(); 164 | exe.pop(); 165 | if exe.ends_with("deps") { 166 | exe.pop(); 167 | } 168 | exe.push("pzc"); 169 | 170 | let output = dbg!(Command::new(exe) 171 | .arg("--plugin=bundle") 172 | .arg("--output-dir") 173 | .arg(&tmpdir) 174 | .arg("--bundle.out=bundle.pb") 175 | .args(cli) 176 | .current_dir(&tmpdir)) 177 | .output() 178 | .unwrap(); 179 | 180 | let stderr = String::from_utf8(output.stderr).unwrap(); 181 | if !output.status.success() { 182 | eprintln!("{stderr}"); 183 | return PzExit { 184 | bundle: Vec::new(), 185 | stderr, 186 | exit_code: output.status.code().unwrap_or(-1), 187 | }; 188 | } 189 | 190 | PzExit { 191 | bundle: fs::read(tmpdir.join("bundle.pb")).unwrap(), 192 | stderr, 193 | exit_code: 0, 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /rust/src/opt.rs: -------------------------------------------------------------------------------- 1 | //! Wrappers for field values. 2 | 3 | use std::marker::PhantomData; 4 | 5 | use crate::arena::RawArena; 6 | use crate::reflect::Mut; 7 | use crate::reflect::MutView; 8 | use crate::reflect::Opt; 9 | use crate::reflect::Ref; 10 | use crate::reflect::Set; 11 | use crate::reflect::Type; 12 | use crate::seal::Seal; 13 | use crate::tdp; 14 | use crate::tdp::Opaque; 15 | 16 | /// A mutator for optional (singular) fields. 17 | /// 18 | /// An `OptMut` is essentially an `&mut Option>`, but with a more 19 | /// flexible layout. For example, the "has bits" of all of the fields in a 20 | /// `message` are stacked into single bits at the top of the message; the 21 | /// "which word" for a `choice` determines which variant is engaged. In both 22 | /// cases, the layout of the difference between `Some` and `None` is 23 | /// specialized, so instead of an `&mut Option`, we must provide a wrapper. 24 | pub struct OptMut<'a, T: Type> { 25 | ptr: Opaque, 26 | arena: RawArena, 27 | field: tdp::Field, 28 | _ph: PhantomData<&'a mut T>, 29 | } 30 | 31 | impl<'a, T: Type> OptMut<'a, T> { 32 | /// Returns whether this value is unset. 33 | pub fn is_none(&self) -> bool { 34 | !self.is_some() 35 | } 36 | 37 | /// Returns whether this value is present. 38 | pub fn is_some(&self) -> bool { 39 | unsafe { self.field.has(self.ptr) } 40 | } 41 | 42 | /// Clears the field. 43 | #[inline(always)] 44 | pub fn clear(&mut self) { 45 | unsafe { self.field.clear(self.ptr) } 46 | } 47 | 48 | /// Converts this mutator into a view, returning a view of the default value 49 | /// if the view it isn't present. 50 | #[track_caller] 51 | pub fn unwrap(&self) -> Ref { 52 | // TODO: default? 53 | self.as_ref().unwrap() 54 | } 55 | 56 | /// Converts this mutator into a view, returning a view of the default value 57 | /// if the view it isn't present. 58 | /// 59 | /// This version consumes the mutator to make the returned view's lifetime as 60 | /// long as possible. 61 | #[track_caller] 62 | pub fn into_unwrap(self) -> Ref<'a, T> { 63 | self.into_ref().unwrap() 64 | } 65 | 66 | /// Converts this mutator into a mutator of the underlying type, initializing 67 | /// the field if it isn't already 68 | pub fn as_inner(&mut self) -> Mut { 69 | self.as_mut().into_inner() 70 | } 71 | 72 | /// Converts this mutator into a mutator of the underlying type, initializing 73 | /// the field if it isn't already. 74 | /// 75 | /// This version consumes the mutator to make the returned mutator's lifetime 76 | /// as long as possible. 77 | pub fn into_inner(mut self) -> Mut<'a, T> { 78 | unsafe { 79 | self.field.init(self.ptr, self.arena); 80 | self.__mut() 81 | } 82 | } 83 | 84 | /// Converts this mutator into a mutator of the underlying type, or returns 85 | /// `None` if it isn't present. 86 | pub fn as_option(&mut self) -> Option> { 87 | self.as_mut().into_option() 88 | } 89 | 90 | /// Converts this mutator into a mutator of the underlying type, or returns 91 | /// `None` if it isn't present. 92 | /// 93 | /// This version consumes the mutator to make the returned mutator's lifetime 94 | /// as long as possible. 95 | pub fn into_option(mut self) -> Option> { 96 | if !self.is_some() { 97 | return None; 98 | } 99 | unsafe { Some(self.__mut()) } 100 | } 101 | } 102 | 103 | impl<'a, T: Type> MutView<'a> for OptMut<'a, T> { 104 | type Target = Opt; 105 | 106 | fn as_ref(&self) -> Ref { 107 | if self.is_none() { 108 | return None; 109 | } 110 | Some(unsafe { self.__ref() }) 111 | } 112 | 113 | fn into_ref(self) -> Ref<'a, Self::Target> { 114 | if self.is_none() { 115 | return None; 116 | } 117 | Some(unsafe { self.__ref() }) 118 | } 119 | 120 | fn as_mut(&mut self) -> Mut { 121 | OptMut { 122 | ptr: self.ptr, 123 | arena: self.arena, 124 | field: self.field, 125 | _ph: PhantomData, 126 | } 127 | } 128 | } 129 | 130 | impl OptMut<'_, T> { 131 | /// Wraps a pointer to a message type, its arena, and a field to make an 132 | /// `OptMut`. 133 | pub(crate) unsafe fn new( 134 | ptr: Opaque, 135 | arena: RawArena, 136 | field: tdp::Field, 137 | ) -> Self { 138 | Self { 139 | ptr, 140 | arena, 141 | field, 142 | _ph: PhantomData, 143 | } 144 | } 145 | 146 | #[inline(always)] 147 | unsafe fn __ref<'b>(&self) -> Ref<'b, T> { 148 | unsafe { T::__ref(Seal, self.field.cast(self.ptr)) } 149 | } 150 | 151 | #[inline(always)] 152 | unsafe fn __mut<'b>(&mut self) -> Mut<'b, T> { 153 | unsafe { T::__mut(Seal, self.field.cast(self.ptr), self.arena) } 154 | } 155 | } 156 | 157 | impl> Set> for Option { 158 | fn apply_to(self, mut m: Mut>) { 159 | let Some(value) = self else { 160 | m.clear(); 161 | return; 162 | }; 163 | 164 | value.apply_to(m.into_inner()) 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /rust/src/macros.rs: -------------------------------------------------------------------------------- 1 | //! This file defines the `proto!` macro. 2 | //! 3 | //! The way the macro itself works is it generates a complicated type that 4 | //! records all of the keys and values pushed into it, resulting in something 5 | //! that can be `.into()`'d into the appropriate proto type. 6 | 7 | use crate::reflect::Field; 8 | use crate::reflect::MutView; 9 | use crate::reflect::Name; 10 | use crate::reflect::Rep; 11 | use crate::reflect::Selector; 12 | use crate::reflect::Set; 13 | use crate::Mut; 14 | use crate::Type; 15 | 16 | /// The no-op command. This is the root of our settings command chain. 17 | pub struct Nop; 18 | impl Set for Nop { 19 | #[inline(always)] 20 | fn apply_to(self, _: Mut) {} 21 | } 22 | 23 | /// A key-value command. This sets a single singular or repeated value. 24 | pub struct Kv(pub Prev, pub Name, pub Value); 25 | impl Set for Kv 26 | where 27 | M: Field, 28 | N: Name, 29 | V: Set, 30 | P: Set, 31 | { 32 | #[inline(always)] 33 | fn apply_to(self, mut m: Mut) { 34 | self.0.apply_to(m.as_mut()); 35 | self.2.apply_to(>::get_mut(m)); 36 | } 37 | } 38 | 39 | /// A reserve command. This reserves space in a repeated field for a followup 40 | /// set of push entries. 41 | pub struct Reserve(pub Prev, pub Name, pub usize); 42 | impl Set for Reserve 43 | where 44 | M: Field>, 45 | N: Name, 46 | T: Type, 47 | P: Set, 48 | { 49 | #[inline(always)] 50 | fn apply_to(self, mut m: Mut) { 51 | self.0.apply_to(m.as_mut()); 52 | let mut repeated = >::get_mut(m); 53 | repeated.reserve(self.2); 54 | } 55 | } 56 | 57 | /// A push command. This pushes a value onto a repeated field. 58 | pub struct Push(pub Prev, pub Name, pub Value); 59 | impl Set for Push 60 | where 61 | M: Field>, 62 | N: Name, 63 | V: Set, 64 | T: Type, 65 | P: Set, 66 | { 67 | #[inline(always)] 68 | fn apply_to(self, mut m: Mut) { 69 | self.0.apply_to(m.as_mut()); 70 | >::get_mut(m).push(self.2); 71 | } 72 | } 73 | 74 | /* 75 | // This runs into orphan issues around users implementing Field themselves. 76 | // Which they're not supposed to. Ugh. 77 | impl Set> for Kv 78 | where 79 | Self: Set, 80 | { 81 | fn apply_to(self, m: Mut>) { 82 | self.apply_to(m.into_inner()) 83 | } 84 | } 85 | */ 86 | 87 | /// Constructs a message type using JSON-like syntax. 88 | /// 89 | /// This macro is intended to be used like this: 90 | /// 91 | /// ```rust 92 | /// pz::proto! { 93 | /// foo: 42, 94 | /// bar: "my cool string", 95 | /// sub_message: { name: "Solomon" }, 96 | /// array: [1, 2, 3, 4], 97 | /// } 98 | /// # ; 99 | /// ``` 100 | /// 101 | /// This expands into an expression that is not actually a message, but rather 102 | /// a description of the setters to call on an unknown message type. This value 103 | /// can be passed into `MyMessage::from()`, pushed onto a repeated field, etc, 104 | /// since it will implement [`Set`][Set] if `MyMessage` happens to 105 | /// have all of the fields (and subfields!) specified in the macro call. 106 | #[cfg(doc)] 107 | #[macro_export] 108 | macro_rules! proto { 109 | ($($key:ident: $value:expr),*) => { 110 | compile_error!("for exposition only") 111 | }; 112 | } 113 | 114 | #[cfg(not(doc))] 115 | #[macro_export] 116 | macro_rules! proto { 117 | (@entry $p:expr, $k:ident: {$($v:tt)*} $(, $($tt:tt)*)?) => { 118 | $crate::proto!( 119 | @entry $p, $k: $crate::proto!($($v)*), $($($tt)*)? 120 | ) 121 | }; 122 | (@entry $p:expr, $k:ident: [$($v:tt)*] $(, $($tt:tt)*)?) => {{ 123 | let _k = $crate::field!($k); 124 | $crate::proto!( 125 | @entry $crate::proto!( 126 | @push $crate::__z::macros::Reserve($p, _k, $crate::proto!(@count $($v)*)), 127 | _k: $($v)* 128 | ), $($($tt)*)? 129 | ) 130 | }}; 131 | (@entry $p:expr, $k:ident: $v:expr $(, $($tt:tt)*)?) => { 132 | $crate::proto!( 133 | @entry 134 | $crate::__z::macros::Kv($p, $crate::field!($k), $v), 135 | $($($tt)*)? 136 | ) 137 | }; 138 | (@entry $p:expr,) => { $p }; 139 | 140 | (@push $p:expr, $k:ident: {$($v:tt)*} $(, $($tt:tt)*)?) => { 141 | $crate::proto!( 142 | @push $p, $k: $crate::proto!($($v)*), $($($tt)*)? 143 | ) 144 | }; 145 | (@push $p:expr, $k:ident: $v:expr $(, $($tt:tt)*)?) => { 146 | $crate::proto!( 147 | @push 148 | $crate::__z::macros::Push($p, $k, $v), 149 | $k: $($($tt)*)? 150 | ) 151 | }; 152 | (@push $p:expr, $k:ident:) => { $p }; 153 | 154 | (@count $(,)?) => { 0 }; 155 | (@count , $($tt:tt)*) => { 156 | 1 + $crate::proto!(@count $($tt)*) 157 | }; 158 | (@count $_:tt $($tt:tt)*) => { 159 | 1 + $crate::proto!(@count $($tt)*) 160 | }; 161 | 162 | ($($tt:tt)*) => { 163 | $crate::proto!( 164 | @entry $crate::__z::macros::Nop, $($tt)* 165 | ) 166 | }; 167 | } 168 | -------------------------------------------------------------------------------- /rust/tests/tdp.rs: -------------------------------------------------------------------------------- 1 | #[path = "proto/lib.pz.rs"] 2 | mod proto; 3 | 4 | // Data in this file is generated using Protoscope. 5 | // 6 | // Eventually we'll use a Rust implementation of Protoscope to generate test 7 | // data on-the-fly. 8 | // 9 | // For now, inputs need to be pasted into `protoscope -s | xxd -i`. 10 | 11 | #[test] 12 | fn smoke_message() { 13 | let _protoscope = r#" 14 | 1: 42 15 | 2: 42i32 16 | 4: 200 17 | 3: 600i64 18 | 5: 777.77i32 19 | 6: -inf64 20 | 7: {"a normal-looking string"} 21 | 8: false 22 | 23 | 10: !{ 24 | 7: {"a nasty str\xffing"} 25 | 10: {} 26 | } 27 | 11: { 1: -1 } 28 | 29 | 28: false 30 | 31 | 21: 1 32 | 21: 2 33 | 22: -1i64 34 | 21: 3 35 | 22: -2 36 | 23: 0i32 37 | 24: 1000000 38 | 24: 1000000 39 | 24: 1000000 40 | 23: 1000000 41 | 24: 1000000 42 | 25: inf32 43 | 26: inf64 44 | 25: 42.0i32 45 | 25: -0.0i32 46 | 47 | 27: {"more"} 48 | 27: {"nor\x00mal"} 49 | 27: {"strings?"} 50 | 51 | 28: 2 52 | 28: 1 53 | 54 | 30: { 1: 1 } 55 | 30: !{ 1: 6 } 56 | 30: { 2: 9 } 57 | 31: { 2: {"yet"} 2: {"more"} 2: {"hellropes"} } 58 | "#; 59 | 60 | let data = [ 61 | 0x08, 0x2a, 0x15, 0x2a, 0x00, 0x00, 0x00, 0x20, 0xc8, 0x01, 0x19, 0x58, 62 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x48, 0x71, 0x42, 0x44, 63 | 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x3a, 0x17, 0x61, 64 | 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2d, 0x6c, 0x6f, 0x6f, 0x6b, 65 | 0x69, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x40, 0x00, 66 | 0x53, 0x3a, 0x0f, 0x61, 0x20, 0x6e, 0x61, 0x73, 0x74, 0x79, 0x20, 0x73, 67 | 0x74, 0x72, 0xff, 0x69, 0x6e, 0x67, 0x52, 0x00, 0x54, 0x5a, 0x0b, 0x08, 68 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xe0, 0x01, 69 | 0x00, 0xa8, 0x01, 0x01, 0xa8, 0x01, 0x02, 0xb1, 0x01, 0xff, 0xff, 0xff, 70 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xa8, 0x01, 0x03, 0xb0, 0x01, 0xfe, 0xff, 71 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xbd, 0x01, 0x00, 0x00, 72 | 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x84, 0x3d, 0xc0, 0x01, 0xc0, 0x84, 0x3d, 73 | 0xc0, 0x01, 0xc0, 0x84, 0x3d, 0xb8, 0x01, 0xc0, 0x84, 0x3d, 0xc0, 0x01, 74 | 0xc0, 0x84, 0x3d, 0xcd, 0x01, 0x00, 0x00, 0x80, 0x7f, 0xd1, 0x01, 0x00, 75 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f, 0xcd, 0x01, 0x00, 0x00, 0x28, 76 | 0x42, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x80, 0xda, 0x01, 0x04, 0x6d, 0x6f, 77 | 0x72, 0x65, 0xda, 0x01, 0x07, 0x6e, 0x6f, 0x72, 0x00, 0x6d, 0x61, 0x6c, 78 | 0xda, 0x01, 0x08, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x3f, 0xe0, 79 | 0x01, 0x02, 0xe0, 0x01, 0x01, 0xf2, 0x01, 0x02, 0x08, 0x01, 0xf3, 0x01, 80 | 0x08, 0x06, 0xf4, 0x01, 0xf2, 0x01, 0x02, 0x10, 0x09, 0xfa, 0x01, 0x16, 81 | 0x12, 0x03, 0x79, 0x65, 0x74, 0x12, 0x04, 0x6d, 0x6f, 0x72, 0x65, 0x12, 82 | 0x09, 0x68, 0x65, 0x6c, 0x6c, 0x72, 0x6f, 0x70, 0x65, 0x73, 83 | ]; 84 | 85 | let proto = 86 | dbg!( 87 | proto::test::TestAll::parse(pz::Codec::Protobuf, &mut &data[..]).unwrap() 88 | ); 89 | 90 | assert_eq!(proto.opt_i32(), 42); 91 | assert_eq!(proto.opt_i64(), 42); 92 | assert_eq!(proto.opt_u32(), 600); 93 | assert_eq!(proto.opt_u64(), 200); 94 | assert_eq!(proto.opt_f32(), 777.77); 95 | assert_eq!(proto.opt_f64(), -f64::INFINITY); 96 | assert_eq!(proto.opt_str(), "a normal-looking string"); 97 | assert!(!proto.opt_bool()); 98 | assert_eq!(proto.opt_recursive().opt_str(), b"a nasty str\xffing"); 99 | assert!(proto.opt_recursive().opt_recursive_or().is_some()); 100 | assert_eq!(proto.opt_nested().a(), -1); 101 | assert_eq!(proto.rep_i32(), [1, 2, 3]); 102 | assert_eq!(proto.rep_i64(), [-1, -2]); 103 | assert_eq!(proto.rep_u32(), [0, 1000000]); 104 | assert_eq!(proto.rep_u64(), [1000000; 4]); 105 | assert_eq!(proto.rep_f32(), [f32::INFINITY, 42.0, -0.0]); 106 | assert_eq!(proto.rep_f64(), [f64::INFINITY]); 107 | assert_eq!(proto.rep_bool(), [false, true, true]); 108 | assert_eq!(proto.rep_str(), ["more", "nor\0mal", "strings?"]); 109 | assert_eq!(proto.rep_recursive_at(0).opt_i32(), 1); 110 | assert_eq!(proto.rep_recursive_at(1).opt_i32(), 6); 111 | assert_eq!(proto.rep_recursive_at(2).opt_i64(), 9); 112 | assert_eq!(proto.rep_nested_at(0).b(), ["yet", "more", "hellropes"]); 113 | } 114 | 115 | #[test] 116 | fn smoke_choice() { 117 | let _protoscope = r#" 118 | 1: 42 119 | "#; 120 | 121 | let data = [0x08, 0x2a]; 122 | 123 | let proto = 124 | proto::test::TestAll2::parse(pz::Codec::Protobuf, &mut &data[..]).unwrap(); 125 | 126 | assert_eq!(proto.opt_i32_or(), Some(42)); 127 | assert!(matches!( 128 | proto.cases(), 129 | proto::test::TestAll2Cases::OptI32(42) 130 | )); 131 | 132 | let _protoscope = r#" 133 | 7: {"a normal-looking string"} 134 | 1: 42 135 | 27: {"more"} 136 | 27: {"nor\x00mal"} 137 | 27: {"strings?"} 138 | "#; 139 | 140 | let data = [ 141 | 0x3a, 0x17, 0x61, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2d, 0x6c, 142 | 0x6f, 0x6f, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 143 | 0x67, 0x08, 0x2a, 0xda, 0x01, 0x04, 0x6d, 0x6f, 0x72, 0x65, 0xda, 0x01, 144 | 0x07, 0x6e, 0x6f, 0x72, 0x00, 0x6d, 0x61, 0x6c, 0xda, 0x01, 0x08, 0x73, 145 | 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x3f, 146 | ]; 147 | 148 | let proto = dbg!(proto::test::TestAll2::parse( 149 | pz::Codec::Protobuf, 150 | &mut &data[..] 151 | ) 152 | .unwrap()); 153 | 154 | assert!(proto.opt_str_or().is_none()); 155 | assert!(proto.opt_i32_or().is_none()); 156 | assert_eq!(proto.rep_str(), ["more", "nor\0mal", "strings?"]); 157 | match proto.cases() { 158 | proto::test::TestAll2Cases::RepStr(s) => { 159 | assert_eq!(s, ["more", "nor\0mal", "strings?"]) 160 | } 161 | _ => panic!(), 162 | }; 163 | } 164 | -------------------------------------------------------------------------------- /rust/src/rep/eq.rs: -------------------------------------------------------------------------------- 1 | //! Implementations of comparison traits. There's a lot of them. 2 | 3 | use crate::Ref; 4 | use crate::Repeated; 5 | use crate::Slice; 6 | use crate::SliceMut; 7 | use crate::Type; 8 | 9 | // Reflexive Eq. 10 | 11 | impl Eq for Slice<'_, T> 12 | where 13 | for<'a> Ref<'a, T>: PartialEq, 14 | { 15 | // 16 | } 17 | 18 | impl Eq for SliceMut<'_, T> 19 | where 20 | for<'a> Ref<'a, T>: PartialEq, 21 | { 22 | // 23 | } 24 | 25 | impl Eq for Repeated<'_, T> 26 | where 27 | for<'a> Ref<'a, T>: PartialEq, 28 | { 29 | // 30 | } 31 | 32 | // Comparing to slices. 33 | 34 | impl PartialEq<[U]> for Slice<'_, T> 35 | where 36 | T: Type + ?Sized, 37 | for<'a> Ref<'a, T>: PartialEq, 38 | { 39 | fn eq(&self, other: &[U]) -> bool { 40 | if self.len() != other.len() { 41 | return false; 42 | } 43 | self.iter().zip(other).all(|(a, b)| a == *b) 44 | } 45 | } 46 | 47 | impl PartialEq<[U]> for SliceMut<'_, T> 48 | where 49 | T: Type + ?Sized, 50 | for<'a> Ref<'a, T>: PartialEq, 51 | { 52 | fn eq(&self, other: &[U]) -> bool { 53 | if self.len() != other.len() { 54 | return false; 55 | } 56 | self.iter().zip(other).all(|(a, b)| a == *b) 57 | } 58 | } 59 | 60 | impl PartialEq<[U]> for Repeated<'_, T> 61 | where 62 | T: Type + ?Sized, 63 | for<'a> Ref<'a, T>: PartialEq, 64 | { 65 | fn eq(&self, other: &[U]) -> bool { 66 | if self.len() != other.len() { 67 | return false; 68 | } 69 | self.iter().zip(other).all(|(a, b)| a == *b) 70 | } 71 | } 72 | 73 | // Comparing to arrays. 74 | 75 | impl PartialEq<[U; N]> for Slice<'_, T> 76 | where 77 | T: Type + ?Sized, 78 | for<'a> Ref<'a, T>: PartialEq, 79 | { 80 | fn eq(&self, other: &[U; N]) -> bool { 81 | self.eq(other.as_slice()) 82 | } 83 | } 84 | 85 | impl PartialEq<[U; N]> for SliceMut<'_, T> 86 | where 87 | T: Type + ?Sized, 88 | for<'a> Ref<'a, T>: PartialEq, 89 | { 90 | fn eq(&self, other: &[U; N]) -> bool { 91 | self.eq(other.as_slice()) 92 | } 93 | } 94 | 95 | impl PartialEq<[U; N]> for Repeated<'_, T> 96 | where 97 | T: Type + ?Sized, 98 | for<'a> Ref<'a, T>: PartialEq, 99 | { 100 | fn eq(&self, other: &[U; N]) -> bool { 101 | self.eq(other.as_slice()) 102 | } 103 | } 104 | 105 | // Comparing between the n^2 combinations of custom slice. 106 | 107 | impl PartialEq> for Slice<'_, T> 108 | where 109 | T: Type + ?Sized, 110 | U: Type + ?Sized, 111 | for<'a> Ref<'a, T>: PartialEq>, 112 | { 113 | fn eq(&self, other: &Slice<'_, U>) -> bool { 114 | if self.len() != other.len() { 115 | return false; 116 | } 117 | self.iter().zip(other).all(|(a, b)| a == b) 118 | } 119 | } 120 | 121 | impl PartialEq> for Slice<'_, T> 122 | where 123 | T: Type + ?Sized, 124 | U: Type + ?Sized, 125 | for<'a> Ref<'a, T>: PartialEq>, 126 | { 127 | fn eq(&self, other: &SliceMut<'_, U>) -> bool { 128 | if self.len() != other.len() { 129 | return false; 130 | } 131 | self.iter().zip(other).all(|(a, b)| a == b) 132 | } 133 | } 134 | 135 | impl PartialEq> for Slice<'_, T> 136 | where 137 | T: Type + ?Sized, 138 | U: Type + ?Sized, 139 | for<'a> Ref<'a, T>: PartialEq>, 140 | { 141 | fn eq(&self, other: &Repeated<'_, U>) -> bool { 142 | if self.len() != other.len() { 143 | return false; 144 | } 145 | self.iter().zip(other).all(|(a, b)| a == b) 146 | } 147 | } 148 | 149 | impl PartialEq> for SliceMut<'_, T> 150 | where 151 | T: Type + ?Sized, 152 | U: Type + ?Sized, 153 | for<'a> Ref<'a, T>: PartialEq>, 154 | { 155 | fn eq(&self, other: &Slice<'_, U>) -> bool { 156 | if self.len() != other.len() { 157 | return false; 158 | } 159 | self.iter().zip(other).all(|(a, b)| a == b) 160 | } 161 | } 162 | 163 | impl PartialEq> for SliceMut<'_, T> 164 | where 165 | T: Type + ?Sized, 166 | U: Type + ?Sized, 167 | for<'a> Ref<'a, T>: PartialEq>, 168 | { 169 | fn eq(&self, other: &SliceMut<'_, U>) -> bool { 170 | if self.len() != other.len() { 171 | return false; 172 | } 173 | self.iter().zip(other).all(|(a, b)| a == b) 174 | } 175 | } 176 | 177 | impl PartialEq> for SliceMut<'_, T> 178 | where 179 | T: Type + ?Sized, 180 | U: Type + ?Sized, 181 | for<'a> Ref<'a, T>: PartialEq>, 182 | { 183 | fn eq(&self, other: &Repeated<'_, U>) -> bool { 184 | if self.len() != other.len() { 185 | return false; 186 | } 187 | self.iter().zip(other).all(|(a, b)| a == b) 188 | } 189 | } 190 | 191 | impl PartialEq> for Repeated<'_, T> 192 | where 193 | T: Type + ?Sized, 194 | U: Type + ?Sized, 195 | for<'a> Ref<'a, T>: PartialEq>, 196 | { 197 | fn eq(&self, other: &Slice<'_, U>) -> bool { 198 | if self.len() != other.len() { 199 | return false; 200 | } 201 | self.iter().zip(other).all(|(a, b)| a == b) 202 | } 203 | } 204 | 205 | impl PartialEq> for Repeated<'_, T> 206 | where 207 | T: Type + ?Sized, 208 | U: Type + ?Sized, 209 | for<'a> Ref<'a, T>: PartialEq>, 210 | { 211 | fn eq(&self, other: &SliceMut<'_, U>) -> bool { 212 | if self.len() != other.len() { 213 | return false; 214 | } 215 | self.iter().zip(other).all(|(a, b)| a == b) 216 | } 217 | } 218 | 219 | impl PartialEq> for Repeated<'_, T> 220 | where 221 | T: Type + ?Sized, 222 | U: Type + ?Sized, 223 | for<'a> Ref<'a, T>: PartialEq>, 224 | { 225 | fn eq(&self, other: &Repeated<'_, U>) -> bool { 226 | if self.len() != other.len() { 227 | return false; 228 | } 229 | self.iter().zip(other).all(|(a, b)| a == b) 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /rust/src/rep/index.rs: -------------------------------------------------------------------------------- 1 | //! Indexing traits, a la SliceIndex. 2 | 3 | use std::fmt; 4 | use std::ops; 5 | use std::ptr::NonNull; 6 | 7 | use crate::arena::RawArena; 8 | use crate::rep::Elem; 9 | use crate::rep::Slice; 10 | use crate::rep::SliceMut; 11 | use crate::seal::Seal; 12 | use crate::Mut; 13 | use crate::Ref; 14 | use crate::Type; 15 | 16 | pub trait RepIndex: Clone + fmt::Debug { 17 | type Ref<'a, T: Type + ?Sized> 18 | where 19 | T: 'a; 20 | type Mut<'a, T: Type + ?Sized> 21 | where 22 | T: 'a; 23 | 24 | #[doc(hidden)] 25 | unsafe fn __get<'a, T: Type + ?Sized + 'a>( 26 | self, 27 | ptr: NonNull>, 28 | len: usize, 29 | ) -> Option>; 30 | 31 | #[doc(hidden)] 32 | unsafe fn __get_mut<'a, T: Type + ?Sized + 'a>( 33 | self, 34 | ptr: NonNull>, 35 | len: usize, 36 | arena: RawArena, 37 | ) -> Option>; 38 | } 39 | 40 | impl RepIndex for usize { 41 | type Ref<'a, T: Type + ?Sized> = Ref<'a, T> where T: 'a; 42 | type Mut<'a, T: Type + ?Sized> = Mut<'a, T> where T: 'a; 43 | 44 | unsafe fn __get<'a, T: Type + ?Sized + 'a>( 45 | self, 46 | ptr: NonNull>, 47 | len: usize, 48 | ) -> Option> { 49 | if self >= len { 50 | return None; 51 | } 52 | 53 | Some(T::__ref(Seal, ptr.add(self).cast())) 54 | } 55 | 56 | unsafe fn __get_mut<'a, T: Type + ?Sized + 'a>( 57 | self, 58 | ptr: NonNull>, 59 | len: usize, 60 | arena: RawArena, 61 | ) -> Option> { 62 | if self >= len { 63 | return None; 64 | } 65 | 66 | Some(T::__mut(Seal, ptr.add(self).cast(), arena)) 67 | } 68 | } 69 | 70 | impl RepIndex for ops::Range { 71 | type Ref<'a, T: Type + ?Sized> = Slice<'a, T> where T: 'a; 72 | type Mut<'a, T: Type + ?Sized> = SliceMut<'a, T> where T: 'a; 73 | 74 | unsafe fn __get<'a, T: Type + ?Sized + 'a>( 75 | self, 76 | ptr: NonNull>, 77 | len: usize, 78 | ) -> Option> { 79 | if self.start > self.end || self.end > len { 80 | return None; 81 | } 82 | 83 | Some(Slice::from_raw_parts( 84 | ptr.add(self.start), 85 | self.end - self.start, 86 | )) 87 | } 88 | 89 | unsafe fn __get_mut<'a, T: Type + ?Sized + 'a>( 90 | self, 91 | ptr: NonNull>, 92 | len: usize, 93 | arena: RawArena, 94 | ) -> Option> { 95 | if self.start > self.end || self.end > len { 96 | return None; 97 | } 98 | 99 | Some(SliceMut::from_raw_parts( 100 | ptr.add(self.start), 101 | self.end - self.start, 102 | arena, 103 | )) 104 | } 105 | } 106 | 107 | impl RepIndex for ops::RangeTo { 108 | type Ref<'a, T: Type + ?Sized> = Slice<'a, T> where T: 'a; 109 | type Mut<'a, T: Type + ?Sized> = SliceMut<'a, T> where T: 'a; 110 | 111 | unsafe fn __get<'a, T: Type + ?Sized + 'a>( 112 | self, 113 | ptr: NonNull>, 114 | len: usize, 115 | ) -> Option> { 116 | RepIndex::__get(0..self.end, ptr, len) 117 | } 118 | 119 | unsafe fn __get_mut<'a, T: Type + ?Sized + 'a>( 120 | self, 121 | ptr: NonNull>, 122 | len: usize, 123 | arena: RawArena, 124 | ) -> Option> { 125 | RepIndex::__get_mut(0..self.end, ptr, len, arena) 126 | } 127 | } 128 | 129 | impl RepIndex for ops::RangeFrom { 130 | type Ref<'a, T: Type + ?Sized> = Slice<'a, T> where T: 'a; 131 | type Mut<'a, T: Type + ?Sized> = SliceMut<'a, T> where T: 'a; 132 | 133 | unsafe fn __get<'a, T: Type + ?Sized + 'a>( 134 | self, 135 | ptr: NonNull>, 136 | len: usize, 137 | ) -> Option> { 138 | RepIndex::__get(self.start..len, ptr, len) 139 | } 140 | 141 | unsafe fn __get_mut<'a, T: Type + ?Sized + 'a>( 142 | self, 143 | ptr: NonNull>, 144 | len: usize, 145 | arena: RawArena, 146 | ) -> Option> { 147 | RepIndex::__get_mut(self.start..len, ptr, len, arena) 148 | } 149 | } 150 | 151 | impl RepIndex for ops::RangeFull { 152 | type Ref<'a, T: Type + ?Sized> = Slice<'a, T> where T: 'a; 153 | type Mut<'a, T: Type + ?Sized> = SliceMut<'a, T> where T: 'a; 154 | 155 | unsafe fn __get<'a, T: Type + ?Sized + 'a>( 156 | self, 157 | ptr: NonNull>, 158 | len: usize, 159 | ) -> Option> { 160 | Some(Slice::from_raw_parts(ptr, len)) 161 | } 162 | 163 | unsafe fn __get_mut<'a, T: Type + ?Sized + 'a>( 164 | self, 165 | ptr: NonNull>, 166 | len: usize, 167 | arena: RawArena, 168 | ) -> Option> { 169 | Some(SliceMut::from_raw_parts(ptr, len, arena)) 170 | } 171 | } 172 | 173 | impl RepIndex for ops::RangeInclusive { 174 | type Ref<'a, T: Type + ?Sized> = Slice<'a, T> where T: 'a; 175 | type Mut<'a, T: Type + ?Sized> = SliceMut<'a, T> where T: 'a; 176 | 177 | unsafe fn __get<'a, T: Type + ?Sized + 'a>( 178 | self, 179 | ptr: NonNull>, 180 | len: usize, 181 | ) -> Option> { 182 | if *self.end() == usize::MAX { 183 | return None; 184 | } 185 | RepIndex::__get(*self.start()..*self.end() + 1, ptr, len) 186 | } 187 | 188 | unsafe fn __get_mut<'a, T: Type + ?Sized + 'a>( 189 | self, 190 | ptr: NonNull>, 191 | len: usize, 192 | arena: RawArena, 193 | ) -> Option> { 194 | if *self.end() == usize::MAX { 195 | return None; 196 | } 197 | RepIndex::__get_mut(*self.start()..*self.end() + 1, ptr, len, arena) 198 | } 199 | } 200 | 201 | impl RepIndex for ops::RangeToInclusive { 202 | type Ref<'a, T: Type + ?Sized> = Slice<'a, T> where T: 'a; 203 | type Mut<'a, T: Type + ?Sized> = SliceMut<'a, T> where T: 'a; 204 | 205 | unsafe fn __get<'a, T: Type + ?Sized + 'a>( 206 | self, 207 | ptr: NonNull>, 208 | len: usize, 209 | ) -> Option> { 210 | RepIndex::__get(0..=self.end, ptr, len) 211 | } 212 | 213 | unsafe fn __get_mut<'a, T: Type + ?Sized + 'a>( 214 | self, 215 | ptr: NonNull>, 216 | len: usize, 217 | arena: RawArena, 218 | ) -> Option> { 219 | RepIndex::__get_mut(0..=self.end, ptr, len, arena) 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /pzc/src/syn/mod.rs: -------------------------------------------------------------------------------- 1 | //! Syntax trees for pz. 2 | 3 | mod parse; 4 | 5 | use ilex::token; 6 | use ilex::Span; 7 | use ilex::Spanned; 8 | use ilex::Token; 9 | 10 | pub fn lex<'t>( 11 | file: ilex::File<'t>, 12 | report: &ilex::Report, 13 | ) -> Result, ilex::Fatal> { 14 | parse::lex(file, report) 15 | } 16 | 17 | /// A single `.pz` file. 18 | #[derive(Debug)] 19 | pub struct PzFile<'ast> { 20 | pub attrs: Vec>, 21 | pub package: Package<'ast>, 22 | pub imports: Vec>, 23 | pub items: Vec>, 24 | } 25 | 26 | impl<'ast> PzFile<'ast> { 27 | pub fn parse( 28 | stream: &'ast token::Stream<'ast>, 29 | report: &ilex::Report, 30 | ) -> Result { 31 | parse::parse(stream, report) 32 | } 33 | } 34 | 35 | /// A `package = foo.bar.baz` declaration. 36 | /// 37 | /// This is the first thing in the file. 38 | #[derive(Debug)] 39 | pub struct Package<'ast> { 40 | pub package: token::Keyword<'ast>, 41 | pub path: Path<'ast>, 42 | } 43 | 44 | impl Spanned for Package<'_> { 45 | fn span(&self, icx: &ilex::Context) -> Span { 46 | Span::union([self.package.span(icx), self.path.span(icx)]) 47 | } 48 | } 49 | 50 | /// An `import foo.bar { Type.Sub, Enum as Rename }` declaration. 51 | /// 52 | /// This is the first thing in the file. 53 | #[derive(Debug)] 54 | pub struct Import<'ast> { 55 | pub import: token::Keyword<'ast>, 56 | pub attrs: Vec>, 57 | pub package: Path<'ast>, 58 | 59 | /// Pairs of imported paths, and an optional rename. 60 | pub braces: token::Bracket<'ast>, 61 | pub symbols: Vec>, 62 | } 63 | 64 | #[derive(Debug)] 65 | pub struct ImportedSymbol<'ast> { 66 | pub symbol: Path<'ast>, 67 | pub rename: Option<(token::Keyword<'ast>, token::Ident<'ast>)>, 68 | } 69 | 70 | impl Spanned for Import<'_> { 71 | fn span(&self, icx: &ilex::Context) -> Span { 72 | Span::union([self.import.span(icx), self.braces.span(icx)]) 73 | } 74 | } 75 | 76 | /// A period-delimited path, e.g. `foo.bar.Msg`. 77 | #[derive(Debug)] 78 | pub struct Path<'ast> { 79 | /// List of components and the dots that follow them, if any. 80 | pub components: Vec<(token::Ident<'ast>, Option>)>, 81 | } 82 | 83 | impl<'ast> Path<'ast> { 84 | pub fn last(&self) -> token::Ident<'ast> { 85 | self.components.last().unwrap().0 86 | } 87 | 88 | pub fn join(&self) -> String { 89 | let mut name = String::new(); 90 | for (id, dot) in &self.components { 91 | name.push_str(id.name().text(id.context())); 92 | if dot.is_some() { 93 | name.push('.'); 94 | } 95 | } 96 | 97 | name 98 | } 99 | 100 | pub fn is_exactly<'a>( 101 | &self, 102 | path: impl IntoIterator, 103 | ) -> bool { 104 | self 105 | .components 106 | .iter() 107 | .zip(path) 108 | .map(|((a, _), b)| a.name().text(a.context()) == b) 109 | .all(|x| x) 110 | } 111 | } 112 | 113 | impl Spanned for Path<'_> { 114 | fn span(&self, icx: &ilex::Context) -> Span { 115 | Span::union([ 116 | self.components.first().unwrap().0.span(icx), 117 | self.components.last().unwrap().0.span(icx), 118 | ]) 119 | } 120 | } 121 | 122 | /// Any kind of delcaration. 123 | #[derive(Debug)] 124 | pub enum Item<'ast> { 125 | Decl(Decl<'ast>), 126 | Field(Field<'ast>), 127 | } 128 | 129 | impl Spanned for Item<'_> { 130 | fn span(&self, icx: &ilex::Context) -> Span { 131 | match self { 132 | Self::Decl(x) => x.span(icx), 133 | Self::Field(x) => x.span(icx), 134 | } 135 | } 136 | } 137 | 138 | /// An attribute on something, e.g. `@deprecated`. 139 | #[derive(Debug)] 140 | pub enum Attr<'ast> { 141 | At { 142 | at: Option>, 143 | name: Path<'ast>, 144 | value: Option<(token::Keyword<'ast>, AttrValue<'ast>)>, 145 | }, 146 | Doc(token::Quoted<'ast>), 147 | } 148 | 149 | impl Spanned for Attr<'_> { 150 | fn span(&self, icx: &ilex::Context) -> Span { 151 | match self { 152 | Attr::At { at, name, value } => { 153 | let start = at.map(|s| s.span(icx)).unwrap_or_else(|| name.span(icx)); 154 | let end = value 155 | .as_ref() 156 | .map(|(_, v)| v.span(icx)) 157 | .unwrap_or_else(|| name.span(icx)); 158 | Span::union([start, end]) 159 | } 160 | Attr::Doc(doc) => doc.span(icx), 161 | } 162 | } 163 | } 164 | 165 | /// An attribute value. 166 | #[derive(Debug)] 167 | pub enum AttrValue<'ast> { 168 | Path(Path<'ast>), 169 | Int(token::Digital<'ast>), 170 | Str(token::Quoted<'ast>), 171 | } 172 | 173 | impl Spanned for AttrValue<'_> { 174 | fn span(&self, icx: &ilex::Context) -> Span { 175 | match self { 176 | AttrValue::Path(p) => p.span(icx), 177 | AttrValue::Int(i) => i.span(icx), 178 | AttrValue::Str(s) => s.span(icx), 179 | } 180 | } 181 | } 182 | 183 | /// A declaration. This is anything of the form `keyword Name { items }`. 184 | #[derive(Debug)] 185 | pub struct Decl<'ast> { 186 | pub kw: token::Keyword<'ast>, 187 | pub braces: token::Bracket<'ast>, 188 | pub kind: DeclKind, 189 | pub name: token::Ident<'ast>, 190 | pub items: Vec>, 191 | pub attrs: Vec>, 192 | } 193 | 194 | impl Spanned for Decl<'_> { 195 | fn span(&self, icx: &ilex::Context) -> Span { 196 | Span::union([self.kw.span(icx), self.braces.span(icx)]) 197 | } 198 | } 199 | 200 | /// A kind of [`Decl`]. 201 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 202 | pub enum DeclKind { 203 | Message, 204 | Struct, 205 | Choice, 206 | Enum, 207 | } 208 | 209 | /// A `my_field: type = 5,` declaration. 210 | /// 211 | /// All declarations use the same field production, except that some might 212 | /// not use a number and some might not use a type. 213 | #[derive(Debug)] 214 | pub struct Field<'ast> { 215 | pub number: Option>, 216 | pub name: token::Ident<'ast>, 217 | pub ty: Option>, 218 | pub attrs: Vec>, 219 | } 220 | 221 | impl Spanned for Field<'_> { 222 | fn span(&self, icx: &ilex::Context) -> Span { 223 | let start = self 224 | .number 225 | .map(|n| n.span(icx)) 226 | .unwrap_or_else(|| self.name.span(icx)); 227 | let end = self 228 | .ty 229 | .as_ref() 230 | .map(|n| n.span(icx)) 231 | .unwrap_or_else(|| self.name.span(icx)); 232 | Span::union([start, end]) 233 | } 234 | } 235 | 236 | /// A type, such as on a field declaration. 237 | #[derive(Debug)] 238 | pub enum Type<'ast> { 239 | Repeated { 240 | repeated: token::Keyword<'ast>, 241 | element: Box>, 242 | }, 243 | Path(Path<'ast>), 244 | } 245 | 246 | impl Spanned for Type<'_> { 247 | fn span(&self, icx: &ilex::Context) -> Span { 248 | match self { 249 | Type::Repeated { repeated, element } => { 250 | Span::union([repeated.span(icx), element.span(icx)]) 251 | } 252 | Type::Path(path) => path.span(icx), 253 | } 254 | } 255 | } 256 | 257 | pub fn unescape(str: token::Quoted) -> String { 258 | str.to_utf8(|esc, _, out| match esc.text(str.context()) { 259 | "\\\"" => out.push('"'), 260 | "\\\\" => out.push('\\'), 261 | _ => unreachable!(), 262 | }) 263 | } 264 | -------------------------------------------------------------------------------- /rust/plugin/src/rust/mod.rs: -------------------------------------------------------------------------------- 1 | //! Rust codegen backend. 2 | 3 | use pz::proto::plugin; 4 | 5 | use crate::emit; 6 | use crate::exec_plugin; 7 | use crate::rust::names::deprecated; 8 | 9 | mod choice; 10 | mod r#enum; 11 | mod fields; 12 | mod message; 13 | mod names; 14 | 15 | pub fn rust_plugin() -> ! { 16 | exec_plugin( 17 | |_| plugin::AboutResponse { 18 | name: Some("rust".into()), 19 | version: Some(env!("CARGO_PKG_VERSION").into()), 20 | options: vec![ 21 | plugin::about_response::Option { 22 | name: Some("rt-crate".into()), 23 | help: Some( 24 | "Rust crate name to use for importing the pz runtime".into(), 25 | ), 26 | }, 27 | plugin::about_response::Option { 28 | name: Some("package-prefix".into()), 29 | help: Some( 30 | "comma-separated packages to strip from module emits".into(), 31 | ), 32 | }, 33 | ], 34 | }, 35 | |ctx| { 36 | let mut w = emit::SourceWriter::new(emit::Options::default()); 37 | let rt = ctx.option("rt-crate").unwrap_or("pz"); 38 | w.emit( 39 | vars! { 40 | use_rt: |w| match rt { 41 | "crate" => w.write("use crate"), 42 | rt => w.emit(vars! { rt }, "extern crate $rt"), 43 | }, 44 | }, 45 | r" 46 | // ! ! ! GENERATED CODE, DO NOT EDIT ! ! ! 47 | #![cfg_attr(rustfmt, rustfmt_skip)] 48 | 49 | #![allow(non_camel_case_types)] 50 | #![allow(non_upper_case_globals)] 51 | #![allow(non_snake_case)] 52 | #![allow(unused)] 53 | 54 | #![allow(clippy::borrow_interior_mutable_const)] 55 | #![allow(clippy::declare_interior_mutable_const)] 56 | #![allow(clippy::derivable_impls)] 57 | #![allow(clippy::identity_op)] 58 | #![allow(clippy::needless_borrow)] 59 | #![allow(clippy::transmute_float_to_int)] 60 | #![allow(clippy::transmute_int_to_float)] 61 | #![allow(clippy::useless_transmute)] 62 | #![allow(clippy::unnecessary_cast)] 63 | #![allow(clippy::wrong_self_convention)] 64 | 65 | #![no_implicit_prelude] 66 | 67 | $use_rt as __rt; 68 | use __rt::__z; 69 | use __rt::reflect as __r; 70 | use __z::std as __s; 71 | 72 | use __s::default::Default as _; 73 | ", 74 | ); 75 | w.new_line(); 76 | 77 | let mut prefixes: Vec> = ctx 78 | .option("package-prefix") 79 | .map(|opt| { 80 | opt 81 | .split(",") 82 | .map(|s| s.split(".").map(str::trim).collect()) 83 | .collect() 84 | }) 85 | .unwrap_or_default(); 86 | prefixes.sort(); 87 | 88 | // Extract the module set of each type. 89 | let types = ctx.types_to_generate().collect::>(); 90 | let mut types = types 91 | .iter() 92 | .map(|ty| { 93 | let mut pkg = 94 | ty.package().split(".").map(str::trim).collect::>(); 95 | 96 | // Want to search the longest prefixes first. 97 | for prefix in prefixes.iter().rev() { 98 | if let Some(suf) = pkg.strip_prefix(prefix.as_slice()) { 99 | pkg = suf.to_vec(); 100 | break; 101 | } 102 | } 103 | 104 | (pkg, *ty) 105 | }) 106 | .collect::>(); 107 | 108 | // Sort by modules. 109 | types.sort_by(|(a, _), (b, _)| Ord::cmp(a, b)); 110 | 111 | let mut stack = Vec::new(); 112 | for &(ref mods, ty) in &types { 113 | // Quadratic, oops. 114 | let common_prefix = 115 | stack.iter().zip(mods).filter(|(a, b)| a == b).count(); 116 | while stack.len() > common_prefix { 117 | w.emit( 118 | vars! { mod: stack.pop().unwrap() }, 119 | " 120 | } // mod $mod 121 | ", 122 | ); 123 | } 124 | for &m in &mods[common_prefix..] { 125 | w.emit( 126 | vars! { mod: m }, 127 | " 128 | pub mod $mod { 129 | use super::{__, __rt, __z, __s, __r}; 130 | use __s::default::Default as _; 131 | ", 132 | ); 133 | stack.push(m); 134 | } 135 | 136 | w.with_vars( 137 | vars! { 138 | deprecated: deprecated( 139 | ty.proto().attrs.as_ref().and_then(|a| a.deprecated.as_deref())), 140 | 141 | // Common standard library types and names. 142 | fmt: "__s::fmt", 143 | size_of: "__s::mem::size_of", 144 | AsRef: "__s::convert::AsRef", 145 | Default: "__s::default::Default", 146 | Into: "__s::convert::Into", 147 | NonNull: "__s::ptr::NonNull", 148 | Layout: "__s::alloc::Layout", 149 | PhantomData: "__s::marker::PhantomData", 150 | Sized: "__s::marker::Sized", 151 | 152 | Read: "__s::io::Read", 153 | Write: "__s::io::Write", 154 | Vec: "__s::vec::Vec", 155 | 156 | Option: "__s::option::Option", 157 | Some: "__s::option::Option::Some", 158 | None: "__s::option::Option::None", 159 | 160 | Result: "__s::result::Result", 161 | Ok: "__s::result::Result::Ok", 162 | Err: "__s::result::Result::Err", 163 | 164 | // Common runtime types and names. 165 | Ref: "__rt::reflect::Ref", 166 | Mut: "__rt::reflect::Mut", 167 | View: "__rt::reflect::View", 168 | Type: "__rt::reflect::Type", 169 | 170 | Slice: "__rt::Slice", 171 | Repeated: "__rt::Repeated", 172 | 173 | keyword: match ty.kind() { 174 | crate::proto::r#type::Kind::Message => "message", 175 | crate::proto::r#type::Kind::Struct => "struct", 176 | crate::proto::r#type::Kind::Choice => "choice", 177 | crate::proto::r#type::Kind::Enum => "enum", 178 | }, 179 | package: names::ident(ty.package()), 180 | Name: names::ident(ty.name()), 181 | Ident: names::type_ident(ty), 182 | Type: names::type_name(ty), 183 | TDP: format_args!("{}::__tdp_info()", names::type_ident(ty)), 184 | priv: format_args!("__priv_{}", names::type_ident(ty)), 185 | 186 | NUM_FIELDS: ty.fields().count(), 187 | }, 188 | |w| match ty.kind() { 189 | crate::proto::r#type::Kind::Message => message::emit(ty, w), 190 | crate::proto::r#type::Kind::Struct => { 191 | ctx 192 | .warn("sorry: can't emit this kind of type yet") 193 | .at(ty.span().unwrap()); 194 | } 195 | crate::proto::r#type::Kind::Choice => choice::emit(ty, w), 196 | crate::proto::r#type::Kind::Enum => r#enum::emit(ty, w), 197 | }, 198 | ) 199 | } 200 | 201 | while let Some(m) = stack.pop() { 202 | w.emit( 203 | vars! { mod: m }, 204 | " 205 | } // mod $mod 206 | ", 207 | ); 208 | } 209 | w.new_line(); 210 | 211 | w.write( 212 | " 213 | // The __ module exports the package universe needed for this module, to 214 | // simplify cross-type references. 215 | mod __f { pub use super::*; } 216 | mod __ { 217 | use super::__f; 218 | pub use __f::*; 219 | ", 220 | ); 221 | let mut stack = Vec::new(); 222 | for prefix in &prefixes { 223 | // Quadratic, oops. 224 | let common_prefix = 225 | stack.iter().zip(prefix).filter(|(a, b)| a == b).count(); 226 | while stack.len() > common_prefix { 227 | w.emit( 228 | vars! { mod: stack.pop().unwrap() }, 229 | " 230 | } // mod $mod 231 | ", 232 | ); 233 | } 234 | for &m in &prefix[common_prefix..] { 235 | w.emit( 236 | vars! { mod: m }, 237 | " 238 | pub mod $mod { 239 | use super::__f; 240 | pub use __f::*; 241 | ", 242 | ); 243 | stack.push(m); 244 | } 245 | } 246 | while let Some(m) = stack.pop() { 247 | w.emit( 248 | vars! { mod: m }, 249 | " 250 | } // mod $mod 251 | ", 252 | ); 253 | } 254 | w.write( 255 | " 256 | } // mod __ 257 | ", 258 | ); 259 | 260 | ctx.add_file(plugin::codegen_response::File { 261 | path: Some("lib.pz.rs".into()), 262 | content: Some(w.to_string().into_bytes()), 263 | }) 264 | }, 265 | ) 266 | } 267 | -------------------------------------------------------------------------------- /rust/plugin/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Plugins! 2 | 3 | use std::cell; 4 | use std::cell::RefCell; 5 | use std::env; 6 | use std::fmt; 7 | use std::io; 8 | use std::io::Read; 9 | use std::io::Write; 10 | 11 | use prost::Message; 12 | pub use pz::prost; 13 | 14 | use pz::proto; 15 | use pz::proto::plugin; 16 | 17 | #[macro_use] 18 | mod emit; 19 | mod rust; 20 | 21 | pub use rust::rust_plugin; 22 | 23 | /// The context for the current codegen operation. 24 | pub struct CodegenCtx { 25 | req: plugin::CodegenRequest, 26 | resp: RefCell, 27 | } 28 | 29 | impl CodegenCtx { 30 | /// Returns the bundle that was sent as part of the request. 31 | pub fn bundle(&self) -> &proto::Bundle { 32 | self.req.bundle.as_ref().unwrap() 33 | } 34 | 35 | /// Returns an iterator over types that we need to generate. 36 | pub fn types_to_generate(&self) -> impl Iterator + '_ { 37 | self.req.requested_indices.iter().map(|&idx| Type { 38 | ctx: self, 39 | bundle: self.bundle(), 40 | proto: &self.bundle().types[idx as usize], 41 | }) 42 | } 43 | 44 | /// Looks up an option in the options array. 45 | pub fn option(&self, name: &str) -> Option<&str> { 46 | self.req.options.get(name).map(|x| &**x) 47 | } 48 | 49 | /// Returns whether the `pz` driver has requested we operate in "debug mode". 50 | pub fn is_debug_mode(&self) -> bool { 51 | self.req.debug() 52 | } 53 | 54 | /// Adds a file to the response. The file paths are relative to the output 55 | /// directory of the driver process. 56 | pub fn add_file(&self, file: plugin::codegen_response::File) { 57 | self.resp.borrow_mut().files.push(file); 58 | } 59 | 60 | /// Adds a new error to the response. 61 | pub fn error(&self, msg: impl fmt::Display) -> Diagnostic<'_> { 62 | Diagnostic { 63 | proto: cell::RefMut::map(self.resp.borrow_mut(), |resp| { 64 | resp.report.push(plugin::Diagnostic { 65 | message: Some(msg.to_string()), 66 | kind: Some(plugin::diagnostic::Kind::Error.into()), 67 | ..Default::default() 68 | }); 69 | resp.report.last_mut().unwrap() 70 | }), 71 | } 72 | } 73 | 74 | pub fn warn(&self, msg: impl fmt::Display) -> Diagnostic<'_> { 75 | Diagnostic { 76 | proto: cell::RefMut::map(self.resp.borrow_mut(), |resp| { 77 | resp.report.push(plugin::Diagnostic { 78 | message: Some(msg.to_string()), 79 | kind: Some(plugin::diagnostic::Kind::Warning.into()), 80 | ..Default::default() 81 | }); 82 | resp.report.last_mut().unwrap() 83 | }), 84 | } 85 | } 86 | } 87 | 88 | /// A diagnostic that is being built up. 89 | pub struct Diagnostic<'ccx> { 90 | proto: cell::RefMut<'ccx, plugin::Diagnostic>, 91 | } 92 | 93 | impl Diagnostic<'_> { 94 | /// Adds a new relevant snippet at the given location. 95 | pub fn at(self, span: Span) -> Self { 96 | self.saying(span, "") 97 | } 98 | 99 | /// Adds a new relevant snippet at the given location, with the given message 100 | /// attached to it. 101 | pub fn saying(mut self, span: Span, message: impl fmt::Display) -> Self { 102 | self.proto.snippets.push(plugin::diagnostic::Snippet { 103 | span: Some(span.0), 104 | message: Some(message.to_string()), 105 | is_remark: Some(false), 106 | }); 107 | self 108 | } 109 | 110 | /// Like `saying`, but the underline is as for a "note" rather than the 111 | /// overall diagnostic. 112 | pub fn remark(mut self, span: Span, message: impl fmt::Display) -> Self { 113 | self.proto.snippets.push(plugin::diagnostic::Snippet { 114 | span: Some(span.0), 115 | message: Some(message.to_string()), 116 | is_remark: Some(true), 117 | }); 118 | self 119 | } 120 | 121 | /// Appends a note to the bottom of the diagnostic. 122 | pub fn note(&mut self, message: impl fmt::Display) -> &mut Self { 123 | self.proto.notes.push(message.to_string()); 124 | self 125 | } 126 | } 127 | 128 | #[derive(Copy, Clone)] 129 | pub struct Span(u32); 130 | 131 | #[derive(Copy, Clone)] 132 | pub struct Type<'ccx> { 133 | ctx: &'ccx CodegenCtx, 134 | bundle: &'ccx proto::Bundle, 135 | proto: &'ccx proto::Type, 136 | } 137 | 138 | impl<'ccx> Type<'ccx> { 139 | pub fn ccx(&self) -> &'ccx CodegenCtx { 140 | self.ctx 141 | } 142 | 143 | pub fn package(&self) -> &str { 144 | &self.bundle.packages[self.proto.package() as usize] 145 | } 146 | 147 | pub fn name(&self) -> &str { 148 | self.proto.name() 149 | } 150 | 151 | pub fn kind(&self) -> proto::r#type::Kind { 152 | self.proto.kind() 153 | } 154 | 155 | pub fn parent(&self) -> Option> { 156 | self.proto.declared_in.map(|idx| Type { 157 | ctx: self.ctx, 158 | bundle: self.bundle, 159 | proto: &self.bundle.types[idx as usize], 160 | }) 161 | } 162 | 163 | pub fn nesteds(&self) -> impl Iterator> + '_ { 164 | self.proto.nesteds.iter().map(|&idx| Type { 165 | ctx: self.ctx, 166 | bundle: self.bundle, 167 | proto: &self.bundle.types[idx as usize], 168 | }) 169 | } 170 | 171 | pub fn fields(&self) -> impl Iterator> + '_ { 172 | self.proto.fields.iter().enumerate().map(|(i, f)| Field { 173 | ctx: self.ctx, 174 | bundle: self.bundle, 175 | proto: f, 176 | parent: self.proto, 177 | index: i as u32, 178 | }) 179 | } 180 | 181 | pub fn span(&self) -> Option { 182 | self.proto.span.map(Span) 183 | } 184 | 185 | pub fn proto(&self) -> &'ccx proto::Type { 186 | self.proto 187 | } 188 | } 189 | 190 | #[derive(Copy, Clone)] 191 | pub struct Field<'ccx> { 192 | ctx: &'ccx CodegenCtx, 193 | bundle: &'ccx proto::Bundle, 194 | proto: &'ccx proto::Field, 195 | parent: &'ccx proto::Type, 196 | index: u32, 197 | } 198 | 199 | impl<'ccx> Field<'ccx> { 200 | pub fn ccx(&self) -> &'ccx CodegenCtx { 201 | self.ctx 202 | } 203 | 204 | pub fn name(&self) -> &str { 205 | self.proto.name() 206 | } 207 | 208 | pub fn number(&self) -> Option { 209 | self.proto.number 210 | } 211 | 212 | pub fn index(&self) -> u32 { 213 | self.index 214 | } 215 | 216 | pub fn is_repeated(&self) -> bool { 217 | self.proto.is_repeated() 218 | } 219 | 220 | pub fn parent(&self) -> Type<'ccx> { 221 | Type { 222 | ctx: self.ctx, 223 | bundle: self.bundle, 224 | proto: self.parent, 225 | } 226 | } 227 | 228 | pub fn ty(&self) -> (proto::field::Type, Option>) { 229 | let kind = self.proto.r#type(); 230 | if kind == proto::field::Type::Type { 231 | return ( 232 | kind, 233 | Some(Type { 234 | ctx: self.ctx, 235 | bundle: self.bundle, 236 | proto: &self.bundle.types[self.proto.type_index() as usize], 237 | }), 238 | ); 239 | } 240 | 241 | (kind, None) 242 | } 243 | 244 | pub fn span(&self) -> Option { 245 | self.proto.span.map(Span) 246 | } 247 | 248 | pub fn proto(&self) -> &'ccx proto::Field { 249 | self.proto 250 | } 251 | } 252 | 253 | /// Executes a plugin main function. 254 | /// 255 | /// This function should be called in the `main` function of a program that 256 | /// implements a codegen backend. 257 | pub fn exec_plugin( 258 | about: impl FnOnce(&plugin::AboutRequest) -> plugin::AboutResponse, 259 | codegen: impl FnOnce(&CodegenCtx), 260 | ) -> ! { 261 | let mut input = Vec::new(); 262 | io::stdin() 263 | .read_to_end(&mut input) 264 | .expect("failed to read request proto"); 265 | 266 | let mut req = plugin::Request::decode(input.as_slice()) 267 | .expect("failed to parse request proto"); 268 | let mut resp = plugin::Response::default(); 269 | 270 | match req.value.take() { 271 | Some(plugin::request::Value::About(req)) => { 272 | resp.value = Some(plugin::response::Value::About(about(&req))); 273 | } 274 | Some(plugin::request::Value::Codegen(req)) => { 275 | let ctx = CodegenCtx { 276 | req, 277 | resp: Default::default(), 278 | }; 279 | codegen(&ctx); 280 | resp.value = Some(plugin::response::Value::Codegen(RefCell::into_inner( 281 | ctx.resp, 282 | ))); 283 | } 284 | None => panic!("unknown request proto"), 285 | } 286 | 287 | io::stdout() 288 | .write_all(&resp.encode_to_vec()) 289 | .expect("failed to write response proto"); 290 | 291 | std::process::exit(0); 292 | } 293 | 294 | /// Runs the "trivial" bundle plugin that simply echoes the request bundle. 295 | pub fn bundle_plugin() -> ! { 296 | exec_plugin( 297 | |_| plugin::AboutResponse { 298 | name: Some("bundle".into()), 299 | version: Some(env!("CARGO_PKG_VERSION").into()), 300 | options: vec![plugin::about_response::Option { 301 | name: Some("out".into()), 302 | help: Some( 303 | "The file to write the bundle proto to; defaults to \"bundle.pb\"" 304 | .into(), 305 | ), 306 | }], 307 | }, 308 | |ctx| { 309 | ctx.add_file(plugin::codegen_response::File { 310 | path: Some(ctx.option("out").unwrap_or("bundle.pb").into()), 311 | content: Some(ctx.bundle().encode_to_vec()), 312 | }); 313 | }, 314 | ) 315 | } 316 | -------------------------------------------------------------------------------- /rust/plugin/src/emit.rs: -------------------------------------------------------------------------------- 1 | //! Source code printing utilities. 2 | 3 | use std::collections::HashMap; 4 | use std::fmt; 5 | use std::fmt::Display; 6 | use std::fmt::Write; 7 | use std::mem; 8 | use std::panic; 9 | 10 | macro_rules! vars_inner { 11 | (($($args:tt)*) $(,)?) => { 12 | [$($args),*] 13 | }; 14 | (($($args:tt)*) $name:tt: |$x:tt| $expr:literal $(, $($rest:tt)*)?) => { 15 | vars_inner!( 16 | ($($args)* (vars_inner!(@stringify $name), 17 | $crate::emit::Sub::Text($expr))) 18 | $($($rest)*)? 19 | ) 20 | }; 21 | (($($args:tt)*) $name:tt: |$x:tt| $expr:expr $(, $($rest:tt)*)?) => { 22 | vars_inner!( 23 | ($($args)* (vars_inner!(@stringify $name), 24 | $crate::emit::Sub::Cb(&|$x| $expr))) 25 | $($($rest)*)? 26 | ) 27 | }; 28 | (($($args:tt)*) $name:tt: $expr:expr $(, $($rest:tt)*)?) => { 29 | vars_inner!( 30 | ($($args)* (vars_inner!(@stringify $name), 31 | $crate::emit::Sub::Fmt(&$expr as &dyn std::fmt::Display))) 32 | $($($rest)*)? 33 | ) 34 | }; 35 | 36 | (($($args:tt)*) $name:tt $(, $($rest:tt)*)?) => { 37 | vars_inner!( 38 | ($($args)*) $name: $name $(, $($rest)*)? 39 | ) 40 | }; 41 | 42 | (@stringify $name:ident) => {stringify!($name)}; 43 | (@stringify $name:expr) => {$name}; 44 | } 45 | 46 | macro_rules! vars { 47 | ($($tt:tt)*) => {vars_inner!(() $($tt)*)} 48 | } 49 | 50 | pub fn display( 51 | body: impl Fn(&mut fmt::Formatter) -> fmt::Result, 52 | ) -> impl Display { 53 | pub struct Display(F); 54 | impl fmt::Result> fmt::Display for Display { 55 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 56 | (self.0)(f) 57 | } 58 | } 59 | Display(body) 60 | } 61 | 62 | pub struct SourceWriter { 63 | lines: Vec, 64 | indent: u32, 65 | opts: Options, 66 | frames: Vec>>, 67 | } 68 | 69 | pub struct Options { 70 | #[allow(unused)] 71 | pub comment_start: &'static str, 72 | } 73 | 74 | #[allow(unused)] 75 | pub enum Sub<'a> { 76 | Text(&'a str), 77 | Fmt(&'a dyn fmt::Display), 78 | Cb(&'a dyn Fn(&mut SourceWriter)), 79 | } 80 | 81 | impl Default for Options { 82 | fn default() -> Self { 83 | Self { 84 | comment_start: "//", 85 | } 86 | } 87 | } 88 | 89 | struct Line { 90 | indent: u32, 91 | data: String, 92 | } 93 | 94 | impl SourceWriter { 95 | pub fn new(opts: Options) -> Self { 96 | Self { 97 | lines: Vec::new(), 98 | indent: 0, 99 | opts, 100 | frames: Vec::new(), 101 | } 102 | } 103 | 104 | pub fn new_line(&mut self) { 105 | self.lines.push(Line { 106 | indent: self.indent, 107 | data: String::new(), 108 | }) 109 | } 110 | 111 | fn buf_mut(&mut self) -> &mut String { 112 | if self.lines.is_empty() { 113 | self.new_line(); 114 | } 115 | &mut self.lines.last_mut().unwrap().data 116 | } 117 | 118 | pub fn with_vars( 119 | &mut self, 120 | vars: [(&str, Sub); N], 121 | cb: impl FnOnce(&mut Self), 122 | ) { 123 | let map: HashMap<&str, Sub> = vars.into(); 124 | unsafe { 125 | self.frames.push(mem::transmute::< 126 | HashMap<&str, Sub>, 127 | HashMap<&'static str, Sub<'static>>, 128 | >(map)); 129 | } 130 | 131 | // This assert-unwind-safe is actually safe, because all we do 132 | // while the panic is paused is pop from `self.frames` and then 133 | // resume the panic. 134 | let err = panic::catch_unwind(panic::AssertUnwindSafe(|| cb(self))); 135 | 136 | self.frames.pop(); 137 | if let Err(p) = err { 138 | panic::resume_unwind(p); 139 | } 140 | } 141 | 142 | #[track_caller] 143 | pub fn emit(&mut self, vars: [(&str, Sub); N], tpl: &str) { 144 | self.with_vars(vars, |e| { 145 | e.exec(Template::parse(tpl, &e.opts)); 146 | }) 147 | } 148 | 149 | pub fn write(&mut self, tpl: &str) { 150 | self.emit(vars! {}, tpl) 151 | } 152 | 153 | #[track_caller] 154 | fn exec(&mut self, tpl: Template) { 155 | let ambient_indent = self.indent; 156 | let mut was_newline = true; 157 | for tok in &tpl.tokens { 158 | match tok { 159 | Token::Newline { indent } => { 160 | // Non-consecutive newlines that *appear* to have been printed 161 | // consecutively indicate that the previous line consisted only of 162 | // templates that expanded to the empty string, so we can safely 163 | // delete such a line. 164 | if !was_newline { 165 | if let Some(cur) = self.lines.last_mut() { 166 | if cur.data.is_empty() { 167 | self.lines.pop(); 168 | } 169 | } 170 | } 171 | self.indent = ambient_indent + indent; 172 | self.new_line(); 173 | was_newline = true; 174 | continue; 175 | } 176 | Token::Text(data) => { 177 | was_newline = false; 178 | self.buf_mut().push_str(data); 179 | } 180 | Token::Var(var) => { 181 | was_newline = false; 182 | let mut sub = None; 183 | for frame in self.frames.iter().rev() { 184 | if let Some(s) = frame.get(var) { 185 | sub = Some(s); 186 | break; 187 | } 188 | } 189 | 190 | assert!(sub.is_some(), "unknown variable {var}"); 191 | let sub = unsafe { mem::transmute::<&Sub, &Sub>(sub.unwrap()) }; 192 | match sub { 193 | Sub::Text(text) => self.buf_mut().push_str(text), 194 | Sub::Fmt(value) => { 195 | let _ = write!(self.buf_mut(), "{value}"); 196 | } 197 | Sub::Cb(cb) => cb(self), 198 | } 199 | } 200 | } 201 | } 202 | self.indent = ambient_indent; 203 | } 204 | } 205 | 206 | impl fmt::Display for SourceWriter { 207 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 208 | let mut last_was_empty = true; 209 | for Line { indent, data } in &self.lines { 210 | if !data.is_empty() { 211 | for _ in 0..*indent { 212 | f.write_char(' ')?; 213 | } 214 | f.write_str(data)?; 215 | f.write_char('\n')?; 216 | 217 | last_was_empty = false; 218 | } else { 219 | if !last_was_empty { 220 | f.write_char('\n')?; 221 | } 222 | last_was_empty = true; 223 | } 224 | } 225 | 226 | Ok(()) 227 | } 228 | } 229 | 230 | struct Template<'tpl> { 231 | tokens: Vec>, 232 | } 233 | 234 | enum Token<'tpl> { 235 | Newline { indent: u32 }, 236 | Text(&'tpl str), 237 | Var(&'tpl str), 238 | } 239 | 240 | impl<'tpl> Template<'tpl> { 241 | fn parse(tpl: &'tpl str, _opts: &Options) -> Template<'tpl> { 242 | let (tpl, indent) = match tpl.strip_prefix('\n') { 243 | Some(tpl) => { 244 | let indent = tpl.find(|c| c != ' ').unwrap_or(tpl.len()); 245 | (tpl, indent) 246 | } 247 | None => { 248 | assert!( 249 | !tpl.contains('\n'), 250 | "non-multiline templates must not contain newlines" 251 | ); 252 | (tpl, 0) 253 | } 254 | }; 255 | 256 | let mut tokens = Vec::new(); 257 | for (i, mut line) in tpl.split('\n').enumerate() { 258 | let indent = line 259 | .find(|c| c != ' ') 260 | .unwrap_or(line.len()) 261 | .saturating_sub(indent); 262 | line = line[indent..].trim(); 263 | if i != 0 { 264 | tokens.push(Token::Newline { 265 | indent: indent as u32, 266 | }); 267 | } 268 | 269 | while !line.is_empty() { 270 | match line.find('$') { 271 | Some(dollar) => { 272 | if line[dollar + 1..].starts_with('$') { 273 | tokens.push(Token::Text(&line[dollar + 1..])); 274 | line = &line[dollar + 2..]; 275 | continue; 276 | } 277 | 278 | let text = &line[..dollar]; 279 | line = &line[dollar + 1..]; 280 | if !text.is_empty() { 281 | tokens.push(Token::Text(text)) 282 | } 283 | 284 | match line.chars().next() { 285 | None => panic!("expected character after $"), 286 | Some('a'..='z' | 'A'..='Z' | '_') => { 287 | let end = line 288 | .find(|c: char| !(c == '_' || c.is_ascii_alphanumeric())) 289 | .unwrap_or(line.len()); 290 | 291 | tokens.push(Token::Var(&line[..end])); 292 | line = &line[end..]; 293 | } 294 | Some('{') => { 295 | let end = line.find('}').expect("unclosed ${...}"); 296 | 297 | let var = &line[1..end - 1]; 298 | assert!(!var.is_empty(), "missing var name in ${{...}}"); 299 | 300 | tokens.push(Token::Var(&line[1..end])); 301 | line = &line[end + 1..]; 302 | } 303 | Some(c) => panic!("unexpected character after $: {c:?}"), 304 | } 305 | } 306 | None => { 307 | tokens.push(Token::Text(line)); 308 | line = ""; 309 | } 310 | }; 311 | } 312 | } 313 | 314 | Template { tokens } 315 | } 316 | } 317 | -------------------------------------------------------------------------------- /pzc/src/main.rs: -------------------------------------------------------------------------------- 1 | //! Compiler driver binary. 2 | 3 | use std::collections::HashMap; 4 | use std::env; 5 | use std::fmt; 6 | use std::fs; 7 | use std::io::Write; 8 | use std::path::Path; 9 | use std::path::PathBuf; 10 | use std::process::Command; 11 | use std::process::Stdio; 12 | 13 | use clap::Arg; 14 | use clap::ArgAction; 15 | use clap::CommandFactory; 16 | use clap::FromArgMatches; 17 | use ilex::report::Report; 18 | use pz::prost::Message; 19 | 20 | use pz::proto::plugin; 21 | 22 | use pzc::ir; 23 | use pzc::syn; 24 | 25 | #[derive(clap::Parser, Debug)] 26 | #[command(about, disable_help_flag(true), arg_required_else_help(true))] 27 | struct Pzc { 28 | /// Prints this help. 29 | #[arg(long, short)] 30 | help: bool, 31 | 32 | /// Prints the version. 33 | #[arg(long, short = 'V')] 34 | version: bool, 35 | 36 | /// What plugin to execute; this can either be the name of a built-in plugin, 37 | /// or the path to a plugin binary. 38 | #[arg(long)] 39 | plugin: Option, 40 | 41 | /// Where to output the generated files to; defaults to the current directory. 42 | #[arg(long)] 43 | output_dir: Option, 44 | 45 | /// Bundle files to use for resolving imports. 46 | #[arg(long = "extern")] 47 | bundles: Vec, 48 | 49 | /// The `.pz` files to pass to the plugin. 50 | files: Vec, 51 | } 52 | 53 | fn expect( 54 | report: &Report, 55 | msg: impl fmt::Display, 56 | res: Result, 57 | ) -> Result { 58 | match res { 59 | Ok(x) => Ok(x), 60 | Err(e) => { 61 | report.error(format_args!("{msg}: {e}")); 62 | report.fatal() 63 | } 64 | } 65 | } 66 | 67 | fn run_plugin( 68 | plugin: &Path, 69 | req: &plugin::Request, 70 | report: &Report, 71 | ) -> Result { 72 | let mut child = expect( 73 | report, 74 | format_args!("could not spawn plugin {}", plugin.display()), 75 | Command::new(plugin) 76 | .stdin(Stdio::piped()) 77 | .stdout(Stdio::piped()) 78 | .stderr(Stdio::inherit()) 79 | .env("RUST_BACKTRACE", "1") 80 | .spawn(), 81 | )?; 82 | 83 | expect( 84 | report, 85 | "could not send request to plugin", 86 | child.stdin.take().unwrap().write_all(&req.encode_to_vec()), 87 | )?; 88 | 89 | let exit = expect( 90 | report, 91 | "plugin did not exit successfully", 92 | child.wait_with_output(), 93 | )?; 94 | 95 | if exit.status.code() != Some(0) { 96 | expect( 97 | report, 98 | "plugin returned abnormally", 99 | Err(format_args!("$? = {:?}", exit.status)), 100 | )?; 101 | } 102 | 103 | expect( 104 | report, 105 | "plugin returned malformed response", 106 | plugin::Response::decode(exit.stdout.as_slice()), 107 | ) 108 | } 109 | 110 | fn main() { 111 | match env::var("_PZ_SELF_EXEC").as_deref() { 112 | Ok("bundle") => pz_plugins::bundle_plugin(), 113 | Ok("rust") => pz_plugins::rust_plugin(), 114 | _ => {} 115 | } 116 | 117 | let mut ctx = ilex::Context::new(); 118 | let report = ctx.new_report(); 119 | let options = ilex::ice::Options { 120 | show_backtrace: env::var_os("PZ_BRACKTRACE").map(|val| val != "0"), 121 | what_panicked: Some("the compiler".into()), 122 | report_bugs_at: Some("https://github.com/mcy/pz/issues".into()), 123 | extra_notes: Vec::new(), 124 | }; 125 | 126 | let result = 127 | ilex::ice::handle(&mut ctx, &report, options, |ctx| pzc(ctx, &report)); 128 | if let Err(e) = result { 129 | e.terminate(); 130 | } 131 | } 132 | 133 | fn pzc(icx: &ilex::Context, report: &Report) -> Result<(), ilex::Fatal> { 134 | let _dbg = icx.use_for_debugging_spans(); 135 | 136 | match env::var("_PZ_SELF_EXEC").as_deref() { 137 | Ok("bundle") => pz_plugins::bundle_plugin(), 138 | Ok("rust") => pz_plugins::rust_plugin(), 139 | _ => {} 140 | } 141 | 142 | let args = env::args_os().collect::>(); 143 | let mut plugin_name = None; 144 | for (i, arg) in args.iter().enumerate() { 145 | plugin_name = if arg == "--plugin" { 146 | args.get(i + 1).and_then(|s| s.to_str()) 147 | } else if let Some(arg) = 148 | arg.to_str().filter(|s| s.starts_with("--plugin=")) 149 | { 150 | arg.strip_prefix("--plugin=") 151 | } else { 152 | continue; 153 | }; 154 | 155 | break; 156 | } 157 | 158 | let plugin = match plugin_name { 159 | plugin @ (None | Some("bundle") | Some("rust")) => { 160 | env::set_var("_PZ_SELF_EXEC", plugin.unwrap_or("bundle")); 161 | env::current_exe().unwrap() 162 | } 163 | Some(plugin) => plugin.into(), 164 | }; 165 | 166 | let req = plugin::Request { 167 | value: Some(plugin::request::Value::About(plugin::AboutRequest {})), 168 | }; 169 | let resp = match run_plugin(&plugin, &req, report)?.value { 170 | Some(plugin::response::Value::About(a)) => a, 171 | _ => { 172 | report 173 | .error("plugin returned malformed response: expected AboutResponse"); 174 | return report.fatal(); 175 | } 176 | }; 177 | 178 | let mut plugin_command = Pzc::command().help_template(format!( 179 | "\ 180 | Usage: {{name}} {plugin}[OPTIONS] 181 | 182 | Options: 183 | {{options}} 184 | ", 185 | plugin = plugin_name 186 | .map(|p| format!("--plugin {p:?} ")) 187 | .unwrap_or_default() 188 | )); 189 | for opt in &resp.options { 190 | let name = format!("{}.{}", resp.name(), opt.name()); 191 | plugin_command = plugin_command.arg( 192 | Arg::new(name.clone()) 193 | .long(name) 194 | .action(ArgAction::Set) 195 | .value_parser(clap::value_parser!(String)) 196 | .value_name("ARG") 197 | .help(opt.help().to_string()), 198 | ); 199 | } 200 | 201 | let opts = plugin_command 202 | .clone() 203 | .try_get_matches() 204 | .and_then(|opts| Ok((Pzc::from_arg_matches(&opts)?, opts))); 205 | let (opts, plugin_opts) = match opts { 206 | Ok(opts) => opts, 207 | Err(e) => { 208 | use clap::error::ErrorKind::*; 209 | if matches!( 210 | e.kind(), 211 | DisplayHelp | DisplayVersion | DisplayHelpOnMissingArgumentOrSubcommand 212 | ) { 213 | e.exit(); 214 | } 215 | 216 | let text = e.to_string(); 217 | let message = text.trim_start_matches("error: "); 218 | let message = 219 | message[..message.find("Usage: pz").unwrap_or(message.len())].trim(); 220 | 221 | report.error(message); 222 | return report.fatal(); 223 | } 224 | }; 225 | 226 | if opts.help { 227 | plugin_command.print_help().unwrap(); 228 | return Ok(()); 229 | } 230 | 231 | if opts.version { 232 | eprintln!( 233 | "pz v{} / {} v{}", 234 | env!("CARGO_PKG_VERSION"), 235 | resp.name(), 236 | resp.version() 237 | ); 238 | return Ok(()); 239 | } 240 | 241 | let mut options = HashMap::new(); 242 | for opt in &resp.options { 243 | let name = format!("{}.{}", resp.name(), opt.name()); 244 | if let Some(val) = plugin_opts.get_one::(&name) { 245 | options.insert(opt.name().to_string(), val.to_string()); 246 | } 247 | } 248 | 249 | if opts.files.is_empty() { 250 | report.error("missing input filename"); 251 | return report.fatal(); 252 | } 253 | 254 | let contents = opts 255 | .files 256 | .iter() 257 | .filter_map(|path| icx.open_file(path, report).ok()) 258 | .collect::>(); 259 | report.fatal_or(())?; 260 | 261 | let bundles = opts 262 | .bundles 263 | .iter() 264 | .filter_map(|path| match fs::read(path) { 265 | Ok(data) => match pz::proto::Bundle::decode(&*data) { 266 | Ok(b) => Some((path.to_string_lossy().into_owned(), b)), 267 | Err(e) => { 268 | report 269 | .error(format_args!("could not process --extern argument: {e}")); 270 | None 271 | } 272 | }, 273 | 274 | Err(e) => { 275 | report.error(format_args!("could not process --extern argument: {e}")); 276 | None 277 | } 278 | }) 279 | .collect::>(); 280 | report.fatal_or(())?; 281 | 282 | let tokens = contents 283 | .iter() 284 | .filter_map(|file| syn::lex(*file, report).ok()) 285 | .collect::>(); 286 | report.fatal_or(())?; 287 | 288 | let files = tokens 289 | .iter() 290 | .filter_map(|file| syn::PzFile::parse(file, report).ok()) 291 | .collect::>(); 292 | report.fatal_or(())?; 293 | 294 | let rcx = ir::ResolveCtx::new(icx, report); 295 | let bundle = rcx.resolve(&bundles, &files); 296 | report.fatal_or(())?; 297 | 298 | let (bundle_proto, spans) = bundle.unwrap().to_proto(icx); 299 | let req = plugin::Request { 300 | value: Some(plugin::request::Value::Codegen(plugin::CodegenRequest { 301 | requested_indices: (0..bundle_proto.types.len() as u32).collect(), 302 | bundle: Some(bundle_proto), 303 | options, 304 | debug: Some(env::var_os("PZ_DEBUG").is_some()), 305 | })), 306 | }; 307 | 308 | let resp = match run_plugin(&plugin, &req, report)?.value { 309 | Some(plugin::response::Value::Codegen(a)) => a, 310 | _ => { 311 | report 312 | .error("plugin returned malformed response: expected CodegenResponse"); 313 | return report.fatal(); 314 | } 315 | }; 316 | 317 | for diagnostic in &resp.report { 318 | let mut d = match diagnostic.kind() { 319 | plugin::diagnostic::Kind::Error => report.error(diagnostic.message()), 320 | plugin::diagnostic::Kind::Warning => report.warn(diagnostic.message()), 321 | }; 322 | for snippet in &diagnostic.snippets { 323 | if snippet.is_remark() { 324 | d = d.remark(spans[&snippet.span()], snippet.message()); 325 | } else { 326 | d = d.saying(spans[&snippet.span()], snippet.message()); 327 | } 328 | } 329 | for note in &diagnostic.notes { 330 | d = d.note(note); 331 | } 332 | } 333 | report.fatal_or(())?; 334 | 335 | for file in &resp.files { 336 | let mut path = opts.output_dir.clone().unwrap_or(PathBuf::new()); 337 | path.push(file.path()); 338 | 339 | if let Err(e) = fs::write(&path, file.content()) { 340 | report.error(format_args!( 341 | "could not write output {}: {e}", 342 | path.display() 343 | )); 344 | } 345 | } 346 | 347 | report.fatal_or(()) 348 | } 349 | -------------------------------------------------------------------------------- /rust/plugin/src/rust/fields/mod.rs: -------------------------------------------------------------------------------- 1 | //! Field codegen (accessors, storage, etc). 2 | 3 | use pz::proto::field::Type as TypeEnum; 4 | use pz::proto::r#type::Kind; 5 | 6 | use crate::emit::SourceWriter; 7 | use crate::rust::names::ident; 8 | use crate::Field; 9 | 10 | use super::names; 11 | 12 | mod scalar; 13 | mod str; 14 | mod submsg; 15 | 16 | #[derive(Copy, Clone, PartialEq, Eq)] 17 | #[allow(clippy::enum_variant_names)] 18 | pub enum Where { 19 | TypeImpl, 20 | ViewImpl, 21 | MutImpl, 22 | } 23 | 24 | pub struct GenField<'ccx> { 25 | gen: Box, 26 | pub field: Field<'ccx>, 27 | #[allow(unused)] 28 | pub hasbit: Option, 29 | } 30 | 31 | impl<'ccx> GenField<'ccx> { 32 | fn common_vars( 33 | &self, 34 | w: &mut SourceWriter, 35 | cb: impl FnOnce(&mut SourceWriter), 36 | ) { 37 | w.with_vars( 38 | vars! { 39 | name: self.field.name(), 40 | "#name": ident(self.field.name()), 41 | Name: ident(heck::AsPascalCase(self.field.name())), 42 | __name: names::field_name_type_name(self.field), 43 | number: self.field.number().unwrap_or(0), 44 | idx: self.field.index(), 45 | raw_name: self.field.name(), 46 | Field: |w| match self.field.ty() { 47 | (TypeEnum::I32, _) => w.write("__s::primitive::i32"), 48 | (TypeEnum::U32, _) => w.write("__s::primitive::u32"), 49 | (TypeEnum::F32, _) => w.write("__s::primitive::f32"), 50 | (TypeEnum::I64, _) => w.write("__s::primitive::i64"), 51 | (TypeEnum::U64, _) => w.write("__s::primitive::u64"), 52 | (TypeEnum::F64, _) => w.write("__s::primitive::f64"), 53 | (TypeEnum::Bool, _) => w.write("__s::primitive::bool"), 54 | (TypeEnum::String, _) => w.write("__rt::String"), 55 | (TypeEnum::Type, Some(t)) => w.emit(vars!{ Type: names::type_name(t), }, "$Type"), 56 | (t, _) => panic!("unsupported type: {t:?}"), 57 | }, 58 | field: |w| { 59 | if self.field.parent().kind() == Kind::Choice { 60 | w.emit(vars! {}, "unsafe { &self.ptr.as_ref().union.$name }") 61 | } else { 62 | w.emit(vars! {}, "unsafe { &self.ptr.as_ref().$name }") 63 | } 64 | }, 65 | field_mut: |w| { 66 | if self.field.parent().kind() == Kind::Choice { 67 | w.emit(vars! {}, "unsafe { &mut self.ptr.as_mut().union.$name }") 68 | } else { 69 | w.emit(vars! {}, "unsafe { &mut self.ptr.as_mut().$name }") 70 | } 71 | }, 72 | }, 73 | cb, 74 | ) 75 | } 76 | 77 | pub fn in_impls(&self, w: &mut SourceWriter) { 78 | self.common_vars(w, |w| self.gen.in_impls(self.field, w)); 79 | } 80 | pub fn in_storage(&self, w: &mut SourceWriter) { 81 | self.common_vars(w, |w| self.gen.in_storage(self.field, w)); 82 | } 83 | pub fn in_variants(&self, w: &mut SourceWriter) { 84 | self.common_vars(w, |w| self.gen.in_variants(self.field, w)); 85 | } 86 | pub fn in_storage_init(&self, w: &mut SourceWriter) { 87 | self.common_vars(w, |w| self.gen.in_storage_init(self.field, w)); 88 | } 89 | pub fn in_ref_methods(&self, at: Where, w: &mut SourceWriter) { 90 | self.common_vars(w, |w| self.gen.in_ref_methods(self.field, at, w)); 91 | } 92 | pub fn in_mut_methods(&self, at: Where, w: &mut SourceWriter) { 93 | self.common_vars(w, |w| self.gen.in_mut_methods(self.field, at, w)) 94 | } 95 | pub fn in_debug(&self, w: &mut SourceWriter) { 96 | self.common_vars(w, |w| self.gen.in_debug(self.field, w)) 97 | } 98 | } 99 | 100 | #[allow(unused)] 101 | trait GenFieldImpl { 102 | fn in_impls(&self, field: Field, w: &mut SourceWriter) { 103 | w.emit( 104 | vars! { How: if field.is_repeated() { "Rep" } else { "Opt" } }, 105 | r#" 106 | type $__name = __rt::field!($name); 107 | impl __r::Field<$__name> for $Type { 108 | type Type = __r::$How<$Field>; 109 | type Name = $__name; 110 | const NUMBER: __s::primitive::i32 = $number; 111 | const INDEX: __s::primitive::usize = $idx; 112 | const NAME: &'static __s::primitive::str = "$name"; 113 | } 114 | "#, 115 | ) 116 | } 117 | 118 | fn in_storage(&self, field: Field, w: &mut SourceWriter) { 119 | match field.is_repeated() { 120 | false => w.write( 121 | " 122 | pub(in super) ${#name}: <$Field as __z::Type>::__Storage<__z::Seal>, 123 | ", 124 | ), 125 | true => w.write( 126 | " 127 | pub(in super) ${#name}: __z::AVec<<$Field as __z::Type>::__Storage<__z::Seal>>, 128 | ", 129 | ), 130 | } 131 | } 132 | 133 | fn in_variants(&self, field: Field, w: &mut SourceWriter) { 134 | match field.is_repeated() { 135 | false => w.write( 136 | " 137 | $Name(__r::View<'proto, $Field, Which>), 138 | ", 139 | ), 140 | true => w.write( 141 | " 142 | $Name(__r::View<'proto, __r::Rep<$Field>, Which>), 143 | ", 144 | ), 145 | } 146 | } 147 | 148 | fn in_storage_init(&self, field: Field, w: &mut SourceWriter) {} 149 | 150 | fn in_ref_methods(&self, field: Field, at: Where, w: &mut SourceWriter) { 151 | match field.is_repeated() { 152 | false => w.emit( 153 | vars! { 154 | self: if at == Where::TypeImpl { "&self" } else { "self" }, 155 | lt: if at == Where::TypeImpl { "_" } else { "proto" }, 156 | }, 157 | r" 158 | $deprecated 159 | pub fn ${#name}($self) -> $Ref<'$lt, $Field> { 160 | self.${name}_or().unwrap_or_default() 161 | } 162 | $deprecated 163 | pub fn ${name}_or($self) -> $Option<$Ref<'$lt, $Field>> { 164 | self.get($__name{}) 165 | } 166 | ", 167 | ), 168 | true => w.emit( 169 | vars! { 170 | self: if at == Where::TypeImpl { "&self" } else { "self" }, 171 | lt: if at == Where::TypeImpl { "_" } else { "proto" }, 172 | }, 173 | r" 174 | $deprecated 175 | pub fn ${#name}($self) -> $Slice<'$lt, $Field> { 176 | self.get($__name{}) 177 | } 178 | $deprecated 179 | pub fn ${name}_at($self, idx: usize) -> $Ref<'$lt, $Field> { 180 | self.$name().at(idx) 181 | } 182 | ", 183 | ), 184 | } 185 | } 186 | 187 | fn in_mut_methods(&self, field: Field, at: Where, w: &mut SourceWriter) { 188 | match field.is_repeated() { 189 | false => w.emit( 190 | vars! { 191 | self: if at == Where::TypeImpl { "&mut self" } else { "mut self" }, 192 | as_mut: if at == Where::TypeImpl { "self.as_mut()" } else { "self" }, 193 | lt: if at == Where::TypeImpl { "_" } else { "proto" }, 194 | }, 195 | r" 196 | $deprecated 197 | pub fn ${name}_mut($self) -> $Mut<'$lt, $Field> { 198 | self.${name}_mut_or().into_inner() 199 | } 200 | $deprecated 201 | pub fn ${name}_mut_or($self) -> __rt::OptMut<'$lt, $Field> { 202 | self.get_mut($__name{}) 203 | } 204 | $deprecated 205 | pub fn set_${name}($self, value: impl __r::Set<__r::Opt<$Field>>) -> __r::Mut<'$lt, $Type> { 206 | value.apply_to(self.as_mut().${name}_mut_or()); 207 | $as_mut 208 | } 209 | ", 210 | ), 211 | true => w.emit( 212 | vars! { 213 | self: if at == Where::TypeImpl { "&mut self" } else { "mut self" }, 214 | as_mut: if at == Where::TypeImpl { "self.as_mut()" } else { "self" }, 215 | lt: if at == Where::TypeImpl { "_" } else { "proto" }, 216 | }, 217 | r" 218 | $deprecated 219 | pub fn ${name}_mut($self) -> $Repeated<'$lt, $Field> { 220 | self.get_mut($__name{}) 221 | } 222 | $deprecated 223 | pub fn set_${name}($self, value: impl __r::Set<__r::Rep<$Field>>) -> __r::Mut<'$lt, $Type> { 224 | value.apply_to(self.as_mut().${name}_mut()); 225 | $as_mut 226 | } 227 | ", 228 | ), 229 | } 230 | } 231 | 232 | fn in_debug(&self, field: Field, w: &mut SourceWriter) {} 233 | } 234 | 235 | pub struct FieldGenerators<'ccx> { 236 | pub num_hasbits: u32, 237 | pub fields: Vec>, 238 | } 239 | 240 | impl<'ccx> FieldGenerators<'ccx> { 241 | pub fn build(fields: impl IntoIterator>) -> Self { 242 | let mut generators = Self { 243 | num_hasbits: 0, 244 | fields: Vec::new(), 245 | }; 246 | 247 | for field in fields { 248 | let gen: Box = match (field.ty(), field.is_repeated()) { 249 | ((TypeEnum::String, _), false) => Box::new(str::Singular), 250 | ((TypeEnum::String, _), true) => Box::new(str::Repeated), 251 | ((TypeEnum::Type, Some(submsg)), false) => match submsg.kind() { 252 | Kind::Message | Kind::Choice => Box::new(submsg::Singular), 253 | Kind::Enum => Box::new(scalar::Singular), 254 | _ => { 255 | field 256 | .ccx() 257 | .warn("sorry: cannot generate code for this kind of field yet") 258 | .at(field.span().unwrap()); 259 | continue; 260 | } 261 | }, 262 | ((TypeEnum::Type, Some(submsg)), true) => match submsg.kind() { 263 | Kind::Message | Kind::Choice => Box::new(submsg::Repeated), 264 | Kind::Enum => Box::new(scalar::Repeated), 265 | _ => { 266 | field 267 | .ccx() 268 | .warn("sorry: cannot generate code for this kind of field yet") 269 | .at(field.span().unwrap()); 270 | continue; 271 | } 272 | }, 273 | ((TypeEnum::Foreign, _), _) => unreachable!(), 274 | (_, false) => Box::new(scalar::Singular), 275 | (_, true) => Box::new(scalar::Repeated), 276 | }; 277 | 278 | let needs_hasbit = 279 | field.parent().kind() != Kind::Choice && !field.is_repeated(); 280 | generators.fields.push(GenField { 281 | gen, 282 | field, 283 | hasbit: needs_hasbit.then(|| { 284 | generators.num_hasbits += 1; 285 | generators.num_hasbits - 1 286 | }), 287 | }); 288 | } 289 | 290 | generators 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /rust/src/rep/mod.rs: -------------------------------------------------------------------------------- 1 | //! Wrappers for field values. 2 | 3 | use std::fmt; 4 | use std::marker::PhantomData; 5 | use std::ptr::NonNull; 6 | 7 | use crate::arena::AVec; 8 | use crate::arena::RawArena; 9 | use crate::reflect; 10 | use crate::reflect::MutView; 11 | use crate::reflect::RefView; 12 | use crate::reflect::Rep; 13 | use crate::reflect::Set; 14 | use crate::seal::Seal; 15 | use crate::Mut; 16 | use crate::Type; 17 | 18 | mod eq; 19 | mod index; 20 | mod iter; 21 | 22 | pub use index::RepIndex; 23 | pub use iter::Iter; 24 | pub use iter::IterMut; 25 | 26 | type Elem = ::__Storage; 27 | 28 | /// An immutable slice of a [`Repeated`] field. This is roughly equivalent to 29 | /// a `&[T]`. 30 | pub struct Slice<'a, T: Type + ?Sized> { 31 | ptr: NonNull>, 32 | len: usize, 33 | _ph: PhantomData<&'a T>, 34 | } 35 | 36 | impl<'a, T: Type + ?Sized> Slice<'a, T> { 37 | /// Returns whether this `Slice` has a length of zero. 38 | pub fn is_empty(&self) -> bool { 39 | self.len == 0 40 | } 41 | 42 | /// Returns the length of this `Slice`. 43 | pub fn len(&self) -> usize { 44 | self.len 45 | } 46 | 47 | /// Gets a subslice of this slice (or a single element). 48 | /// 49 | /// Returns `None` if the range is out of bounds. 50 | pub fn get(self, idx: Range) -> Option> { 51 | unsafe { idx.__get(self.ptr, self.len) } 52 | } 53 | 54 | /// Gets a subslice of this slice (or a single element). 55 | /// 56 | /// # Panics 57 | /// 58 | /// Panics if the index is out of bounds. 59 | pub fn at(self, idx: Range) -> Range::Ref<'a, T> { 60 | match self.get(idx.clone()) { 61 | Some(v) => v, 62 | None => panic!( 63 | "slice index out of bounds: got {idx:?} but expected 0..{}", 64 | self.len() 65 | ), 66 | } 67 | } 68 | 69 | /// Returns an iterator over this slice. 70 | pub fn iter(&self) -> Iter { 71 | self.into_iter() 72 | } 73 | 74 | #[doc(hidden)] 75 | pub(crate) unsafe fn from_raw_parts( 76 | ptr: NonNull>, 77 | len: usize, 78 | ) -> Self { 79 | Self { 80 | ptr, 81 | len, 82 | _ph: PhantomData, 83 | } 84 | } 85 | } 86 | 87 | impl Clone for Slice<'_, T> { 88 | fn clone(&self) -> Self { 89 | *self 90 | } 91 | } 92 | impl Copy for Slice<'_, T> {} 93 | 94 | impl Default for Slice<'_, T> { 95 | fn default() -> Self { 96 | Self { 97 | ptr: NonNull::dangling(), 98 | len: 0, 99 | _ph: PhantomData, 100 | } 101 | } 102 | } 103 | 104 | impl<'a, T: Type> RefView<'a> for Slice<'a, T> { 105 | type Target = Rep; 106 | 107 | fn as_ref(&self) -> Slice { 108 | *self 109 | } 110 | } 111 | 112 | /// An mutable slice of a [`Repeated`] field. This is roughly equivalent to 113 | /// a `&mut [T]`. 114 | pub struct SliceMut<'a, T: Type + ?Sized> { 115 | slice: Slice<'a, T>, 116 | arena: RawArena, 117 | _ph: PhantomData<&'a mut T>, 118 | } 119 | 120 | impl<'a, T: Type + ?Sized> SliceMut<'a, T> { 121 | /// Reborrows this slice as a shared slice. 122 | pub fn as_ref(&self) -> Slice<'_, T> { 123 | self.slice 124 | } 125 | 126 | /// Converts this slice into a shared slice. 127 | /// 128 | /// Note that unlike `as_ref()`, this function consumes the slice to give it 129 | /// the longest possible lifetime. 130 | pub fn into_ref(self) -> Slice<'a, T> { 131 | self.slice 132 | } 133 | 134 | /// Reborrows this slice as a mutable slice. 135 | pub fn as_mut(&mut self) -> SliceMut<'_, T> { 136 | SliceMut { 137 | slice: self.slice, 138 | arena: self.arena, 139 | _ph: PhantomData, 140 | } 141 | } 142 | 143 | /// Returns whether this `SliceMut` has a length of zero. 144 | pub fn is_empty(&self) -> bool { 145 | self.as_ref().is_empty() 146 | } 147 | 148 | /// Returns the length of this `SliceMut`. 149 | pub fn len(&self) -> usize { 150 | self.as_ref().len() 151 | } 152 | 153 | /// Gets a subslice of this slice (or a single element). 154 | /// 155 | /// Returns `None` if the range is out of bounds. 156 | pub fn get(self, idx: Range) -> Option> { 157 | self.into_ref().get(idx) 158 | } 159 | 160 | /// Gets a mutable subslice of this slice (or a single element). 161 | /// 162 | /// Returns `None` if the range is out of bounds. 163 | pub fn get_mut( 164 | self, 165 | idx: Range, 166 | ) -> Option> { 167 | unsafe { idx.__get_mut(self.slice.ptr, self.slice.len, self.arena) } 168 | } 169 | 170 | /// Gets a subslice of this slice (or a single element). 171 | /// 172 | /// # Panics 173 | /// 174 | /// Panics if the index is out of bounds. 175 | pub fn at(self, idx: Range) -> Range::Ref<'a, T> { 176 | self.into_ref().at(idx) 177 | } 178 | 179 | /// Gets a mutable subslice of this slice (or a single element). 180 | /// 181 | /// # Panics 182 | /// 183 | /// Panics if the index is out of bounds. 184 | pub fn at_mut(self, idx: Range) -> Range::Mut<'a, T> { 185 | let len = self.len(); 186 | match self.get_mut(idx.clone()) { 187 | Some(v) => v, 188 | None => { 189 | panic!("slice index out of range: got {idx:?} but expected 0..{len}") 190 | } 191 | } 192 | } 193 | 194 | /// Returns an iterator over this slice. 195 | pub fn iter(&self) -> Iter { 196 | self.as_ref().into_iter() 197 | } 198 | 199 | /// Returns a mutable iterator over this slice. 200 | pub fn iter_mut(&mut self) -> IterMut { 201 | self.as_mut().into_iter() 202 | } 203 | 204 | #[doc(hidden)] 205 | pub(crate) unsafe fn from_raw_parts( 206 | ptr: NonNull>, 207 | len: usize, 208 | arena: RawArena, 209 | ) -> Self { 210 | Self { 211 | slice: Slice::from_raw_parts(ptr, len), 212 | arena, 213 | _ph: PhantomData, 214 | } 215 | } 216 | } 217 | 218 | /// An mutable slice of a [`Repeated`] field. This is roughly equivalent to 219 | /// a `&mut Vec`. 220 | pub struct Repeated<'a, T: Type + ?Sized> { 221 | raw: &'a mut AVec>, 222 | arena: RawArena, 223 | } 224 | 225 | impl<'a, T: Type + ?Sized> Repeated<'a, T> { 226 | /// Returns whether this repeated field has a length of zero. 227 | pub fn is_empty(&self) -> bool { 228 | self.as_ref().is_empty() 229 | } 230 | 231 | /// Returns the length of this repeated field. 232 | pub fn len(&self) -> usize { 233 | self.as_ref().len() 234 | } 235 | 236 | /// Returns the capacity of this repeated field. 237 | pub fn capacity(&self) -> usize { 238 | self.raw.cap() 239 | } 240 | 241 | /// Reserves space in this repeated field for adding `n` more elements without 242 | /// resizing the underlying buffer. 243 | pub fn reserve(&mut self, n: usize) { 244 | let wanted_cap = self.len().saturating_add(n); 245 | if self.capacity() >= wanted_cap { 246 | return; 247 | } 248 | 249 | self.raw.grow(Some(wanted_cap), self.arena) 250 | } 251 | 252 | /// Adds a new, default element to this repeated field, returning a mutator 253 | /// for it. 254 | /// 255 | /// # Memory Usage Footguns 256 | /// 257 | /// This function and [`Repeated::push()`] are generally not recommended 258 | /// without first calling [`Repeated::reserve()`] first. This is because 259 | /// although a [`Repeated`] works like a [`Vec`], resized memory generally 260 | /// isn't freed until the whole message is destroyed. Naive use of these 261 | /// functions can result in quadratic memory usage. 262 | pub fn add(&mut self) -> Mut<'_, T> { 263 | let new_len = self.len() + 1; 264 | unsafe { 265 | T::__resize(Seal, self.raw, new_len, self.arena); 266 | T::__mut( 267 | Seal, 268 | self.raw.as_ptr().unwrap_unchecked().add(new_len - 1).cast(), 269 | self.arena, 270 | ) 271 | } 272 | } 273 | 274 | /// Pushes a new value to this repeated field, returning a mutator for it. 275 | /// 276 | /// # Memory Usage Footguns 277 | /// 278 | /// This function generally isn't what you want. See related docs on 279 | /// [`Repeated::add()`]. 280 | pub fn push(&mut self, value: impl Set) -> Mut<'_, T> { 281 | let mut m = self.add(); 282 | value.apply_to(m.as_mut()); 283 | m 284 | } 285 | 286 | /// Clears this repeated field. 287 | pub fn clear(&mut self) { 288 | self.truncate(0); 289 | } 290 | 291 | /// Truncates this repeated field. 292 | /// 293 | /// If `len > self.len()`, the field is unaffected. 294 | pub fn truncate(&mut self, len: usize) { 295 | let new_len = usize::min(self.len(), len); 296 | unsafe { 297 | self.raw.set_len(new_len); 298 | } 299 | } 300 | 301 | /// Gets a subslice of this slice (or a single element). 302 | /// 303 | /// Returns `None` if the range is out of bounds. 304 | pub fn get(self, idx: Range) -> Option> { 305 | self.into_slice().get(idx) 306 | } 307 | 308 | /// Gets a mutable subslice of this slice (or a single element). 309 | /// 310 | /// Returns `None` if the range is out of bounds. 311 | pub fn get_mut( 312 | self, 313 | idx: Range, 314 | ) -> Option> { 315 | self.into_mut_slice().get_mut(idx) 316 | } 317 | 318 | /// Gets a subslice of this slice (or a single element). 319 | /// 320 | /// # Panics 321 | /// 322 | /// Panics if the index is out of bounds. 323 | pub fn at(self, idx: Range) -> Range::Ref<'a, T> { 324 | self.into_slice().at(idx) 325 | } 326 | 327 | /// Gets a mutable subslice of this slice (or a single element). 328 | /// 329 | /// # Panics 330 | /// 331 | /// Panics if the index is out of bounds. 332 | pub fn at_mut(self, idx: Range) -> Range::Mut<'a, T> { 333 | self.into_mut_slice().at_mut(idx) 334 | } 335 | 336 | /// Returns an iterator over this slice. 337 | pub fn iter(&self) -> Iter { 338 | self.as_slice().into_iter() 339 | } 340 | 341 | /// Returns a mutable iterator over this slice. 342 | pub fn iter_mut(&mut self) -> IterMut { 343 | self.as_mut_slice().into_iter() 344 | } 345 | 346 | /// Borrows this repeated field as a shared slice. 347 | pub fn as_slice(&self) -> Slice { 348 | Slice { 349 | ptr: self.raw.as_ptr().unwrap_or(NonNull::dangling()), 350 | len: self.raw.len(), 351 | _ph: PhantomData, 352 | } 353 | } 354 | 355 | /// Borrows this repeated field as a mutable slice. 356 | pub fn as_mut_slice(&mut self) -> SliceMut { 357 | SliceMut { 358 | slice: self.as_slice(), 359 | arena: self.arena, 360 | _ph: PhantomData, 361 | } 362 | } 363 | 364 | /// Converts this repeated field as a shared slice. 365 | pub fn into_slice(self) -> Slice<'a, T> { 366 | Slice { 367 | ptr: self.raw.as_ptr().unwrap_or(NonNull::dangling()), 368 | len: self.raw.len(), 369 | _ph: PhantomData, 370 | } 371 | } 372 | 373 | /// Converts this repeated field as a mutable slice. 374 | pub fn into_mut_slice(self) -> SliceMut<'a, T> { 375 | SliceMut { 376 | arena: self.arena, 377 | _ph: PhantomData, 378 | slice: self.into_slice(), 379 | } 380 | } 381 | 382 | pub(crate) unsafe fn from_raw_parts( 383 | raw: &'a mut AVec>, 384 | arena: RawArena, 385 | ) -> Self { 386 | Self { raw, arena } 387 | } 388 | } 389 | 390 | impl<'a, T: Type> MutView<'a> for Repeated<'a, T> { 391 | type Target = Rep; 392 | 393 | fn as_ref(&self) -> Slice { 394 | self.as_slice() 395 | } 396 | 397 | fn into_ref(self) -> Slice<'a, T> { 398 | self.into_slice() 399 | } 400 | 401 | fn as_mut(&mut self) -> Mut { 402 | Repeated { 403 | raw: self.raw, 404 | arena: self.arena, 405 | } 406 | } 407 | } 408 | 409 | impl fmt::Debug for Slice<'_, T> { 410 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 411 | let mut dbg = f.debug_list(); 412 | for value in self { 413 | dbg.entry(&value); 414 | } 415 | dbg.finish() 416 | } 417 | } 418 | 419 | impl fmt::Debug for SliceMut<'_, T> { 420 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 421 | fmt::Debug::fmt(&self.as_ref(), f) 422 | } 423 | } 424 | 425 | impl fmt::Debug for Repeated<'_, T> { 426 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 427 | fmt::Debug::fmt(&self.as_ref(), f) 428 | } 429 | } 430 | 431 | impl>> Set> for U { 432 | fn apply_to(self, mut m: Mut>) { 433 | m.clear(); 434 | 435 | let it = self.into_iter(); 436 | let (low, _) = it.size_hint(); 437 | m.reserve(low); 438 | 439 | for value in it { 440 | m.push(value); 441 | } 442 | } 443 | } 444 | -------------------------------------------------------------------------------- /rust/plugin/src/rust/choice.rs: -------------------------------------------------------------------------------- 1 | //! Type codegen. 2 | 3 | #![allow(unused)] 4 | 5 | use std::collections::HashMap; 6 | 7 | use pz::proto; 8 | use pz::proto::field::Type as TypeEnum; 9 | use pz::proto::r#type::Kind; 10 | 11 | use crate::emit::SourceWriter; 12 | use crate::rust::fields::FieldGenerators; 13 | use crate::rust::fields::Where; 14 | use crate::rust::message; 15 | use crate::rust::names; 16 | use crate::Type; 17 | 18 | pub fn emit(ty: Type, w: &mut SourceWriter) { 19 | let gen = FieldGenerators::build(ty.fields()); 20 | let hasbit_words = gen.num_hasbits / 32 + (gen.num_hasbits % 32 != 0) as u32; 21 | 22 | let mut ty_ptrs = ty 23 | .fields() 24 | .filter_map(|f| f.ty().1.filter(|ty| ty.kind() != Kind::Enum)) 25 | .collect::>(); 26 | ty_ptrs.sort_by(|a, b| (a.package(), a.name()).cmp(&(b.package(), b.name()))); 27 | ty_ptrs.dedup_by(|a, b| (a.package(), a.name()) == (b.package(), b.name())); 28 | 29 | w.emit( 30 | vars! { 31 | hasbit_words, 32 | NUM_TYS: ty_ptrs.len(), 33 | "Type::struct": |w| message::emit_main_struct(w), 34 | "Type::common": |w| message::emit_common_methods(w), 35 | "Type::impls": |w| message::emit_impls(w), 36 | "Type::views": |w| message::emit_view_types(w), 37 | "Type::fields": |w| for field in &gen.fields { 38 | field.in_storage(w); 39 | }, 40 | "Type::Variants": |w| for field in &gen.fields { 41 | field.in_variants(w); 42 | }, 43 | "Type::access": |w| for field in &gen.fields { 44 | field.in_ref_methods(Where::TypeImpl, w); 45 | field.in_mut_methods(Where::TypeImpl, w); 46 | w.new_line(); 47 | }, 48 | "Type::memcpys": |w| for field in &gen.fields { 49 | w.emit( 50 | vars! { 51 | n: field.field.number().unwrap(), 52 | __name: names::field_name_type_name(field.field), 53 | }, 54 | r#" 55 | $n => __r::Set::<<$Type as __r::Field<$__name>>::Type>::apply_to(src.get($__name{}), dst.get_mut($__name{})), 56 | "# 57 | ); 58 | }, 59 | "Type::field_impls": |w| for field in &gen.fields { 60 | field.in_impls(w); 61 | w.new_line(); 62 | }, 63 | "Type::debug": |w| for field in &gen.fields { 64 | field.in_debug(w); 65 | }, 66 | "Ref::common": |w| message::emit_common_ref_methods(w), 67 | "Ref::access": |w| for field in &gen.fields { 68 | field.in_ref_methods(Where::ViewImpl, w); 69 | w.new_line(); 70 | }, 71 | "Mut::common": |w| message::emit_common_mut_methods(w), 72 | "Mut::access": |w| for field in &gen.fields { 73 | field.in_ref_methods(Where::MutImpl, w); 74 | field.in_mut_methods(Where::MutImpl, w); 75 | w.new_line(); 76 | }, 77 | self_to_output_arms: |w| for field in ty.fields() { 78 | w.emit( 79 | vars! {Name: names::ident(heck::AsPascalCase(field.name())) }, 80 | " 81 | ${Type}Cases::$Name(val) => ${Type}Cases::$Name(__rt::ptr::ViewFor::as_view(val)), 82 | " 83 | ) 84 | }, 85 | make_view_arms: |w| for field in ty.fields() { 86 | w.emit( 87 | vars! { 88 | number: field.number().unwrap(), 89 | index: field.index, 90 | Name: names::ident(heck::AsPascalCase(field.name())), 91 | __name: names::field_name_type_name(field), 92 | Field: |w| {match field.ty() { 93 | (TypeEnum::I32, _) => w.write("i32"), 94 | (TypeEnum::I64, _) => w.write("i64"), 95 | (TypeEnum::U32, _) => w.write("u32"), 96 | (TypeEnum::U64, _) => w.write("u64"), 97 | (TypeEnum::F32, _) => w.write("f32"), 98 | (TypeEnum::F64, _) => w.write("f64"), 99 | (TypeEnum::Bool, _) => w.write("bool"), 100 | (TypeEnum::String, _) => w.write("__rt::Str"), 101 | (TypeEnum::Type, Some(ty)) => w.write(&names::type_name(ty).to_string()), 102 | _ => unreachable!(), 103 | }}, 104 | suffix: if field.is_repeated() { "" } else {".unwrap_unchecked()"}, 105 | }, 106 | " 107 | $number => ${Type}Cases::$Name(self.get($__name{})$suffix), 108 | " 109 | ) 110 | }, 111 | make_mut_arms: |w| for field in ty.fields() { 112 | w.emit( 113 | vars! { 114 | number: field.number().unwrap(), 115 | index: field.index, 116 | Name: names::ident(heck::AsPascalCase(field.name())), 117 | __name: names::field_name_type_name(field), 118 | Field: |w| {match field.ty() { 119 | (TypeEnum::I32, _) => w.write("i32"), 120 | (TypeEnum::I64, _) => w.write("i64"), 121 | (TypeEnum::U32, _) => w.write("u32"), 122 | (TypeEnum::U64, _) => w.write("u64"), 123 | (TypeEnum::F32, _) => w.write("f32"), 124 | (TypeEnum::F64, _) => w.write("f64"), 125 | (TypeEnum::Bool, _) => w.write("bool"), 126 | (TypeEnum::String, _) => w.write("__rt::Str"), 127 | (TypeEnum::Type, Some(ty)) => w.write(&names::type_name(ty).to_string()), 128 | _ => unreachable!(), 129 | }}, 130 | suffix: if field.is_repeated() { "" } else {".into_option().unwrap_unchecked()"}, 131 | }, 132 | " 133 | $number => ${Type}Cases::$Name(self.get_mut($__name{})$suffix), 134 | " 135 | ) 136 | }, 137 | tdp_descs: |w| for &ty in &ty_ptrs { 138 | w.emit( 139 | vars!{ Submsg: names::type_name(ty) }, 140 | " 141 | $Submsg::__tdp_info, 142 | " 143 | ); 144 | }, 145 | tdp_fields: |w| { 146 | let mut hasbit_index = 0u32; 147 | let ty_map = ty_ptrs.iter().enumerate() 148 | .map(|(i, t)| (t.proto() as *const proto::Type, i)) 149 | .collect::>(); 150 | 151 | for field in ty.fields() { 152 | let mut ty_idx = 0; 153 | let tdp_kind = match field.ty() { 154 | (TypeEnum::I32 | TypeEnum::U32, _) => "I32", 155 | (TypeEnum::I64 | TypeEnum::U64, _) => "I64", 156 | (TypeEnum::F32, _) => "F32", 157 | (TypeEnum::F64, _) => "F64", 158 | (TypeEnum::Bool, _) => "Bool", 159 | (TypeEnum::String, _) => "Str", 160 | (TypeEnum::Type, Some(ty)) => match ty.kind() { 161 | Kind::Message | Kind::Choice => { 162 | ty_idx = ty_map[&(ty.proto() as *const _)]; 163 | "Type" 164 | } 165 | Kind::Struct => todo!(), 166 | Kind::Enum => "I32", 167 | }, 168 | _ => unreachable!(), 169 | }; 170 | 171 | w.emit( 172 | vars! { 173 | hasbit_index, 174 | tdp_kind, 175 | ty_idx, 176 | name: names::ident(field.name()), 177 | number: field.number().unwrap(), 178 | raw_name: field.name(), 179 | repeated: field.is_repeated() as u32, 180 | }, 181 | " 182 | __z::tdp::FieldStorage { 183 | number: $number, 184 | flags: 185 | __z::tdp::Kind::$tdp_kind.raw() << __z::tdp::Field::KIND_SHIFT | 186 | $repeated << __z::tdp::Field::REP_SHIFT, 187 | offset: $priv::UNION_OFFSET as u32, 188 | desc: $ty_idx, 189 | hasbit: 0, 190 | }, 191 | " 192 | ); 193 | if !field.is_repeated() { 194 | hasbit_index += 1; 195 | } 196 | } 197 | }, 198 | }, 199 | r#" 200 | ${Type::struct} 201 | 202 | mod $priv { 203 | pub use super::*; 204 | 205 | ${Type::views} 206 | 207 | #[repr(C)] 208 | pub struct Storage { 209 | pub(super) which: u32, 210 | pub(super) union: Union, 211 | } 212 | 213 | #[repr(C)] 214 | pub union Union { 215 | pub(super) __unset: (), 216 | ${Type::fields} 217 | } 218 | 219 | pub const UNION_OFFSET: usize = { 220 | let align = __s::mem::align_of::<$priv::Union>(); 221 | if align < 4 { 4 } else { align } 222 | }; 223 | } 224 | 225 | impl $Type { 226 | /// The default value for [`$Type`], provided as a static constant. 227 | /// 228 | /// See [`Message::DEFAULT`][__r::Message::DEFAULT]. 229 | pub const DEFAULT: &'static Self = unsafe { &Self { 230 | ptr: $NonNull::new_unchecked(&const { $priv::Storage { 231 | which: 0, 232 | union: $priv::Union { __unset: () }, 233 | }} as *const $priv::Storage as *mut $priv::Storage), 234 | arena: $None, 235 | }}; 236 | 237 | ${Type::common} 238 | 239 | pub fn which(&self) -> i32 { 240 | self.as_ref().which() 241 | } 242 | 243 | pub fn cases(&self) -> ${Type}Cases<__r::SelectRef> { 244 | self.as_ref().cases() 245 | } 246 | 247 | pub fn cases_mut(&mut self) -> ${Type}Cases<__r::SelectMut> { 248 | self.as_mut().cases_mut() 249 | } 250 | 251 | ${Type::access} 252 | 253 | #[doc(hidden)] 254 | pub const __LAYOUT: $Layout = $Layout::new::<$priv::Storage>(); 255 | #[doc(hidden)] 256 | pub unsafe fn __raw_clear(raw: __z::tdp::Opaque) { 257 | raw.cast::<$priv::Storage>().as_mut().which = 0; 258 | } 259 | #[doc(hidden)] 260 | pub fn __tdp_info() -> __z::tdp::Desc { 261 | ::__TDP 262 | } 263 | 264 | #[doc(hidden)] 265 | fn __memcpy(mut dst: $Mut<$Type>, src: $Ref<$Type>) { 266 | match src.which() { 267 | 0 => dst.clear(), 268 | ${Type::memcpys} 269 | _ => __s::unreachable!(), 270 | } 271 | } 272 | } 273 | 274 | #[non_exhaustive] 275 | pub enum ${Ident}Cases<'proto, Which: __r::Select = __r::SelectRef> { 276 | Unset, 277 | ${Type::Variants} 278 | 279 | #[doc(hidden)] 280 | __PhantomData($PhantomData<&'proto Which>, __z::Void), 281 | } 282 | 283 | impl __z::Message for $Type { 284 | const __TDP: __z::tdp::Desc = { 285 | type Tdp = __z::tdp::DescStorage<{$NUM_FIELDS + 1}>; 286 | const STATIC: Tdp = Tdp { 287 | header: __z::tdp::DescHeader { 288 | size: { 289 | let size = $Type::__LAYOUT.size(); 290 | assert!(size <= (u32::MAX as usize)); 291 | size as u32 292 | }, 293 | 294 | descs: { 295 | const DESCS: &[fn() -> __z::tdp::Desc] = &[ 296 | $tdp_descs 297 | ]; 298 | DESCS.as_ptr() 299 | }, 300 | 301 | num_hasbit_words: 0, 302 | kind: __z::tdp::DescKind::Choice, 303 | }, 304 | 305 | fields: [ 306 | $tdp_fields 307 | __z::tdp::FieldStorage { number: 0, flags: 0, offset: 0, desc: 0, hasbit: 0 }, 308 | ], 309 | }; 310 | 311 | unsafe { STATIC.get() } 312 | }; 313 | 314 | fn __is_null(&self, _: impl __z::Sealed) -> bool { 315 | self.ptr == $NonNull::dangling() 316 | } 317 | fn __raw(_: impl __z::Sealed, ptr: __r::Ref) -> __z::tdp::Opaque { ptr.ptr.cast() } 318 | fn __arena(_: impl __z::Sealed, ptr: &mut __r::Mut) -> __z::RawArena { ptr.arena } 319 | } 320 | 321 | ${Type::impls} 322 | 323 | ${Type::field_impls} 324 | 325 | impl<'proto> $priv::Ref<'proto> { 326 | pub fn which(self) -> i32 { 327 | unsafe { self.ptr.as_ref() }.which as i32 328 | } 329 | 330 | pub fn cases(self) -> ${Type}Cases<'proto> { 331 | unsafe { 332 | match self.which() { 333 | 0 => ${Type}Cases::Unset, 334 | $make_view_arms 335 | _ => __s::unreachable!(), 336 | } 337 | } 338 | } 339 | 340 | ${Ref::common} 341 | 342 | ${Ref::access} 343 | 344 | #[doc(hidden)] 345 | pub fn __debug(self, debug: &mut __z::Debug) -> $fmt::Result { 346 | let mut count = 0; 347 | debug.start_block()?; 348 | ${Type::debug} 349 | if count != 0 { 350 | debug.comma(true)?; 351 | } 352 | debug.end_block()?; 353 | $Ok(()) 354 | } 355 | } 356 | 357 | impl<'proto> $priv::Mut<'proto> { 358 | pub fn which(&self) -> i32 { 359 | self.as_ref().which() 360 | } 361 | 362 | pub fn cases(self) -> ${Type}Cases<'proto> { 363 | self.into_ref().cases() 364 | } 365 | 366 | pub fn cases_mut(self) -> ${Type}Cases<'proto, __r::SelectMut> { 367 | unsafe { 368 | match self.which() { 369 | 0 => ${Type}Cases::Unset, 370 | $make_mut_arms 371 | _ => __s::unreachable!(), 372 | } 373 | } 374 | } 375 | 376 | ${Mut::common} 377 | 378 | ${Mut::access} 379 | } 380 | "#, 381 | ); 382 | w.new_line(); 383 | } 384 | -------------------------------------------------------------------------------- /rust/src/tdp/mod.rs: -------------------------------------------------------------------------------- 1 | //! Table-driven codec support. 2 | 3 | use std::alloc::Layout; 4 | use std::iter; 5 | use std::mem; 6 | use std::ptr::NonNull; 7 | 8 | use crate::arena::RawArena; 9 | use crate::str; 10 | 11 | pub mod parse; 12 | 13 | /// An opaque pointer to a message that can be manipulated with TDP. 14 | pub type Opaque = NonNull; 15 | 16 | /// A descriptor for a parseable type. 17 | /// 18 | /// This is essentially a vtable pointer for a Protobuf type, containing all the 19 | /// necessary information to parse and serialize it. 20 | #[derive(Copy, Clone, PartialEq, Eq)] 21 | pub struct Desc(NonNull); 22 | impl Desc { 23 | fn header(&self) -> &DescHeader { 24 | unsafe { self.0.as_ref() } 25 | } 26 | 27 | fn raw(self) -> *mut DescHeader { 28 | self.0.as_ptr() 29 | } 30 | 31 | /// Gets a valid layout for this type's storage. 32 | pub fn layout(self) -> Layout { 33 | unsafe { Layout::from_size_align_unchecked(self.header().size as usize, 8) } 34 | } 35 | 36 | /// The number of bytes in this type's hasbits block, if it has one. 37 | pub fn hasbit_bytes(self) -> usize { 38 | self.header().num_hasbit_words as usize * mem::size_of::() 39 | } 40 | 41 | /// Gets the `n`th type associated with this `DescPtr`. 42 | /// 43 | /// # Safety 44 | /// 45 | /// `idx` must be in range. 46 | pub unsafe fn desc(self, idx: u16) -> Desc { 47 | let getter: fn() -> Desc = 48 | unsafe { self.header().descs.add(idx as usize).read() }; 49 | getter() 50 | } 51 | 52 | /// Gets the kind of type this descriptor is for. 53 | pub fn kind(self) -> DescKind { 54 | self.header().kind 55 | } 56 | 57 | /// Whether this is the descriptor for a message. 58 | pub fn is_message(self) -> bool { 59 | self.kind() == DescKind::Message 60 | } 61 | 62 | /// Whether this is the descriptor for a choice. 63 | pub fn is_choice(self) -> bool { 64 | self.kind() == DescKind::Choice 65 | } 66 | 67 | /// If this type is a choice, returns which of the choice variants is 68 | /// selected. 69 | /// 70 | /// Returns `None` if this is not a choice. Returns `Some(0)` if it is but no 71 | /// variant is selected. 72 | /// 73 | /// # Safety 74 | /// 75 | /// `raw` must point to a valid, allocated value of this type. 76 | pub unsafe fn which(self, raw: Opaque) -> Option { 77 | if !self.is_choice() { 78 | return None; 79 | } 80 | Some(raw.cast::().read()) 81 | } 82 | 83 | /// If this type is a choice, replaces the currently selected variant. 84 | /// 85 | /// # Safety 86 | /// 87 | /// `raw` must point to a valid, allocated value of this type, which must be 88 | /// a choice. Note that this is a raw union tag set operation, which may cause 89 | /// type-confusion bugs. 90 | pub unsafe fn set_which(self, raw: Opaque, number: u32) -> u32 { 91 | debug_assert!(self.is_choice()); 92 | mem::replace(unsafe { raw.cast::().as_mut() }, number) 93 | } 94 | 95 | /// Returns the first field in this `Desc`. 96 | /// 97 | /// Returns `None` if this `Desc` has no fields. 98 | pub fn first_field(self) -> Option { 99 | let first = 100 | unsafe { Field(self, NonNull::new_unchecked(self.raw().add(1).cast())) }; 101 | (first.number() != 0).then_some(first) 102 | } 103 | 104 | /// Returns the `n`th field in this `Desc`. 105 | /// 106 | /// # Safety 107 | /// 108 | /// `n` must be in-range for this `Desc`. 109 | pub unsafe fn field(self, n: u16) -> Field { 110 | Field( 111 | self, 112 | NonNull::new_unchecked( 113 | self.raw().add(1).cast::().add(n as usize), 114 | ), 115 | ) 116 | } 117 | 118 | /// Returns an iterator over this `Desc`'s fields. 119 | pub fn fields(self) -> impl Iterator { 120 | let mut field = self.first_field(); 121 | iter::from_fn(move || { 122 | let ret = field?; 123 | field = Some(ret.next()).filter(|f| f.number() != 0); 124 | Some(ret) 125 | }) 126 | } 127 | 128 | /// Clears all of the fields in `raw`. 129 | /// 130 | /// # Safety 131 | /// 132 | /// `raw` must point to a valid, allocated value of this type. 133 | pub unsafe fn clear(self, raw: Opaque) { 134 | if self.is_choice() { 135 | // For choices, we just need to reset the which word. When we switch away 136 | // in init(), it will clear the incoming field value for us. 137 | self.set_which(raw, 0); 138 | return; 139 | } 140 | 141 | // Clear every field directly. The only thing we need to do is obliterate 142 | // the lengths of the repeated fields, and all of the hasbit words. 143 | raw.write_bytes(0, self.hasbit_bytes()); 144 | for field in self.fields() { 145 | if field.is_repeated() { 146 | field.cast::(raw).write(0); 147 | } 148 | } 149 | } 150 | } 151 | 152 | /// A descriptor for a `Desc`'s field. 153 | /// 154 | /// This is essentially a vtable pointer for a Protobuf type, containing all the 155 | /// necessary information to parse and serialize it. 156 | #[derive(Copy, Clone, PartialEq, Eq)] 157 | pub struct Field(Desc, NonNull); 158 | impl Field { 159 | /// Returns this field's `Desc`. 160 | pub fn parent(self) -> Desc { 161 | self.0 162 | } 163 | 164 | fn storage(&self) -> &FieldStorage { 165 | unsafe { self.1.as_ref() } 166 | } 167 | 168 | fn raw(self) -> *mut FieldStorage { 169 | self.1.as_ptr() 170 | } 171 | 172 | /// Gets the next field after this one, wrapping around if necessary. 173 | pub fn next(self) -> Field { 174 | let next = unsafe { 175 | Field(self.parent(), NonNull::new_unchecked(self.raw().add(1))) 176 | }; 177 | 178 | if next.number() == 0 { 179 | // Wrap back to the beginning. 180 | return self.parent().first_field().unwrap(); 181 | } 182 | 183 | next 184 | } 185 | 186 | /// Gets this field's number. 187 | pub fn number(self) -> u32 { 188 | self.storage().number 189 | } 190 | 191 | pub const KIND_MASK: u32 = 0b1111; 192 | pub const KIND_SHIFT: u32 = 0; 193 | 194 | /// Gets the kind of field this is. 195 | pub fn kind(self) -> Kind { 196 | let nybble = (self.storage().flags & Self::KIND_MASK) as u8; 197 | unsafe { mem::transmute::(nybble) } 198 | } 199 | 200 | pub const REP_MASK: u32 = 0b1_0000; 201 | pub const REP_SHIFT: u32 = 4; 202 | 203 | /// Gets whether this is a repeated field. 204 | pub fn is_repeated(self) -> bool { 205 | self.storage().flags & Self::REP_MASK != 0 206 | } 207 | 208 | /// The offset at which this field's storage is in an allocated value. 209 | pub fn offset(self) -> usize { 210 | self.storage().offset as usize 211 | } 212 | 213 | /// Gets this field's type. 214 | /// 215 | /// # Safety 216 | /// 217 | /// This must be a `Type`-kinded field. 218 | pub unsafe fn desc(self) -> Desc { 219 | self.parent().desc(self.storage().desc) 220 | } 221 | 222 | /// The index of the word of the hasbit vector that contains this field's 223 | /// hasbit (if it has a hasbit). 224 | pub fn hasbit_word(self) -> usize { 225 | self.storage().hasbit as usize / 32 226 | } 227 | 228 | /// The mask to extract the hasbit from the hasbit word. 229 | pub fn hasbit_mask(self) -> u32 { 230 | 1 << (self.storage().hasbit % 32) 231 | } 232 | 233 | /// Checks whether this field is set in a raw allocated value. 234 | /// 235 | /// # Safety 236 | /// 237 | /// `raw` must point to a valid, allocated value of this type. 238 | pub unsafe fn has(&self, raw: Opaque) -> bool { 239 | if let Some(which) = self.parent().which(raw) { 240 | return which == self.number(); 241 | } 242 | 243 | if self.is_repeated() { 244 | return true; 245 | } 246 | 247 | raw.cast::().add(self.hasbit_word()).read() & self.hasbit_mask() != 0 248 | } 249 | 250 | /// Initializes this field in a raw allocated value, if isn't already 251 | /// initialized. 252 | /// 253 | /// # Safety 254 | /// 255 | /// `raw` must point to a valid, allocated value of this type. 256 | #[inline(always)] 257 | pub unsafe fn init(&self, raw: Opaque, arena: RawArena) { 258 | let value = raw.add(self.offset()); 259 | if self.parent().is_choice() { 260 | if self.parent().set_which(raw, self.number()) == self.number() { 261 | return; 262 | } 263 | 264 | if self.is_repeated() { 265 | // We need to vaporize the *whole* AVec, since we don't know a 266 | // priori if whatever used to be here had a compatible layout. 267 | value.write_bytes(0, 3 * mem::size_of::()); 268 | } 269 | } else if !self.is_repeated() { 270 | // NOTE: The hasbits are always the first thing in the message 271 | // right now. 272 | let word = raw.cast::().add(self.hasbit_word()).as_mut(); 273 | if *word & self.hasbit_mask() != 0 { 274 | return; 275 | } 276 | 277 | *word |= self.hasbit_mask(); 278 | } 279 | 280 | // Nothing to do to repeated fields here. 281 | if self.is_repeated() { 282 | return; 283 | } 284 | 285 | // We need to make sure to clear the *values* now, because the actual 286 | // clear operatation only zeroes hasbits. This means that if we clear 287 | // e.g. a string field, its pointer and length will not have been reset. 288 | let to_overwrite = match self.kind() { 289 | Kind::I32 | Kind::F32 => 4, 290 | Kind::I64 | Kind::F64 => 8, 291 | Kind::Bool => 1, 292 | Kind::Str => mem::size_of::(), 293 | Kind::Type => { 294 | // Types are a little special because we need to allocate stuff. 295 | let desc = self.desc(); 296 | let ptr = value.cast::>().as_mut(); 297 | match ptr { 298 | Some(ptr) => { 299 | desc.clear(*ptr); 300 | } 301 | None => { 302 | let fresh = arena.alloc(desc.layout()); 303 | fresh.write_bytes(0, desc.layout().size()); 304 | *ptr = Some(fresh); 305 | } 306 | } 307 | 308 | return; 309 | } 310 | }; 311 | 312 | value.write_bytes(0, to_overwrite); 313 | } 314 | 315 | /// Clears this value. 316 | /// 317 | /// # Safety 318 | /// 319 | /// `raw` must point to a valid, allocated value of this type. 320 | pub unsafe fn clear(&self, raw: Opaque) { 321 | if self.parent().is_choice() { 322 | raw.cast::().write(0); 323 | return; 324 | } 325 | 326 | if !self.is_repeated() { 327 | *raw.cast::().add(self.hasbit_word()).as_mut() &= 328 | !self.hasbit_mask(); 329 | } else { 330 | // Zap the first eight bytes of the repeated field, which truncates to 331 | // zero. 332 | raw 333 | .add(self.offset()) 334 | .write_bytes(0, mem::size_of::()); 335 | } 336 | } 337 | 338 | /// Casts `raw` to a `T`, offset by this field's offset. 339 | /// 340 | /// # Safety 341 | /// 342 | /// `raw` must be a valid pointer to this field's message type, and `T` must 343 | /// be the right type for that field. 344 | #[inline(always)] 345 | pub unsafe fn cast(&self, raw: Opaque) -> NonNull { 346 | raw.add(self.offset()).cast() 347 | } 348 | } 349 | 350 | /// Storage for `Desc` global. 351 | /// 352 | /// This struct all the information needed to parse any top-level Protobuf type. 353 | /// There is a static variable of this type associated with every non-enum 354 | /// generated type, which is fed into the parser. 355 | /// 356 | /// This type should not be constructed or referred to directly, except by the 357 | /// code generator. 358 | #[repr(C)] 359 | #[derive(Debug)] 360 | pub struct DescStorage { 361 | /// The header, which contains all "type-level" information. 362 | pub header: DescHeader, 363 | /// The fields. This array must have at least one element and the final 364 | /// element's number must be zero. 365 | pub fields: [FieldStorage; FIELDS], 366 | } 367 | 368 | unsafe impl Sync for DescStorage {} 369 | impl DescStorage { 370 | /// Gets the `Desc` pointer. 371 | /// 372 | /// `Desc`s should only ever exist as global variables, so this requires a 373 | /// `'static` lifetime. 374 | /// 375 | /// # Safety 376 | /// 377 | /// This function assumes that all the relevant invariants of a `Desc` are 378 | /// observed (in other words, that this was constructed by the code 379 | /// generator or the runtime). 380 | pub const unsafe fn get(&'static self) -> Desc { 381 | Desc(NonNull::new_unchecked(self as *const _ as *mut _)) 382 | } 383 | } 384 | 385 | /// The header for a `DescStorage`. 386 | #[derive(Debug)] 387 | pub struct DescHeader { 388 | /// The size of this type's storage, in bytes; 4GB limit. 389 | pub size: u32, 390 | /// A pointer to an array of functions that return the `DescPtr` for a type 391 | /// referred to directly by this message. See `ty` under `Field`. 392 | pub descs: *const fn() -> Desc, 393 | /// The number of hasbit words in an allocated value of this type. 394 | pub num_hasbit_words: u16, 395 | /// The kind of type this descriptor is for. 396 | pub kind: DescKind, 397 | } 398 | 399 | #[repr(u8)] 400 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 401 | pub enum DescKind { 402 | Message = 0, 403 | Choice = 1, 404 | } 405 | 406 | /// Storage for one of a `Desc`'s fields. 407 | #[derive(Debug)] 408 | pub struct FieldStorage { 409 | pub number: u32, 410 | pub flags: u32, 411 | pub offset: u32, 412 | pub desc: u16, 413 | pub hasbit: u16, 414 | } 415 | 416 | #[repr(u8)] 417 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 418 | pub enum Kind { 419 | I32 = 0, 420 | I64 = 1, 421 | F32 = 2, 422 | F64 = 3, 423 | Bool = 4, 424 | Str = 5, 425 | Type = 6, 426 | } 427 | 428 | impl Kind { 429 | // Converts this `Kind` into a raw value. 430 | pub const fn raw(self) -> u32 { 431 | self as u32 432 | } 433 | } 434 | -------------------------------------------------------------------------------- /rust/src/reflect/mod.rs: -------------------------------------------------------------------------------- 1 | //! Static and dynamic reflection. 2 | 3 | use std::io::Read; 4 | use std::io::Write; 5 | use std::marker::PhantomData; 6 | 7 | use crate::arena::AVec; 8 | use crate::arena::RawArena; 9 | use crate::seal::Seal; 10 | use crate::seal::Sealed; 11 | use crate::tdp; 12 | use crate::Codec; 13 | use crate::Error; 14 | use crate::OptMut; 15 | use crate::Repeated; 16 | use crate::Slice; 17 | 18 | pub(crate) mod names; 19 | pub(crate) mod private; 20 | pub(crate) mod tuple; 21 | 22 | mod impls; 23 | mod view; 24 | 25 | pub use names::Name; 26 | pub use view::*; 27 | 28 | /// A pz type. 29 | /// 30 | /// This type is implemented by all `pz` generated types, as well as [`bool`], 31 | /// [`i32`], [`i64`], [`u32`], [`u64`], [`f32`], [`f64`], and [`String`]. 32 | /// 33 | /// It is also implemented by tuples of size up to 12 and the [`Opt`] and 34 | /// [`Rep`] markers. 35 | pub trait Type: Views + private::Type {} 36 | impl Type for T {} 37 | 38 | /// A field setting argument. 39 | /// 40 | /// This abstracts the notion of setting a value on a field: for example, all 41 | /// optional `i32` fields are settable from both `i32` and `Option`. This 42 | /// type allows `set()` to take `impl Set>`. 43 | pub trait Set { 44 | /// Applies this value to the given mutator. 45 | fn apply_to(self, m: Mut); 46 | } 47 | 48 | /// A message type. 49 | /// 50 | /// This does not just include types declared with `message`, but any type that 51 | /// has fields, such as `choice` and `struct`. 52 | pub trait Message: Type + Views + Default + private::Message 53 | // XXX: Adding these bounds causes rustc to have a stroke? 54 | // where 55 | // for<'a> Ref<'a, Self>: MessageRef<'a>, 56 | // for<'a> Mut<'a, Self>: MessageMut<'a>, 57 | { 58 | /// The default value for this message, provided as a static constant. 59 | const DEFAULT: &'static Self; 60 | 61 | /// Deserializes a new message from the given stream. 62 | fn parse(codec: Codec, input: &mut dyn Read) -> Result { 63 | let mut new = Self::default(); 64 | new.parse_in_place(codec, input)?; 65 | Ok(new) 66 | } 67 | 68 | /// Deserializes onto this message in-place from the given stream. 69 | fn parse_in_place( 70 | &mut self, 71 | codec: Codec, 72 | input: &mut dyn Read, 73 | ) -> Result<(), Error> { 74 | match codec { 75 | Codec::Protobuf => { 76 | let mut ctx = tdp::parse::Context::new( 77 | input, 78 | Self::__arena(Seal, &mut self.as_mut()), 79 | ); 80 | return ctx.parse(Self::__raw(Seal, self.as_ref()), Self::__TDP); 81 | } 82 | } 83 | } 84 | 85 | /// Serializes this message to the given stream. 86 | fn emit(&self, codec: Codec, output: &mut dyn Write) -> Result<(), Error> { 87 | let _ = (codec, output); 88 | todo!() 89 | } 90 | 91 | /// Serializes this message to an in-memory byte array. 92 | fn to_bytes(&self, codec: Codec) -> Vec { 93 | let mut bytes = Vec::new(); 94 | let _ = self.emit(codec, &mut bytes); 95 | bytes 96 | } 97 | 98 | /// Converts an ordinary Rust reference into a message reference. 99 | fn as_ref(&self) -> Ref; 100 | 101 | /// Converts an ordinary Rust reference into a mutable message reference. 102 | fn as_mut(&mut self) -> Mut; 103 | 104 | /// Selects the fields given by `selector` out of this message by reference. 105 | fn get(&self, selector: S) -> Ref 106 | where 107 | S: Selector, 108 | { 109 | let _ = selector; 110 | S::get(self.as_ref()) 111 | } 112 | 113 | /// Selects the fields given by `selector` out of this message by mutable 114 | /// reference. 115 | /// 116 | /// If this would result in aliasing, it generates a post-monomorphization 117 | /// error. 118 | fn get_mut(&mut self, selector: S) -> Mut 119 | where 120 | S: Selector, 121 | { 122 | let _ = selector; 123 | S::get_mut(self.as_mut()) 124 | } 125 | 126 | /// Clears this message, resetting it to its original state, without 127 | /// discarding any held allocations. 128 | fn clear(&mut self) { 129 | if private::Message::__is_null(self, Seal) { 130 | return; 131 | } 132 | 133 | // No need to go through as_mut(); if we made it past the null check we know 134 | // this message is writable. 135 | unsafe { Self::__TDP.clear(Self::__raw(Seal, self.as_ref())) } 136 | } 137 | } 138 | 139 | /// A message reference type. 140 | /// 141 | /// Each [`Message`]'s [`Ref`] type implements this trait. 142 | pub trait MessageRef<'a>: Sized 143 | where 144 | Self: RefView<'a, Target = Self::Message>, 145 | Self::Message: Views = Self>, 146 | { 147 | /// The message type this reference is for. 148 | type Message: Message; 149 | 150 | /// Serializes this message to the given stream. 151 | fn emit(&self, codec: Codec, output: &mut dyn Write) -> Result<(), Error> { 152 | let _ = (codec, output); 153 | todo!() 154 | } 155 | 156 | /// Serializes this message to an in-memory byte array. 157 | fn to_bytes(&self, codec: Codec) -> Vec { 158 | let mut bytes = Vec::new(); 159 | let _ = self.emit(codec, &mut bytes); 160 | bytes 161 | } 162 | 163 | /// Selects the fields given by `selector` out of this reference. 164 | fn get(self, selector: S) -> Ref<'a, S::Type> 165 | where 166 | S: Selector, 167 | { 168 | let _ = selector; 169 | S::get(self) 170 | } 171 | } 172 | 173 | /// A message mutable reference type. 174 | /// 175 | /// Each [`Message`]'s [`Mut`] type implements this trait. 176 | pub trait MessageMut<'a>: Sized 177 | where 178 | Self: MutView<'a, Target = Self::Message>, 179 | Self::Message: Views = Self>, 180 | Ref<'a, Self::Message>: MessageRef<'a, Message = Self::Message>, 181 | { 182 | /// The message type this reference is for. 183 | type Message: Message; 184 | 185 | /// Parses onto this message in place from the given stream. 186 | fn parse_in_place( 187 | &mut self, 188 | codec: Codec, 189 | input: &mut dyn Read, 190 | ) -> Result<(), Error> { 191 | match codec { 192 | Codec::Protobuf => { 193 | let mut ctx = tdp::parse::Context::new( 194 | input, 195 | ::__arena(Seal, self), 196 | ); 197 | return ctx.parse( 198 | ::__raw(Seal, self.as_ref()), 199 | ::__TDP, 200 | ); 201 | } 202 | } 203 | } 204 | 205 | /// Serializes this message to the given stream. 206 | fn emit(&self, codec: Codec, output: &mut dyn Write) -> Result<(), Error> { 207 | let _ = (codec, output); 208 | todo!() 209 | } 210 | 211 | /// Serializes this message to an in-memory byte array. 212 | fn to_bytes(&self, codec: Codec) -> Vec { 213 | let mut bytes = Vec::new(); 214 | let _ = self.emit(codec, &mut bytes); 215 | bytes 216 | } 217 | 218 | /// Selects the fields given by `selector` out of this reference. 219 | fn get(self, selector: S) -> Ref<'a, S::Type> 220 | where 221 | S: Selector, 222 | { 223 | self.into_ref().get(selector) 224 | } 225 | 226 | /// Selects the fields given by `selector` out of this message by mutable 227 | /// reference. 228 | /// 229 | /// If this would result in aliasing, it generates a post-monomorphization 230 | /// error. 231 | fn get_mut(self, selector: S) -> Mut<'a, S::Type> 232 | where 233 | S: Selector, 234 | { 235 | let _ = selector; 236 | S::get_mut(self) 237 | } 238 | 239 | /// Clears this message, resetting it to its original state, without 240 | /// discarding any held allocations. 241 | fn clear(&mut self) { 242 | // No need to go through as_mut(); if we made it past the null check we know 243 | // this message is writable. 244 | unsafe { 245 | ::__TDP.clear( 246 | ::__raw(Seal, self.as_ref()), 247 | ) 248 | } 249 | } 250 | } 251 | 252 | /// A field of a message. 253 | /// 254 | /// If `M: Message`, then `M: Field` if `M` is statically know to 255 | /// a field named `xyz`. The trait methods of that implementation allow 256 | /// operating on that field generically. 257 | pub trait Field: Message 258 | where 259 | Name: Selector, 260 | { 261 | /// The type of this field. 262 | type Type: Views + access::Access; 263 | 264 | /// The name of this field, as a type (this is always the same as the `Name` 265 | /// type parameter). 266 | type Name; 267 | 268 | /// The tag number for this field, as declared in the schema. 269 | const NUMBER: i32; 270 | 271 | /// An index for this field, i.e., the relative position in which it appears 272 | /// in the schema. 273 | const INDEX: usize; 274 | 275 | /// The name of this field, as a string. 276 | const NAME: &'static str; 277 | } 278 | 279 | /// A message selector. 280 | /// 281 | /// A selector generalizes single field access: if `M: Field`, then 282 | /// `X: Selector`. Moreover, `fields!(a, b, c): Selector` if `M` has 283 | /// each of those fields. This makes it possible to select multiple disjoint 284 | /// fields of a message. 285 | pub trait Selector { 286 | /// The result of this selector. If this selector selects more than one 287 | /// message, it will be a tuple. 288 | type Type: Views; 289 | 290 | /// Whether this selects disjoint fields. If this is false, 291 | /// [`Selector::get_mut()`] will fail to compile. 292 | const DISJOINT: bool; 293 | 294 | #[doc(hidden)] 295 | const __M: tuple::Mask; 296 | 297 | /// Selects fields of `message`. 298 | fn get(message: Ref) -> Ref; 299 | 300 | /// Mutably selects fields out of `message`. 301 | /// 302 | /// If this would result in aliasing, it generates a post-monomorphization 303 | /// error. 304 | fn get_mut(mut message: Mut) -> Mut { 305 | const { 306 | assert!( 307 | Self::DISJOINT, 308 | "attempted to mutably select non-disjoint fields" 309 | ); 310 | } 311 | 312 | unsafe { Self::get_mut_unchecked(Seal, &mut message) } 313 | } 314 | 315 | /// Mutably selects fields out of `message`. 316 | /// 317 | /// If this would result in aliasing, returns [`None`]. 318 | fn try_mut(mut message: Mut) -> Option> { 319 | if !Self::DISJOINT { 320 | return None; 321 | } 322 | unsafe { Some(Self::get_mut_unchecked(Seal, &mut message)) } 323 | } 324 | 325 | /// Mutably selects fields out of `message`. 326 | /// 327 | /// # Safety 328 | /// 329 | /// This function does not check `DISJOINT`, nor does it correctly bind the 330 | /// outputs' lifetime to the input. This function is intended for internal 331 | /// use only. 332 | #[doc(hidden)] 333 | unsafe fn get_mut_unchecked<'a>( 334 | _: impl Sealed, 335 | message: &mut Mut, 336 | ) -> Mut<'a, Self::Type>; 337 | } 338 | 339 | impl> Selector for N { 340 | type Type = M::Type; 341 | 342 | const DISJOINT: bool = true; 343 | 344 | const __M: tuple::Mask = tuple::Mask::single(M::INDEX); 345 | 346 | fn get(message: Ref) -> Ref { 347 | let raw = M::__raw(Seal, message); 348 | unsafe { 349 | let tdp = M::__TDP.field(M::INDEX as u16); 350 | ::__ref(raw, tdp) 351 | } 352 | } 353 | 354 | unsafe fn get_mut_unchecked<'a>( 355 | _: impl Sealed, 356 | message: &mut Mut, 357 | ) -> Mut<'a, Self::Type> { 358 | let raw = M::__raw(Seal, message.as_ref()); 359 | let arena = M::__arena(Seal, message); 360 | let tdp = M::__TDP.field(M::INDEX as u16); 361 | ::__mut(raw, arena, tdp) 362 | } 363 | } 364 | 365 | mod access { 366 | use std::ptr::NonNull; 367 | 368 | use tdp::Opaque; 369 | 370 | use super::*; 371 | 372 | pub trait Access: Views { 373 | unsafe fn __ref<'a>(raw: Opaque, tdp: tdp::Field) -> Ref<'a, Self>; 374 | 375 | unsafe fn __mut<'a>( 376 | raw: Opaque, 377 | arena: RawArena, 378 | tdp: tdp::Field, 379 | ) -> Mut<'a, Self>; 380 | } 381 | 382 | impl Access for Opt { 383 | unsafe fn __ref<'a>(raw: Opaque, tdp: tdp::Field) -> Ref<'a, Self> { 384 | if !tdp.has(raw) { 385 | return None; 386 | } 387 | Some(T::__ref(Seal, tdp.cast(raw))) 388 | } 389 | 390 | unsafe fn __mut<'a>( 391 | raw: Opaque, 392 | arena: RawArena, 393 | tdp: tdp::Field, 394 | ) -> Mut<'a, Self> { 395 | OptMut::new(raw, arena, tdp) 396 | } 397 | } 398 | 399 | impl Access for Rep { 400 | unsafe fn __ref<'a>(raw: Opaque, tdp: tdp::Field) -> Ref<'a, Self> { 401 | if !tdp.has(raw) { 402 | return Slice::default(); 403 | } 404 | 405 | let vec = tdp.cast::>>(raw).as_ref(); 406 | Slice::from_raw_parts( 407 | vec.as_ptr().unwrap_or(NonNull::dangling()), 408 | vec.len(), 409 | ) 410 | } 411 | 412 | unsafe fn __mut<'a>( 413 | raw: Opaque, 414 | arena: RawArena, 415 | tdp: tdp::Field, 416 | ) -> Mut<'a, Self> { 417 | if !tdp.has(raw) { 418 | tdp.init(raw, arena) 419 | } 420 | 421 | let vec = tdp.cast::>>(raw).as_mut(); 422 | Repeated::from_raw_parts(vec, arena) 423 | } 424 | } 425 | } 426 | 427 | /// Type-level adapter for optional fields. 428 | /// 429 | /// The type of an optional field of type `i32` is not `i32`, but `Opt`. 430 | /// This allows e.g. `Mut>` to expose a way to set and clear the 431 | /// presence of the field. 432 | pub struct Opt(PhantomData); 433 | 434 | /// Type-level adapter for repeated fields. 435 | /// 436 | /// The type of a repeated field of type `i32` is `Rep`. 437 | pub struct Rep(PhantomData); 438 | 439 | impl Views for Opt { 440 | type Ref<'a> = Option>; 441 | type Mut<'a> = OptMut<'a, T>; 442 | } 443 | 444 | impl<'a, R: RefView<'a, Target: Type>> RefView<'a> for Option { 445 | type Target = Opt; 446 | 447 | fn as_ref(&self) -> Ref { 448 | self.as_ref().map(|r| r.as_ref()) 449 | } 450 | } 451 | 452 | impl Views for Rep { 453 | type Ref<'a> = Slice<'a, T>; 454 | type Mut<'a> = Repeated<'a, T>; 455 | } 456 | -------------------------------------------------------------------------------- /pzc/src/syn/parse.rs: -------------------------------------------------------------------------------- 1 | //! The parser. 2 | 3 | use std::mem; 4 | 5 | use crate::syn; 6 | use crate::syn::ImportedSymbol; 7 | 8 | use ilex::rule; 9 | use ilex::token; 10 | use ilex::token::Cursor; 11 | use ilex::Lexeme; 12 | use ilex::Report; 13 | use ilex::Span; 14 | use ilex::Spanned; 15 | use ilex::Token; 16 | 17 | #[ilex::spec] 18 | struct Pz { 19 | #[named("line comment")] 20 | #[rule("//")] 21 | line_comment: Lexeme, 22 | 23 | #[named("doc comment")] 24 | #[rule(rule::Quoted::from(rule::Bracket::paired("///", "\n")))] 25 | doc_comment: Lexeme, 26 | 27 | #[named("block comment")] 28 | #[rule("/*", "*/")] 29 | block_comment: Lexeme, 30 | 31 | #[rule("{", "}")] 32 | braces: Lexeme, 33 | 34 | #[rule(";")] 35 | semi: Lexeme, 36 | #[rule(".")] 37 | dot: Lexeme, 38 | #[rule("=")] 39 | equal: Lexeme, 40 | #[rule(":")] 41 | colon: Lexeme, 42 | #[rule("/")] 43 | slash: Lexeme, 44 | #[rule(",")] 45 | comma: Lexeme, 46 | #[rule("@")] 47 | at: Lexeme, 48 | 49 | #[rule("enum")] 50 | enum_: Lexeme, 51 | #[rule("struct")] 52 | struct_: Lexeme, 53 | #[rule("where")] 54 | where_: Lexeme, 55 | #[rule("as")] 56 | as_: Lexeme, 57 | 58 | message: Lexeme, 59 | choice: Lexeme, 60 | package: Lexeme, 61 | repeated: Lexeme, 62 | import: Lexeme, 63 | 64 | #[named("identifier")] 65 | #[rule(rule::Ident::new().ascii_only().prefixes(["", "#"]))] 66 | ident: Lexeme, 67 | 68 | #[named("integer")] 69 | #[rule(rule::Digital::new(10).separator("_").minus())] 70 | int: Lexeme, 71 | 72 | #[named("binary integer")] 73 | #[rule(rule::Digital::new(2).separator("_").minus().prefix("0b"))] 74 | bin: Lexeme, 75 | 76 | #[named("hexadecimal integer")] 77 | #[rule(rule::Digital::new(16).separator("_").minus().prefix("0x"))] 78 | hex: Lexeme, 79 | 80 | #[named("string literal")] 81 | #[rule(rule::Quoted::new('"').invalid_escape(r"\").escapes(["\\\"", r"\\"]))] 82 | str: Lexeme, 83 | } 84 | 85 | fn parse_path<'t>( 86 | pz: &Pz, 87 | toks: &mut Cursor<'t>, 88 | report: &Report, 89 | ) -> Option> { 90 | let mut path = syn::Path { 91 | components: vec![(toks.take(pz.ident, report)?, None)], 92 | }; 93 | 94 | while let Some(dot) = toks.try_take(pz.dot) { 95 | path.components.last_mut().unwrap().1 = Some(dot); 96 | path.components.push((toks.take(pz.ident, report)?, None)); 97 | } 98 | 99 | Some(path) 100 | } 101 | 102 | fn parse_ident<'t>( 103 | pz: &Pz, 104 | toks: &mut Cursor<'t>, 105 | report: &Report, 106 | ) -> Option> { 107 | // We go through parse_path to catch a path where we wanted a single 108 | // identifier. 109 | let idents = parse_path(pz, toks, report)?; 110 | 111 | if idents.components.len() > 1 { 112 | report.error("expected identifier, got path").at(&idents); 113 | } 114 | 115 | Some(idents.components[0].0) 116 | } 117 | 118 | fn parse_package<'t>( 119 | pz: &Pz, 120 | toks: &mut Cursor<'t>, 121 | report: &Report, 122 | ) -> Option<(Vec>, syn::Package<'t>)> { 123 | let mut attrs = Vec::new(); 124 | loop { 125 | let result = token::switch() 126 | .case(pz.doc_comment, |doc, _| Err(Some(syn::Attr::Doc(doc)))) 127 | .case(pz.at, |at, toks| { 128 | Err(parse_attr_kv(Some(at), pz, toks, report)) 129 | }) 130 | .case(pz.package, |package, toks| { 131 | Ok( 132 | parse_path(pz, toks, report) 133 | .map(|path| syn::Package { package, path }), 134 | ) 135 | }) 136 | .take(toks, report)?; 137 | 138 | match result { 139 | Ok(pkg) => return Some((attrs, pkg?)), 140 | Err(attr) => attrs.push(attr?), 141 | } 142 | } 143 | } 144 | 145 | fn parse_type<'t>( 146 | pz: &Pz, 147 | toks: &mut Cursor<'t>, 148 | report: &Report, 149 | ) -> Option> { 150 | if let Some(repeated) = toks.try_take(pz.repeated) { 151 | return Some(syn::Type::Repeated { 152 | repeated, 153 | element: Box::new(parse_type(pz, toks, report)?), 154 | }); 155 | }; 156 | 157 | Some(syn::Type::Path(parse_path(pz, toks, report)?)) 158 | } 159 | 160 | fn parse_attr_kv<'t>( 161 | at: Option>, 162 | pz: &Pz, 163 | toks: &mut Cursor<'t>, 164 | report: &Report, 165 | ) -> Option> { 166 | let name = parse_path(pz, toks, report); 167 | let value = toks.try_take(pz.equal).and_then(|eq| { 168 | let value = token::switch() 169 | .case(pz.ident, |_, toks| { 170 | toks.back_up(1); 171 | parse_path(pz, toks, report).map(syn::AttrValue::Path) 172 | }) 173 | .case(pz.str, |q, _| Some(syn::AttrValue::Str(q))) 174 | .cases([pz.int, pz.bin, pz.hex], |d, _| { 175 | Some(syn::AttrValue::Int(d)) 176 | }) 177 | .take(toks, report) 178 | .flatten(); 179 | value.map(|v| (eq, v)) 180 | }); 181 | 182 | Some(syn::Attr::At { 183 | at, 184 | name: name?, 185 | value, 186 | }) 187 | } 188 | 189 | fn parse_wheres<'t>( 190 | pz: &Pz, 191 | toks: &mut Cursor<'t>, 192 | report: &Report, 193 | attrs: &mut Vec>, 194 | ) { 195 | while let Some(_where_) = toks.try_take(pz.where_) { 196 | if let Some(attr) = parse_attr_kv(None, pz, toks, report) { 197 | attrs.push(attr); 198 | } 199 | } 200 | } 201 | 202 | fn parse_item<'t>( 203 | pz: &Pz, 204 | toks: &mut Cursor<'t>, 205 | report: &Report, 206 | mut imports: Option<&mut Vec>>, 207 | inside: Option, 208 | outer_name: Option>, 209 | ) -> Option> { 210 | let mut attrs = Vec::new(); 211 | let inside_of = match inside { 212 | Some(syn::DeclKind::Message) => "message", 213 | Some(syn::DeclKind::Enum) => "enum", 214 | Some(syn::DeclKind::Struct) => "struct", 215 | Some(syn::DeclKind::Choice) => "choice", 216 | None => "file", 217 | }; 218 | 219 | loop { 220 | enum What<'t> { 221 | Attr(syn::Attr<'t>), 222 | Import(syn::Import<'t>), 223 | Decl(syn::Decl<'t>), 224 | Field(syn::Field<'t>), 225 | } 226 | 227 | let done = token::switch() 228 | .case(pz.at, |at, toks| { 229 | Some(What::Attr(parse_attr_kv(Some(at), pz, toks, report)?)) 230 | }) 231 | .case(pz.doc_comment, |doc, _| { 232 | Some(What::Attr(syn::Attr::Doc(doc))) 233 | }) 234 | .case(pz.import, |import, toks| { 235 | let package = parse_path(pz, toks, report); 236 | let braces = toks.take(pz.braces, report); 237 | 238 | let mut symbols = Vec::new(); 239 | if let Some(braces) = braces { 240 | symbols.extend( 241 | braces 242 | .contents() 243 | .delimited(pz.comma, |toks| { 244 | let symbol = parse_path(pz, toks, report); 245 | let rename = toks 246 | .try_take(pz.as_) 247 | .and_then(|as_| Some((as_, parse_ident(pz, toks, report)?))); 248 | Some(ImportedSymbol { 249 | symbol: symbol?, 250 | rename, 251 | }) 252 | }) 253 | .map(|(i, _)| i), 254 | ); 255 | } 256 | 257 | Some(What::Import(syn::Import { 258 | import, 259 | attrs: Vec::new(), 260 | package: package?, 261 | braces: braces?, 262 | symbols, 263 | })) 264 | }) 265 | .cases([pz.message, pz.enum_, pz.struct_, pz.choice], |kw, toks| { 266 | let kind = if kw.lexeme() == pz.message { 267 | syn::DeclKind::Message 268 | } else if kw.lexeme() == pz.enum_ { 269 | syn::DeclKind::Enum 270 | } else if kw.lexeme() == pz.struct_ { 271 | syn::DeclKind::Struct 272 | } else { 273 | syn::DeclKind::Choice 274 | }; 275 | 276 | let name = parse_ident(pz, toks, report); 277 | let body = toks.take(pz.braces, report); 278 | 279 | let outer_span = body.map(|body| { 280 | Span::union([kw.span(toks.context()), body.span(toks.context())]) 281 | }); 282 | 283 | if inside == Some(syn::DeclKind::Enum) { 284 | let mut d = 285 | report.error("declarations not permitted inside an `enum`"); 286 | if let Some(span) = outer_span { 287 | d = d.saying(span, "this declaration"); 288 | } 289 | if let Some(outer) = outer_name { 290 | d.remark(outer, "declared within this enum"); 291 | } 292 | } 293 | 294 | let mut items = Vec::new(); 295 | if let Some(body) = body { 296 | let mut toks = body.contents(); 297 | while !toks.is_empty() { 298 | if let Some(item) = 299 | parse_item(pz, &mut toks, report, None, Some(kind), name) 300 | { 301 | items.push(item); 302 | } 303 | } 304 | } 305 | 306 | Some(What::Decl(syn::Decl { 307 | kw, 308 | braces: body?, 309 | kind, 310 | name: name?, 311 | items, 312 | attrs: Vec::new(), 313 | })) 314 | }) 315 | .cases( 316 | [pz.ident.any(), pz.int.any(), pz.hex.any(), pz.bin.any()], 317 | |tok, toks| { 318 | let number = tok.digital().ok(); 319 | if let Some(n) = number { 320 | if inside == Some(syn::DeclKind::Struct) { 321 | let d = report 322 | .error(format_args!("struct fields cannot have numbers")) 323 | .saying(n, "remove this number"); 324 | 325 | if let Some(outer) = outer_name { 326 | d.remark(outer, format_args!("declared within this struct")); 327 | } 328 | } 329 | 330 | toks.take(pz.dot, report); 331 | } else { 332 | toks.back_up(1); 333 | }; 334 | 335 | let name = parse_ident(pz, toks, report); 336 | 337 | // This needs to be here so we can moor the diagnostic onto the `name`. 338 | // (This may be a sign I should move where these diagnostics are 339 | // generated...) 340 | if number.is_none() && inside != Some(syn::DeclKind::Struct) { 341 | let mut d = report 342 | .error(format_args!("{inside_of} fields must have numbers")); 343 | if let Some(name) = name { 344 | d = d.saying(name, "expected number") 345 | } 346 | if let Some(outer) = outer_name { 347 | d.remark(outer, format_args!("declared within this {inside_of}")); 348 | } 349 | } 350 | 351 | let mut ty = None; 352 | if let Some(_colon) = toks.try_take(pz.colon) { 353 | ty = parse_type(pz, toks, report); 354 | if inside == Some(syn::DeclKind::Enum) { 355 | let mut d = report 356 | .error(format_args!("{inside_of} fields cannot have types")); 357 | if let Some(ty) = &ty { 358 | d = d.saying(ty, "remove this type") 359 | } 360 | if let Some(outer) = outer_name { 361 | d.remark( 362 | outer, 363 | format_args!("declared within this {inside_of}"), 364 | ); 365 | } 366 | } 367 | } else if inside.is_some_and(|k| k != syn::DeclKind::Enum) { 368 | let mut d = 369 | report.error(format_args!("{inside_of} fields must have types")); 370 | if let Some(name) = name { 371 | d = d.saying(name, "expected type") 372 | } 373 | if let Some(outer) = outer_name { 374 | d.remark(outer, format_args!("declared within this {inside_of}")); 375 | } 376 | } 377 | 378 | parse_wheres(pz, toks, report, &mut attrs); 379 | 380 | if inside.is_none() { 381 | report 382 | .error("bare fields are not permitted at the file level") 383 | .at(name?); 384 | } 385 | 386 | Some(What::Field(syn::Field { 387 | name: name?, 388 | number, 389 | ty, 390 | attrs: Vec::new(), 391 | })) 392 | }, 393 | ) 394 | .case(Lexeme::eof(), |_, _| { 395 | // TODO: handle unmoored attributes? 396 | None 397 | }) 398 | .take(toks, report)??; 399 | 400 | match done { 401 | What::Attr(attr) => attrs.push(attr), 402 | What::Import(mut import) => { 403 | import.attrs = mem::take(&mut attrs); 404 | match &mut imports { 405 | Some(imports) => imports.push(import), 406 | None => { 407 | report 408 | .error("imports are only permitted at the top of the file") 409 | .at(&import); 410 | } 411 | } 412 | } 413 | What::Decl(mut decl) => { 414 | decl.attrs = attrs; 415 | return Some(syn::Item::Decl(decl)); 416 | } 417 | What::Field(mut field) => { 418 | field.attrs = attrs; 419 | return Some(syn::Item::Field(field)); 420 | } 421 | } 422 | } 423 | } 424 | 425 | pub fn lex<'t>( 426 | file: ilex::File<'t>, 427 | report: &ilex::Report, 428 | ) -> Result, ilex::Fatal> { 429 | file.lex(Pz::get().spec(), report) 430 | } 431 | 432 | pub fn parse<'t>( 433 | stream: &'t token::Stream<'t>, 434 | report: &ilex::Report, 435 | ) -> Result, ilex::Fatal> { 436 | let _u = stream.context().use_for_debugging_spans(); 437 | let mut cursor = stream.cursor(); 438 | 439 | let pz = Pz::get(); 440 | let pkg = parse_package(pz, &mut cursor, report); 441 | 442 | let mut imports = Vec::new(); 443 | let mut items = Vec::new(); 444 | while !cursor.is_empty() { 445 | let item = parse_item( 446 | pz, 447 | &mut cursor, 448 | report, 449 | // Only parse imports before we parse any other kind of item. 450 | items.is_empty().then_some(&mut imports), 451 | None, 452 | None, 453 | ); 454 | if let Some(item) = item { 455 | items.push(item); 456 | } 457 | } 458 | 459 | let (attrs, package) = pkg.unwrap(); 460 | Ok(syn::PzFile { 461 | attrs, 462 | package, 463 | imports, 464 | items, 465 | }) 466 | } 467 | --------------------------------------------------------------------------------