From f963ff72acf959bd9611824e8f9b3025a5797b86 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 10 May 2026 09:15:02 -0600 Subject: [PATCH] ssh-encoding: enable and fix workspace-level lints Applies the workspace-level config added in #509 to this crate and fixes any failures. --- ssh-encoding/Cargo.toml | 9 ++--- ssh-encoding/LICENSE-MIT | 2 +- ssh-encoding/README.md | 7 ---- ssh-encoding/src/base64/reader.rs | 14 +++++-- ssh-encoding/src/base64/writer.rs | 16 ++++++++ ssh-encoding/src/checked.rs | 1 + ssh-encoding/src/decode.rs | 3 ++ ssh-encoding/src/encode.rs | 24 ++++++++++-- ssh-encoding/src/label.rs | 2 + ssh-encoding/src/lib.rs | 17 +-------- ssh-encoding/src/mpint.rs | 8 +++- ssh-encoding/src/pem/decode.rs | 12 ++++-- ssh-encoding/src/pem/encode.rs | 19 +++++++--- ssh-encoding/src/pem/reader.rs | 6 +-- ssh-encoding/src/pem/writer.rs | 6 +-- ssh-encoding/src/reader.rs | 62 +++++++++++++++++++------------ ssh-encoding/src/writer.rs | 3 ++ ssh-encoding/tests/derive.rs | 2 + 18 files changed, 136 insertions(+), 77 deletions(-) diff --git a/ssh-encoding/Cargo.toml b/ssh-encoding/Cargo.toml index 9873f9e4..3c47a363 100644 --- a/ssh-encoding/Cargo.toml +++ b/ssh-encoding/Cargo.toml @@ -1,10 +1,7 @@ [package] name = "ssh-encoding" version = "0.3.0-rc.8" -description = """ -Pure Rust implementation of SSH data type decoders/encoders as described -in RFC4251 -""" +description = "Pure Rust implementation of SSH data type decoders/encoders as described in RFC4251" authors = ["RustCrypto Developers"] license = "Apache-2.0 OR MIT" homepage = "https://github.com/RustCrypto/SSH/tree/master/ssh-encoding" @@ -37,6 +34,8 @@ bytes = ["alloc", "dep:bytes"] pem = ["base64", "dep:pem-rfc7468"] derive = ["ssh-derive"] +[lints] +workspace = true + [package.metadata.docs.rs] all-features = true -rustdoc-args = ["--cfg", "docsrs"] diff --git a/ssh-encoding/LICENSE-MIT b/ssh-encoding/LICENSE-MIT index 6f139a79..11d19168 100644 --- a/ssh-encoding/LICENSE-MIT +++ b/ssh-encoding/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2021-2024 The RustCrypto Project Developers +Copyright (c) 2021-2026 The RustCrypto Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/ssh-encoding/README.md b/ssh-encoding/README.md index c7aea07a..5a433943 100644 --- a/ssh-encoding/README.md +++ b/ssh-encoding/README.md @@ -14,13 +14,6 @@ Pure Rust implementation of SSH data type decoders/encoders as described in [RFC4251]. -## Minimum Supported Rust Version - -This crate requires **Rust 1.85** at a minimum. - -We may change the MSRV in the future, but it will be accompanied by a minor -version bump. - ## License Licensed under either of: diff --git a/ssh-encoding/src/base64/reader.rs b/ssh-encoding/src/base64/reader.rs index a5e6d09f..ef58fba5 100644 --- a/ssh-encoding/src/base64/reader.rs +++ b/ssh-encoding/src/base64/reader.rs @@ -1,6 +1,7 @@ //! Base64 reader support (constant-time). use crate::{Decode, Error, Reader, Result}; +use core::fmt::{self, Debug}; /// Inner constant-time Base64 reader type from the `base64ct` crate. type Inner<'i> = base64ct::Decoder<'i, base64ct::Base64>; @@ -18,9 +19,8 @@ impl<'i> Base64Reader<'i> { /// Create a new Base64 reader for a byte slice containing contiguous (non-newline-delimited) /// Base64-encoded data. /// - /// # Returns - /// - `Ok(reader)` on success. - /// - `Err(Error::Base64)` if the input buffer is empty. + /// # Errors + /// Returns [`Error::Base64`] if the `input` buffer is empty. pub fn new(input: &'i [u8]) -> Result { let inner = Inner::new(input)?; let remaining_len = inner.remaining_len(); @@ -32,4 +32,12 @@ impl<'i> Base64Reader<'i> { } } +impl Debug for Base64Reader<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Base64Reader") + .field("remaining_len", &self.remaining_len) + .finish_non_exhaustive() + } +} + impl_reader_for_newtype!(Base64Reader<'_>); diff --git a/ssh-encoding/src/base64/writer.rs b/ssh-encoding/src/base64/writer.rs index 9c07eeab..dcb6716a 100644 --- a/ssh-encoding/src/base64/writer.rs +++ b/ssh-encoding/src/base64/writer.rs @@ -1,6 +1,10 @@ //! Base64 writer support (constant-time). use crate::{Result, Writer}; +use core::fmt::{self, Debug}; + +#[cfg(doc)] +use crate::Error; /// Inner constant-time Base64 reader type from the `base64ct` crate. type Inner<'o> = base64ct::Encoder<'o, base64ct::Base64>; @@ -14,6 +18,9 @@ impl<'o> Base64Writer<'o> { /// Create a new Base64 writer which writes output to the given byte slice. /// /// Output constructed using this method is not line-wrapped. + /// + /// # Errors + /// Returns [`Error::Base64`] if the `output` buffer is empty. pub fn new(output: &'o mut [u8]) -> Result { Ok(Self { inner: Inner::new(output)?, @@ -21,11 +28,20 @@ impl<'o> Base64Writer<'o> { } /// Finish encoding data, returning the resulting Base64 as a `str`. + /// + /// # Errors + /// Returns [`Error::Base64`] if there is insufficient space in the output buffer. pub fn finish(self) -> Result<&'o str> { Ok(self.inner.finish()?) } } +impl Debug for Base64Writer<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Base64Writer").finish_non_exhaustive() + } +} + impl Writer for Base64Writer<'_> { fn write(&mut self, bytes: &[u8]) -> Result<()> { Ok(self.inner.encode(bytes)?) diff --git a/ssh-encoding/src/checked.rs b/ssh-encoding/src/checked.rs index 013574da..91eeb652 100644 --- a/ssh-encoding/src/checked.rs +++ b/ssh-encoding/src/checked.rs @@ -6,6 +6,7 @@ use crate::{Error, Result}; pub trait CheckedSum: Sized { /// Iterate over the values of this type, computing a checked sum. /// + /// # Errors /// Returns [`Error::Length`] on overflow. fn checked_sum(self) -> Result; } diff --git a/ssh-encoding/src/decode.rs b/ssh-encoding/src/decode.rs index b744e3de..85e14a2c 100644 --- a/ssh-encoding/src/decode.rs +++ b/ssh-encoding/src/decode.rs @@ -22,6 +22,9 @@ pub trait Decode: Sized { type Error: From; /// Attempt to decode a value of this type using the provided [`Reader`]. + /// + /// # Errors + /// Returns errors specific to the concrete implementation of this trait. fn decode(reader: &mut impl Reader) -> core::result::Result; } diff --git a/ssh-encoding/src/encode.rs b/ssh-encoding/src/encode.rs index 09fd7258..3e89b18f 100644 --- a/ssh-encoding/src/encode.rs +++ b/ssh-encoding/src/encode.rs @@ -17,25 +17,38 @@ use bytes::{Bytes, BytesMut}; /// This trait describes how to encode a given type. pub trait Encode { /// Get the length of this type encoded in bytes, prior to Base64 encoding. + /// + /// # Errors + /// Returns errors specific to the concrete implementation of this trait. fn encoded_len(&self) -> Result; /// Encode this value using the provided [`Writer`]. + /// + /// # Errors + /// Returns errors specific to the concrete implementation of this trait. fn encode(&self, writer: &mut impl Writer) -> Result<(), Error>; - /// Return the length of this type after encoding when prepended with a - /// `uint32` length prefix. + /// Return the length of this type after encoding when prepended with a `uint32` length prefix. + /// + /// # Errors + /// Returns errors specific to the concrete implementation of this trait. fn encoded_len_prefixed(&self) -> Result { [4, self.encoded_len()?].checked_sum() } - /// Encode this value, first prepending a `uint32` length prefix - /// set to [`Encode::encoded_len`]. + /// Encode this value, first prepending a `uint32` length prefix set to [`Encode::encoded_len`]. + /// + /// # Errors + /// Returns errors specific to the concrete implementation of this trait. fn encode_prefixed(&self, writer: &mut impl Writer) -> Result<(), Error> { self.encoded_len()?.encode(writer)?; self.encode(writer) } /// Encode this value, returning a `Vec` containing the encoded message. + /// + /// # Errors + /// Returns errors specific to the concrete implementation of this trait. #[cfg(feature = "alloc")] fn encode_vec(&self) -> Result, Error> { let mut ret = Vec::with_capacity(self.encoded_len()?); @@ -44,6 +57,9 @@ pub trait Encode { } /// Encode this value, returning a [`BytesMut`] containing the encoded message. + /// + /// # Errors + /// Returns errors specific to the concrete implementation of this trait. #[cfg(feature = "bytes")] fn encode_bytes(&self) -> Result { let mut ret = BytesMut::with_capacity(self.encoded_len()?); diff --git a/ssh-encoding/src/label.rs b/ssh-encoding/src/label.rs index 44496eab..3b2a2c77 100644 --- a/ssh-encoding/src/label.rs +++ b/ssh-encoding/src/label.rs @@ -45,6 +45,7 @@ pub struct LabelError { impl LabelError { /// Create a new [`LabelError`] for the given invalid label. #[cfg_attr(not(feature = "alloc"), allow(unused_variables))] + #[must_use] pub fn new(label: &str) -> Self { Self { #[cfg(feature = "alloc")] @@ -54,6 +55,7 @@ impl LabelError { /// The invalid label string (if available). #[inline] + #[must_use] pub fn label(&self) -> &str { #[cfg(not(feature = "alloc"))] { diff --git a/ssh-encoding/src/lib.rs b/ssh-encoding/src/lib.rs index 96436892..dd8903e3 100644 --- a/ssh-encoding/src/lib.rs +++ b/ssh-encoding/src/lib.rs @@ -1,25 +1,10 @@ #![no_std] -#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] #![doc = include_str!("../README.md")] #![doc( html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" )] -#![forbid(unsafe_code)] -#![warn( - clippy::alloc_instead_of_core, - clippy::arithmetic_side_effects, - clippy::mod_module_files, - clippy::panic, - clippy::panic_in_result_fn, - clippy::std_instead_of_alloc, - clippy::std_instead_of_core, - clippy::unwrap_used, - missing_docs, - rust_2018_idioms, - unused_lifetimes, - unused_qualifications -)] //! ## Conventions used in this crate //! diff --git a/ssh-encoding/src/mpint.rs b/ssh-encoding/src/mpint.rs index ca0b3d48..2060d09a 100644 --- a/ssh-encoding/src/mpint.rs +++ b/ssh-encoding/src/mpint.rs @@ -64,6 +64,7 @@ impl Mpint { /// /// The input may begin with leading zeros, which will be stripped when converted to [`Mpint`] /// encoding. + #[must_use] pub fn from_positive_bytes(mut bytes: &[u8]) -> Self { // Strip leading zeros while bytes.first().copied() == Some(0) { @@ -91,6 +92,7 @@ impl Mpint { /// This slice will contain a leading zero if the value is positive but the /// MSB is also set. Use [`Mpint::as_positive_bytes`] to ensure the number /// is positive and strip the leading zero byte if it exists. + #[must_use] pub fn as_bytes(&self) -> &[u8] { &self.inner } @@ -100,6 +102,7 @@ impl Mpint { /// # Returns /// - `Some(bytes)` if the number is positive. The leading zero byte will be stripped. /// - `None` if the value is negative + #[must_use] pub fn as_positive_bytes(&self) -> Option<&[u8]> { match self.as_bytes() { [0x00, rest @ ..] => Some(rest), @@ -109,6 +112,7 @@ impl Mpint { } /// Is this [`Mpint`] positive? + #[must_use] pub fn is_positive(&self) -> bool { self.as_positive_bytes().is_some() } @@ -258,7 +262,7 @@ mod tests { #[test] fn decode_0() { let n = Mpint::from_bytes(b"").unwrap(); - assert_eq!(b"", n.as_bytes()) + assert_eq!(b"", n.as_bytes()); } #[test] @@ -278,7 +282,7 @@ mod tests { let n = Mpint::from_bytes(&hex!("00 80")).unwrap(); // Leading zero stripped - assert_eq!(&hex!("80"), n.as_positive_bytes().unwrap()) + assert_eq!(&hex!("80"), n.as_positive_bytes().unwrap()); } #[test] fn from_positive_bytes_strips_leading_zeroes() { diff --git a/ssh-encoding/src/pem/decode.rs b/ssh-encoding/src/pem/decode.rs index 7a7dabd7..54d36f37 100644 --- a/ssh-encoding/src/pem/decode.rs +++ b/ssh-encoding/src/pem/decode.rs @@ -1,20 +1,24 @@ use super::{PemLabel, reader::PemReader}; -use crate::{Decode, Reader}; +use crate::{Decode, Error, Reader}; /// Decoding trait for PEM documents. /// /// This is an extension trait which is auto-impl'd for types which impl the /// [`Decode`], [`PemLabel`], and [`Sized`] traits. pub trait DecodePem: Decode + PemLabel + Sized { - /// Decode the provided PEM-encoded string, interpreting the Base64-encoded - /// body of the document using the [`Decode`] trait. + /// Decode the provided PEM-encoded string, interpreting the Base64-encoded body of the document + /// using the [`Decode`] trait. + /// + /// # Errors + /// - Returns [`Error::Pem`] in the event of PEM decoding errors. + /// - Propagates errors returned from the [`Decode::decode`] method. fn decode_pem(pem: impl AsRef<[u8]>) -> Result; } impl DecodePem for T { fn decode_pem(pem: impl AsRef<[u8]>) -> Result { let mut reader = PemReader::new(pem.as_ref())?; - Self::validate_pem_label(reader.type_label()).map_err(crate::Error::from)?; + Self::validate_pem_label(reader.type_label()).map_err(Error::from)?; let ret = Self::decode(&mut reader)?; Ok(reader.finish(ret)?) diff --git a/ssh-encoding/src/pem/encode.rs b/ssh-encoding/src/pem/encode.rs index 152923a4..9a0502b2 100644 --- a/ssh-encoding/src/pem/encode.rs +++ b/ssh-encoding/src/pem/encode.rs @@ -7,15 +7,22 @@ use {super::LINE_WIDTH, alloc::string::String}; /// Encoding trait for PEM documents. /// -/// This is an extension trait which is auto-impl'd for types which impl the -/// [`Encode`] and [`PemLabel`] traits. +/// This is an extension trait which is auto-impl'd for types which impl the [`Encode`] and +/// [`PemLabel`] traits. pub trait EncodePem: Encode + PemLabel { - /// Encode this type using the [`Encode`] trait, writing the resulting PEM - /// document into the provided `out` buffer. + /// Encode this type using the [`Encode`] trait, writing the resulting PEM document into the + /// provided `out` buffer. + /// + /// # Errors + /// - Returns [`Error::Pem`] in the event of PEM encoding errors. + /// - Propagates errors returned from the [`Encode::encode`] method. fn encode_pem<'o>(&self, line_ending: LineEnding, out: &'o mut [u8]) -> Result<&'o str, Error>; - /// Encode this type using the [`Encode`] trait, writing the resulting PEM - /// document to a returned [`String`]. + /// Encode this type using the [`Encode`] trait, writing the resulting PEM document to a + /// returned [`String`]. + /// + /// # Errors + /// Propagates errors returned from [`EncodePem::encode_pem`]. #[cfg(feature = "alloc")] fn encode_pem_string(&self, line_ending: LineEnding) -> Result; } diff --git a/ssh-encoding/src/pem/reader.rs b/ssh-encoding/src/pem/reader.rs index 6323c9de..e51f67b5 100644 --- a/ssh-encoding/src/pem/reader.rs +++ b/ssh-encoding/src/pem/reader.rs @@ -4,7 +4,7 @@ use crate::{Decode, Error, Reader, Result}; type Inner<'i> = pem_rfc7468::Decoder<'i>; /// Constant-time PEM reader. -pub struct PemReader<'i> { +pub(crate) struct PemReader<'i> { /// Inner PEM reader. inner: Inner<'i>, @@ -14,7 +14,7 @@ pub struct PemReader<'i> { impl<'i> PemReader<'i> { /// Create a new PEM reader which autodetects the line width of the input. - pub fn new(pem: &'i [u8]) -> Result { + pub(crate) fn new(pem: &'i [u8]) -> Result { let inner = Inner::new_detect_wrap(pem)?; let remaining_len = inner.remaining_len(); @@ -25,7 +25,7 @@ impl<'i> PemReader<'i> { } /// Get the PEM type label for the input document. - pub fn type_label(&self) -> &'i str { + pub(crate) fn type_label(&self) -> &'i str { self.inner.type_label() } } diff --git a/ssh-encoding/src/pem/writer.rs b/ssh-encoding/src/pem/writer.rs index 1d561919..134a149d 100644 --- a/ssh-encoding/src/pem/writer.rs +++ b/ssh-encoding/src/pem/writer.rs @@ -5,7 +5,7 @@ use crate::{Result, Writer}; type Inner<'o> = pem_rfc7468::Encoder<'static, 'o>; /// Constant-time PEM writer. -pub struct PemWriter<'o> { +pub(crate) struct PemWriter<'o> { inner: Inner<'o>, } @@ -14,7 +14,7 @@ impl<'o> PemWriter<'o> { /// buffer. /// /// Uses 70-character line wrapping to be equivalent to OpenSSH. - pub fn new( + pub(crate) fn new( type_label: &'static str, line_ending: LineEnding, out: &'o mut [u8], @@ -28,7 +28,7 @@ impl<'o> PemWriter<'o> { /// /// On success, returns the total number of bytes written to the output /// buffer. - pub fn finish(self) -> Result { + pub(crate) fn finish(self) -> Result { Ok(self.inner.finish()?) } } diff --git a/ssh-encoding/src/reader.rs b/ssh-encoding/src/reader.rs index 35373d67..de6a18fc 100644 --- a/ssh-encoding/src/reader.rs +++ b/ssh-encoding/src/reader.rs @@ -8,12 +8,12 @@ use core::str; pub trait Reader: Sized { /// Read as much data as is needed to exactly fill `out`. /// - /// This is the base decoding method on which the rest of the trait is - /// implemented in terms of. + /// This is the base decoding method on which the rest of the trait is implemented in terms of. /// - /// # Returns - /// - `Ok(bytes)` if the expected amount of data was read - /// - `Err(Error::Length)` if the exact amount of data couldn't be read + /// Returns `out` reborrowed as an immutable byte slice. + /// + /// # Errors + /// Returns `Err(Error::Length)` if the exact amount of data couldn't be read. fn read<'o>(&mut self, out: &'o mut [u8]) -> Result<&'o [u8]>; /// Get the length of the remaining data after Base64 decoding. @@ -26,9 +26,11 @@ pub trait Reader: Sized { /// Decode length-prefixed data. /// - /// Decodes a `uint32` which identifies the length of some encapsulated - /// data, then calls the given reader function with the length of the - /// remaining data. + /// Decodes a `uint32` which identifies the length of some encapsulated data, then calls the + /// given reader function with the length of the remaining data. + /// + /// # Errors + /// Propagates errors returned from `F`. fn read_prefixed(&mut self, f: F) -> core::result::Result where E: From, @@ -40,18 +42,21 @@ pub trait Reader: Sized { /// > data is sometimes represented as an array of bytes, written /// > `byte[n]`, where n is the number of bytes in the array. /// - /// Storage for the byte array must be provided as mutable byte slice in - /// order to accommodate `no_std` use cases. + /// Storage for the byte array must be provided as mutable byte slice in order to accommodate + /// `no_alloc` use cases. /// - /// The [`Decode`] impl on `Vec` can be used to allocate a buffer for - /// the result. + /// The [`Decode`] impl on `Vec` can be used to allocate a buffer for the result. /// /// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5 + /// + /// # Errors + /// - Returns [`Error::Length`] if `out` is too small to accommodate the full `byte[n]`. + /// - Propagates errors returned from [`Reader::read`]. fn read_byten<'o>(&mut self, out: &'o mut [u8]) -> Result<&'o [u8]> { self.read_prefixed(|reader| { let slice = out.get_mut(..reader.remaining_len()).ok_or(Error::Length)?; reader.read(slice)?; - Ok(slice as &[u8]) + Ok(&*slice) }) } @@ -71,18 +76,24 @@ pub trait Reader: Sized { /// > string "testing" is represented as 00 00 00 07 t e s t i n g. The /// > UTF-8 mapping does not alter the encoding of US-ASCII characters. /// - /// Storage for the string data must be provided as mutable byte slice in - /// order to accommodate `no_std` use cases. + /// Storage for the string data must be provided as mutable byte slice in order to accommodate + /// `no_alloc` use cases. /// - /// The [`Decode`] impl on `String` can be used to allocate a buffer for - /// the result. + /// The [`Decode`] impl on `String` can be used to allocate a buffer for the result. /// /// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5 + /// + /// # Errors + /// - Propagates errors returned from [`Reader::read_byten`]. + /// - Returns [`Error::CharacterEncoding`] if the data is not valid UTF-8. fn read_string<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o str> { Ok(str::from_utf8(self.read_byten(buf)?)?) } /// Drain the given number of bytes from the reader, discarding them. + /// + /// # Errors + /// Propagates errors returned from [`Reader::read`]. fn drain(&mut self, n_bytes: usize) -> Result<()> { let mut byte = [0]; for _ in 0..n_bytes { @@ -93,8 +104,12 @@ pub trait Reader: Sized { /// Decode a `u32` length prefix, and then drain the length of the body. /// - /// Upon success, returns the number of bytes drained sans the length of - /// the `u32` length prefix (4-bytes). + /// Upon success, returns the number of bytes drained sans the length of the `u32` length prefix + /// (4-bytes). + /// + /// # Errors + /// - Propagates errors returned from [`Reader::read_prefixed`]. + /// - Propagates errors returned from [`Reader::drain`]. fn drain_prefixed(&mut self) -> Result { self.read_prefixed(|reader| { let len = reader.remaining_len(); @@ -106,8 +121,7 @@ pub trait Reader: Sized { /// Ensure that decoding is finished. /// /// # Errors - /// - /// - Returns `Error::TrailingData` if there is data remaining in the encoder. + /// Returns [`Error::TrailingData`] if there is data remaining in the encoder. fn ensure_finished(&self) -> Result<()> { if self.is_finished() { Ok(()) @@ -118,8 +132,10 @@ pub trait Reader: Sized { } } - /// Finish decoding, returning the given value if there is no remaining - /// data, or an error otherwise. + /// Finish decoding, returning the given value if there is no remaining data. + /// + /// # Errors + /// Returns [`Error::TrailingData`] if there is data remaining in the encoder. fn finish(self, value: T) -> Result { self.ensure_finished()?; Ok(value) diff --git a/ssh-encoding/src/writer.rs b/ssh-encoding/src/writer.rs index 6df6836a..7b1fbcb7 100644 --- a/ssh-encoding/src/writer.rs +++ b/ssh-encoding/src/writer.rs @@ -15,6 +15,9 @@ use digest::Digest; /// encodings. pub trait Writer: Sized { /// Write the given bytes to the writer. + /// + /// # Errors + /// Returns errors specific to the concrete implementation of this trait. fn write(&mut self, bytes: &[u8]) -> Result<()>; } diff --git a/ssh-encoding/tests/derive.rs b/ssh-encoding/tests/derive.rs index 812f8ced..9e034b43 100644 --- a/ssh-encoding/tests/derive.rs +++ b/ssh-encoding/tests/derive.rs @@ -1,5 +1,7 @@ //! Tests for the derive implementations for the `Decode` and `Encode` traits. + #![cfg(all(feature = "derive", feature = "alloc"))] +#![allow(missing_docs, missing_copy_implementations)] use ssh_encoding::{Decode, Encode, Error};