Skip to main content

api_bones_protos/
lib.rs

1// SPDX-License-Identifier: MIT
2//! Embedded bytes of the api-bones canonical proto shapes.
3//!
4//! This crate ships the `bones/v1/*.proto` files via `include_bytes!`
5//! and exposes a single accessor — [`files`] — that yields
6//! `(relative_path, bytes)` pairs ready for staging onto a protoc
7//! include path at consumer build time.
8//!
9//! **Zero runtime dependencies.** This crate exists purely as a
10//! distribution mechanism for the bytes. Pair it with any staging
11//! library (e.g. [`proto-build-kit`](https://crates.io/crates/proto-build-kit))
12//! to assemble a tempdir for codegen tools (connectrpc-build,
13//! tonic-prost-build, ...).
14//!
15//! # Example
16//!
17//! ```no_run
18//! # // We can't actually run this in a doctest because it depends on
19//! # // proto-build-kit, but it shows the shape.
20//! # mod proto_build_kit {
21//! #     pub struct Stager;
22//! #     impl Stager {
23//! #         pub fn new() -> Self { Self }
24//! #         pub fn with<I>(self, _: I) -> Self { self }
25//! #         pub fn stage(self) -> Result<tempfile::TempDir, std::io::Error> {
26//! #             tempfile::tempdir()
27//! #         }
28//! #     }
29//! # }
30//! let staged = proto_build_kit::Stager::new()
31//!     .with(api_bones_protos::files())
32//!     .stage()
33//!     .expect("stage");
34//! // Add staged.path() to your protoc include path.
35//! ```
36//!
37//! # What's included
38//!
39//! The shapes match the proto/bones/v1/ directory in the api-bones
40//! repo. See the README for the canonical schema inventory.
41
42const PAGINATION_PROTO: &[u8] = include_bytes!("../proto/bones/v1/pagination.proto");
43const QUERIES_PROTO: &[u8] = include_bytes!("../proto/bones/v1/queries.proto");
44const ERRORS_PROTO: &[u8] = include_bytes!("../proto/bones/v1/errors.proto");
45const RATELIMIT_PROTO: &[u8] = include_bytes!("../proto/bones/v1/ratelimit.proto");
46
47/// Yield `(relative_path, bytes)` pairs for every `bones/v1/*.proto`
48/// file shipped by this crate.
49///
50/// `relative_path` is the protoc-style import path consumers use
51/// (`bones/v1/pagination.proto`, etc.). The order of the iterator is
52/// stable but unspecified — consumers should not rely on it.
53pub fn files() -> impl Iterator<Item = (&'static str, &'static [u8])> {
54    [
55        ("bones/v1/pagination.proto", PAGINATION_PROTO),
56        ("bones/v1/queries.proto", QUERIES_PROTO),
57        ("bones/v1/errors.proto", ERRORS_PROTO),
58        ("bones/v1/ratelimit.proto", RATELIMIT_PROTO),
59    ]
60    .into_iter()
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn ships_four_files() {
69        let v: Vec<_> = files().collect();
70        assert_eq!(v.len(), 4);
71    }
72
73    #[test]
74    fn relative_paths_are_unique() {
75        let mut paths: Vec<_> = files().map(|(p, _)| p).collect();
76        let n = paths.len();
77        paths.sort_unstable();
78        paths.dedup();
79        assert_eq!(paths.len(), n, "duplicate relative paths in files()");
80    }
81
82    #[test]
83    fn every_file_has_non_empty_bytes() {
84        for (path, bytes) in files() {
85            assert!(!bytes.is_empty(), "{path} embeds empty bytes");
86        }
87    }
88
89    #[test]
90    fn pagination_proto_declares_expected_messages() {
91        let body = std::str::from_utf8(PAGINATION_PROTO).expect("utf8");
92        for msg in [
93            "message PageRequest",
94            "message PageResponse",
95            "message OffsetPageRequest",
96            "message OffsetPageResponse",
97        ] {
98            assert!(body.contains(msg), "pagination.proto missing `{msg}`");
99        }
100    }
101
102    #[test]
103    fn queries_proto_declares_filter_op_enum() {
104        let body = std::str::from_utf8(QUERIES_PROTO).expect("utf8");
105        assert!(
106            body.contains("enum FilterOp"),
107            "queries.proto missing FilterOp enum"
108        );
109        assert!(
110            body.contains("FILTER_OP_EQ"),
111            "queries.proto missing FILTER_OP_EQ"
112        );
113    }
114}