consensus_encoding: add api.rs to test public API surface
What changed, and why it matters
This commit adds a new test file that checks the public API surface of the consensus_encoding crate. It only imports types, checks that they implement common traits like Debug, Clone, Default, Send, and Sync, and verifies that Debug output is non-empty. There is no change to production code or security-sensitive logic.
No action required. This is a routine API-surface regression test.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit introduces consensus_encoding/tests/api.rs, a compile-time and runtime API-surface test. It constructs placeholder structs holding public types, derives common traits, and asserts Send/Sync/dyn-compatibility. No implementation code is modified; no bug fix, behavior change, or security patch is present.
Changed components
consensus_encoding/tests/api.rsInspect captured patch +149 / −0
diff --git a/consensus_encoding/tests/api.rs b/consensus_encoding/tests/api.rs
new file mode 100644
index 00000000..97575b96
--- /dev/null
+++ b/consensus_encoding/tests/api.rs
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: CC0-1.0
+
+//! Test the API surface of `consensus_encoding`.
+//!
+//! The point of these tests is to check the API surface as opposed to test the API functionality.
+//!
+//! ref: <https://rust-lang.github.io/api-guidelines/about.html>
+
+#![allow(dead_code)]
+#![allow(unused_imports)]
+
+use bitcoin_consensus_encoding::{
+ ArrayDecoder, ArrayEncoder, ArrayRefEncoder, BytesEncoder, CompactSizeDecoder,
+ CompactSizeDecoderError, CompactSizeEncoder, UnexpectedEofError,
+};
+#[cfg(feature = "alloc")]
+use bitcoin_consensus_encoding::{
+ ByteVecDecoder, ByteVecDecoderError, LengthPrefixExceedsMaxError, VecDecoderError,
+};
+
+static BYTES: &[u8] = &[];
+
+/// A struct that includes all public non-error structs.
+#[derive(Debug)] // All public types implement Debug (C-DEBUG).
+struct Structs {
+ a: ArrayDecoder<4>,
+ b: ArrayEncoder<4>,
+ c: ArrayRefEncoder<'static, 4>,
+ d: BytesEncoder<'static>,
+ #[cfg(feature = "alloc")]
+ e: ByteVecDecoder,
+ f: CompactSizeDecoder,
+ g: CompactSizeEncoder,
+}
+
+/// A struct that includes all types that implement `Clone`.
+#[derive(Clone)] // C-COMMON-TRAITS: `Clone`
+struct Clone {
+ a: ArrayDecoder<4>,
+ b: ArrayEncoder<4>,
+ c: ArrayRefEncoder<'static, 4>,
+ d: BytesEncoder<'static>,
+ #[cfg(feature = "alloc")]
+ e: ByteVecDecoder,
+ f: CompactSizeDecoder,
+ g: CompactSizeEncoder,
+}
+
+/// A struct that includes all types that implement `Default`.
+#[derive(Debug, Default)] // C-COMMON-TRAITS: `Default`
+struct Default {
+ a: ArrayDecoder<4>,
+ #[cfg(feature = "alloc")]
+ b: ByteVecDecoder,
+ c: CompactSizeDecoder,
+}
+
+/// A struct that includes all public error types.
+// These derives are the policy of `rust-bitcoin` not Rust API guidelines.
+#[derive(Debug, Clone, PartialEq, Eq)] // All public types implement Debug (C-DEBUG).
+struct Errors {
+ #[cfg(feature = "alloc")]
+ a: ByteVecDecoderError,
+ b: CompactSizeDecoderError,
+ #[cfg(feature = "alloc")]
+ c: LengthPrefixExceedsMaxError,
+ d: UnexpectedEofError,
+ #[cfg(feature = "alloc")]
+ e: VecDecoderError<UnexpectedEofError>,
+}
+
+#[test]
+fn api_can_use_all_encoder_types() {
+ use bitcoin_consensus_encoding::{
+ ArrayEncoder, ArrayRefEncoder, BytesEncoder, CompactSizeEncoder, Encoder2, Encoder3,
+ Encoder4, Encoder6, SliceEncoder,
+ };
+}
+
+#[test]
+fn api_can_use_all_decoder_types() {
+ use bitcoin_consensus_encoding::{
+ ArrayDecoder, CompactSizeDecoder, Decoder2, Decoder3, Decoder4, Decoder6,
+ };
+ #[cfg(feature = "alloc")]
+ use bitcoin_consensus_encoding::{ByteVecDecoder, VecDecoder};
+}
+
+#[test]
+fn api_can_use_all_decoder_error_types() {
+ #[cfg(feature = "std")]
+ use bitcoin_consensus_encoding::ReadError;
+ #[cfg(feature = "alloc")]
+ use bitcoin_consensus_encoding::{
+ ByteVecDecoderError, LengthPrefixExceedsMaxError, VecDecoderError,
+ };
+ use bitcoin_consensus_encoding::{CompactSizeDecoderError, UnexpectedEofError};
+}
+
+// `Debug` representation is never empty (C-DEBUG-NONEMPTY).
+#[test]
+fn api_all_non_error_types_have_non_empty_debug() {
+ static ARR: [u8; 4] = [0u8; 4];
+
+ let debug = format!("{:?}", ArrayDecoder::<4>::default());
+ assert!(!debug.is_empty());
+ let debug = format!("{:?}", ArrayEncoder::<4>::without_length_prefix([0u8; 4]));
+ assert!(!debug.is_empty());
+ let debug = format!("{:?}", ArrayRefEncoder::<4>::without_length_prefix(&ARR));
+ assert!(!debug.is_empty());
+ let debug = format!("{:?}", BytesEncoder::without_length_prefix(BYTES));
+ assert!(!debug.is_empty());
+ #[cfg(feature = "alloc")]
+ {
+ let debug = format!("{:?}", ByteVecDecoder::default());
+ assert!(!debug.is_empty());
+ }
+ let debug = format!("{:?}", CompactSizeDecoder::default());
+ assert!(!debug.is_empty());
+ let debug = format!("{:?}", CompactSizeEncoder::new(0));
+ assert!(!debug.is_empty());
+}
+
+#[test]
+fn all_types_implement_send_sync() {
+ fn assert_send<T: Send>() {}
+ fn assert_sync<T: Sync>() {}
+
+ // Types are `Send` and `Sync` where possible (C-SEND-SYNC).
+ assert_send::<Structs>();
+ assert_sync::<Structs>();
+
+ // Error types should implement the Send and Sync traits (C-GOOD-ERR).
+ assert_send::<Errors>();
+ assert_sync::<Errors>();
+}
+
+#[test]
+fn dyn_compatible() {
+ // If this builds then traits are dyn compatible.
+ struct Traits {
+ a: Box<dyn bitcoin_consensus_encoding::Encoder>,
+ b: Box<dyn bitcoin_consensus_encoding::ExactSizeEncoder>,
+ }
+ // The following traits are not dyn compatible:
+ // - `Encodable`: has a GAT (`type Encoder<'e>`)
+ // - `Decodable`: has an associated type (`type Decoder`)
+ // - `Decoder`: has a `Sized` bound
+}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.