Skip to content

Commit 11b7ec0

Browse files
committed
ssh-encoding: remove Encoding::Error; add LabelError
Removes the associated `Encoding::Error` type as well as `Label::Error`, using `ssh_encoding::Error` as the type. Adds a `LabelError` type which captures the invalid label when the `alloc` feature has been enabled for display purposes. This is used as the error type for `FromStr` impls, so invalid labels can be propagated properly.
1 parent b3dc879 commit 11b7ec0

29 files changed

Lines changed: 285 additions & 313 deletions

ssh-encoding/src/encode.rs

Lines changed: 11 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,21 @@ use {
1919
///
2020
/// This trait describes how to encode a given type.
2121
pub trait Encode {
22-
/// Type returned in the event of an encoding error.
23-
type Error: From<Error>;
24-
2522
/// Get the length of this type encoded in bytes, prior to Base64 encoding.
26-
fn encoded_len(&self) -> Result<usize, Self::Error>;
23+
fn encoded_len(&self) -> Result<usize, Error>;
2724

2825
/// Encode this value using the provided [`Writer`].
29-
fn encode(&self, writer: &mut impl Writer) -> Result<(), Self::Error>;
26+
fn encode(&self, writer: &mut impl Writer) -> Result<(), Error>;
3027

3128
/// Return the length of this type after encoding when prepended with a
3229
/// `uint32` length prefix.
33-
fn encoded_len_prefixed(&self) -> Result<usize, Self::Error> {
34-
Ok([4, self.encoded_len()?].checked_sum()?)
30+
fn encoded_len_prefixed(&self) -> Result<usize, Error> {
31+
[4, self.encoded_len()?].checked_sum()
3532
}
3633

3734
/// Encode this value, first prepending a `uint32` length prefix
3835
/// set to [`Encode::encoded_len`].
39-
fn encode_prefixed(&self, writer: &mut impl Writer) -> Result<(), Self::Error> {
36+
fn encode_prefixed(&self, writer: &mut impl Writer) -> Result<(), Error> {
4037
self.encoded_len()?.encode(writer)?;
4138
self.encode(writer)
4239
}
@@ -50,36 +47,28 @@ pub trait Encode {
5047
pub trait EncodePem: Encode + PemLabel {
5148
/// Encode this type using the [`Encode`] trait, writing the resulting PEM
5249
/// document into the provided `out` buffer.
53-
fn encode_pem<'o>(
54-
&self,
55-
line_ending: LineEnding,
56-
out: &'o mut [u8],
57-
) -> Result<&'o str, Self::Error>;
50+
fn encode_pem<'o>(&self, line_ending: LineEnding, out: &'o mut [u8]) -> Result<&'o str, Error>;
5851

5952
/// Encode this type using the [`Encode`] trait, writing the resulting PEM
6053
/// document to a returned [`String`].
6154
#[cfg(feature = "alloc")]
62-
fn encode_pem_string(&self, line_ending: LineEnding) -> Result<String, Self::Error>;
55+
fn encode_pem_string(&self, line_ending: LineEnding) -> Result<String, Error>;
6356
}
6457

6558
#[cfg(feature = "pem")]
6659
impl<T: Encode + PemLabel> EncodePem for T {
67-
fn encode_pem<'o>(
68-
&self,
69-
line_ending: LineEnding,
70-
out: &'o mut [u8],
71-
) -> Result<&'o str, Self::Error> {
60+
fn encode_pem<'o>(&self, line_ending: LineEnding, out: &'o mut [u8]) -> Result<&'o str, Error> {
7261
let mut writer =
7362
pem::Encoder::new_wrapped(Self::PEM_LABEL, PEM_LINE_WIDTH, line_ending, out)
7463
.map_err(Error::from)?;
7564

7665
self.encode(&mut writer)?;
7766
let encoded_len = writer.finish().map_err(Error::from)?;
78-
Ok(str::from_utf8(&out[..encoded_len]).map_err(Error::from)?)
67+
str::from_utf8(&out[..encoded_len]).map_err(Error::from)
7968
}
8069

8170
#[cfg(feature = "alloc")]
82-
fn encode_pem_string(&self, line_ending: LineEnding) -> Result<String, Self::Error> {
71+
fn encode_pem_string(&self, line_ending: LineEnding) -> Result<String, Error> {
8372
let encoded_len = pem::encapsulated_len_wrapped(
8473
Self::PEM_LABEL,
8574
PEM_LINE_WIDTH,
@@ -91,14 +80,12 @@ impl<T: Encode + PemLabel> EncodePem for T {
9180
let mut buf = vec![0u8; encoded_len];
9281
let actual_len = self.encode_pem(line_ending, &mut buf)?.len();
9382
buf.truncate(actual_len);
94-
Ok(String::from_utf8(buf).map_err(Error::from)?)
83+
String::from_utf8(buf).map_err(Error::from)
9584
}
9685
}
9786

9887
/// Encode a single `byte` to the writer.
9988
impl Encode for u8 {
100-
type Error = Error;
101-
10289
fn encoded_len(&self) -> Result<usize, Error> {
10390
Ok(1)
10491
}
@@ -116,8 +103,6 @@ impl Encode for u8 {
116103
///
117104
/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
118105
impl Encode for u32 {
119-
type Error = Error;
120-
121106
fn encoded_len(&self) -> Result<usize, Error> {
122107
Ok(4)
123108
}
@@ -134,8 +119,6 @@ impl Encode for u32 {
134119
///
135120
/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
136121
impl Encode for u64 {
137-
type Error = Error;
138-
139122
fn encoded_len(&self) -> Result<usize, Error> {
140123
Ok(8)
141124
}
@@ -152,8 +135,6 @@ impl Encode for u64 {
152135
///
153136
/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
154137
impl Encode for usize {
155-
type Error = Error;
156-
157138
fn encoded_len(&self) -> Result<usize, Error> {
158139
Ok(4)
159140
}
@@ -171,8 +152,6 @@ impl Encode for usize {
171152
///
172153
/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
173154
impl Encode for [u8] {
174-
type Error = Error;
175-
176155
fn encoded_len(&self) -> Result<usize, Error> {
177156
[4, self.len()].checked_sum()
178157
}
@@ -191,8 +170,6 @@ impl Encode for [u8] {
191170
///
192171
/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
193172
impl<const N: usize> Encode for [u8; N] {
194-
type Error = Error;
195-
196173
fn encoded_len(&self) -> Result<usize, Error> {
197174
self.as_slice().encoded_len()
198175
}
@@ -220,8 +197,6 @@ impl<const N: usize> Encode for [u8; N] {
220197
///
221198
/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
222199
impl Encode for &str {
223-
type Error = Error;
224-
225200
fn encoded_len(&self) -> Result<usize, Error> {
226201
self.as_bytes().encoded_len()
227202
}
@@ -233,8 +208,6 @@ impl Encode for &str {
233208

234209
#[cfg(feature = "alloc")]
235210
impl Encode for Vec<u8> {
236-
type Error = Error;
237-
238211
fn encoded_len(&self) -> Result<usize, Error> {
239212
self.as_slice().encoded_len()
240213
}
@@ -246,8 +219,6 @@ impl Encode for Vec<u8> {
246219

247220
#[cfg(feature = "alloc")]
248221
impl Encode for String {
249-
type Error = Error;
250-
251222
fn encoded_len(&self) -> Result<usize, Error> {
252223
self.as_str().encoded_len()
253224
}
@@ -259,8 +230,6 @@ impl Encode for String {
259230

260231
#[cfg(feature = "alloc")]
261232
impl Encode for Vec<String> {
262-
type Error = Error;
263-
264233
fn encoded_len(&self) -> Result<usize, Error> {
265234
self.iter().try_fold(4usize, |acc, string| {
266235
acc.checked_add(string.encoded_len()?).ok_or(Error::Length)

ssh-encoding/src/error.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
//! Error types
22
3+
use crate::LabelError;
34
use core::fmt;
45

56
/// Result type with `ssh-encoding` crate's [`Error`] as the error type.
67
pub type Result<T> = core::result::Result<T, Error>;
78

89
/// Error type.
9-
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
10+
#[derive(Clone, Debug, Eq, PartialEq)]
1011
#[non_exhaustive]
1112
pub enum Error {
1213
/// Base64-related errors.
@@ -16,6 +17,9 @@ pub enum Error {
1617
/// Character encoding-related errors.
1718
CharacterEncoding,
1819

20+
/// Invalid label.
21+
Label(LabelError),
22+
1923
/// Invalid length.
2024
Length,
2125

@@ -39,6 +43,7 @@ impl fmt::Display for Error {
3943
#[cfg(feature = "base64")]
4044
Error::Base64(err) => write!(f, "Base64 encoding error: {err}"),
4145
Error::CharacterEncoding => write!(f, "character encoding invalid"),
46+
Error::Label(err) => write!(f, "{}", err),
4247
Error::Length => write!(f, "length invalid"),
4348
Error::Overflow => write!(f, "internal overflow error"),
4449
#[cfg(feature = "pem")]
@@ -51,6 +56,12 @@ impl fmt::Display for Error {
5156
}
5257
}
5358

59+
impl From<LabelError> for Error {
60+
fn from(err: LabelError) -> Error {
61+
Error::Label(err)
62+
}
63+
}
64+
5465
impl From<core::num::TryFromIntError> for Error {
5566
fn from(_: core::num::TryFromIntError) -> Error {
5667
Error::Overflow

ssh-encoding/src/label.rs

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,81 @@
11
//! Convenience trait for decoding/encoding string labels.
22
3-
use crate::{Decode, Encode, Reader, Writer};
4-
use core::str::FromStr;
3+
use crate::{Decode, Encode, Error, Reader, Writer};
4+
use core::{fmt, str::FromStr};
5+
6+
#[cfg(feature = "alloc")]
7+
use alloc::string::String;
58

69
/// Maximum size of any algorithm name/identifier.
710
const MAX_LABEL_SIZE: usize = 48;
811

912
/// Labels for e.g. cryptographic algorithms.
1013
///
1114
/// Receives a blanket impl of [`Decode`] and [`Encode`].
12-
pub trait Label: AsRef<str> + FromStr<Err = Self::Error> {
13-
/// Type returned in the event of an encoding error.
14-
type Error: From<crate::Error>;
15-
}
15+
pub trait Label: AsRef<str> + FromStr<Err = LabelError> {}
1616

1717
impl<T: Label> Decode for T {
18-
type Error = T::Error;
18+
type Error = Error;
1919

20-
fn decode(reader: &mut impl Reader) -> Result<Self, T::Error> {
20+
fn decode(reader: &mut impl Reader) -> Result<Self, Error> {
2121
let mut buf = [0u8; MAX_LABEL_SIZE];
22-
reader.read_string(buf.as_mut())?.parse()
22+
Ok(reader.read_string(buf.as_mut())?.parse()?)
2323
}
2424
}
2525

2626
impl<T: Label> Encode for T {
27-
type Error = T::Error;
27+
fn encoded_len(&self) -> Result<usize, Error> {
28+
self.as_ref().encoded_len()
29+
}
30+
31+
fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
32+
self.as_ref().encode(writer)
33+
}
34+
}
35+
36+
/// Errors related to labels.
37+
#[derive(Clone, Debug, Eq, PartialEq)]
38+
#[non_exhaustive]
39+
pub struct LabelError {
40+
/// The label that was considered invalid.
41+
#[cfg(feature = "alloc")]
42+
label: String,
43+
}
2844

29-
fn encoded_len(&self) -> Result<usize, T::Error> {
30-
Ok(self.as_ref().encoded_len()?)
45+
impl LabelError {
46+
/// Create a new [`LabelError`] for the given invalid label.
47+
pub fn new(label: &str) -> Self {
48+
Self {
49+
#[cfg(feature = "alloc")]
50+
label: label.into(),
51+
}
3152
}
3253

33-
fn encode(&self, writer: &mut impl Writer) -> Result<(), T::Error> {
34-
Ok(self.as_ref().encode(writer)?)
54+
/// The invalid label string (if available).
55+
#[inline]
56+
pub fn label(&self) -> &str {
57+
#[cfg(not(feature = "alloc"))]
58+
{
59+
""
60+
}
61+
#[cfg(feature = "alloc")]
62+
{
63+
&self.label
64+
}
3565
}
3666
}
67+
68+
impl fmt::Display for LabelError {
69+
#[cfg(not(feature = "alloc"))]
70+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71+
f.write_str("invalid label")
72+
}
73+
74+
#[cfg(feature = "alloc")]
75+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76+
write!(f, "invalid label: '{}'", self.label)
77+
}
78+
}
79+
80+
#[cfg(feature = "alloc")]
81+
impl std::error::Error for LabelError {}

ssh-encoding/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub use crate::{
3636
decode::Decode,
3737
encode::Encode,
3838
error::{Error, Result},
39-
label::Label,
39+
label::{Label, LabelError},
4040
reader::{NestedReader, Reader},
4141
writer::Writer,
4242
};

0 commit comments

Comments
 (0)