Skip to content

Commit d816163

Browse files
authored
Add encode_mut_str to guarantee UTF-8 for safe callers (#137)
Fixes #136
1 parent ec53217 commit d816163

File tree

11 files changed

+75
-14
lines changed

11 files changed

+75
-14
lines changed

bin/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## 0.3.7-git
4+
5+
### Patch
6+
7+
- Update `data-encoding` version
8+
39
## 0.3.6
410

511
### Patch

bin/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "data-encoding-bin"
3-
version = "0.3.6"
3+
version = "0.3.7-git"
44
authors = ["Julien Cretin <[email protected]>"]
55
license = "MIT"
66
edition = "2021"
@@ -17,5 +17,5 @@ name = "data-encoding"
1717
path = "src/main.rs"
1818

1919
[dependencies]
20-
data-encoding = { version = "2.8.0", path = "../lib" }
20+
data-encoding = { version = "2.9.0-git", path = "../lib" }
2121
getopts = "0.2"

lib/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## 2.9.0-git
4+
5+
### Minor
6+
7+
- Add `Encoding::encode_mut_str()` to guarantee UTF-8 for safe callers (fixes #136)
8+
39
## 2.8.0
410

511
### Minor

lib/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "data-encoding"
3-
version = "2.8.0"
3+
version = "2.9.0-git"
44
authors = ["Julien Cretin <[email protected]>"]
55
license = "MIT"
66
edition = "2018"

lib/fuzz/Cargo.toml

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,32 @@ name = "impl_decode"
3030
path = "fuzz_targets/impl_decode.rs"
3131

3232
[[bin]]
33-
name = "impl_new_encoder"
34-
path = "fuzz_targets/impl_new_encoder.rs"
33+
name = "impl_encode_mut_str"
34+
path = "fuzz_targets/impl_encode_mut_str.rs"
35+
36+
[[bin]]
37+
name = "impl_encode_append"
38+
path = "fuzz_targets/impl_encode_append.rs"
3539

3640
[[bin]]
3741
name = "impl_encode_write_buffer"
3842
path = "fuzz_targets/impl_encode_write_buffer.rs"
3943

4044
[[bin]]
41-
name = "spec_spec_base"
42-
path = "fuzz_targets/spec_spec_base.rs"
45+
name = "impl_new_encoder"
46+
path = "fuzz_targets/impl_new_encoder.rs"
47+
48+
[[bin]]
49+
name = "spec_decode_encode"
50+
path = "fuzz_targets/spec_decode_encode.rs"
4351

4452
[[bin]]
4553
name = "spec_encode_decode"
4654
path = "fuzz_targets/spec_encode_decode.rs"
4755

4856
[[bin]]
49-
name = "spec_decode_encode"
50-
path = "fuzz_targets/spec_decode_encode.rs"
57+
name = "spec_spec_base"
58+
path = "fuzz_targets/spec_spec_base.rs"
5159

5260
[lints.rust]
5361
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing)'] }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
template.rs
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
template.rs

lib/fuzz/src/cmd.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,17 @@ pub fn execute(target: &str, mut input: &[u8]) -> Output {
5050
output.insert("decode_ok", actual.is_ok() as usize);
5151
assert_eq!(actual.ok(), spec::decode(&spec, input));
5252
}
53+
"impl_encode_mut_str" => {
54+
let (spec, base) = gen_spec_base(&mut input, &mut output);
55+
let mut output = vec![0; base.encode_len(input.len())];
56+
assert_eq!(base.encode_mut_str(input, &mut output), spec::encode(&spec, input));
57+
}
58+
"impl_encode_append" => {
59+
let (spec, base) = gen_spec_base(&mut input, &mut output);
60+
let mut output = String::new();
61+
base.encode_append(input, &mut output);
62+
assert_eq!(output, spec::encode(&spec, input));
63+
}
5364
"impl_encode_write_buffer" => {
5465
let (_, base) = gen_spec_base(&mut input, &mut output);
5566
let mut buffer = vec![0; gen::nat(&mut input, 510, 2050)];

lib/macro/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "data-encoding-macro"
3-
version = "0.1.17"
3+
version = "0.1.18-git"
44
authors = ["Julien Cretin <[email protected]>"]
55
license = "MIT"
66
edition = "2018"
@@ -14,5 +14,5 @@ description = "Macros for data-encoding"
1414
include = ["Cargo.toml", "LICENSE", "README.md", "src/lib.rs"]
1515

1616
[dependencies]
17-
data-encoding = { version = "2.8.0", path = "..", default-features = false }
18-
data-encoding-macro-internal = { version = "0.1.15", path = "internal" }
17+
data-encoding = { version = "2.9.0-git", path = "..", default-features = false }
18+
data-encoding-macro-internal = { version = "0.1.16-git", path = "internal" }

lib/macro/internal/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "data-encoding-macro-internal"
3-
version = "0.1.15"
3+
version = "0.1.16-git"
44
authors = ["Julien Cretin <[email protected]>"]
55
license = "MIT"
66
edition = "2018"
@@ -14,7 +14,7 @@ include = ["Cargo.toml", "LICENSE", "README.md", "src/lib.rs"]
1414
proc-macro = true
1515

1616
[dependencies.data-encoding]
17-
version = "2.8.0"
17+
version = "2.9.0-git"
1818
path = "../.."
1919
default-features = false
2020
features = ["alloc"]

lib/src/lib.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,34 @@ impl Encoding {
12981298
}
12991299
}
13001300

1301+
/// Encodes `input` in `output` and returns it as a `&str`
1302+
///
1303+
/// It is guaranteed that `output` and the return value only differ by their type. They both
1304+
/// point to the same range of memory (pointer and length).
1305+
///
1306+
/// # Panics
1307+
///
1308+
/// Panics if the `output` length does not match the result of [`encode_len`] for the `input`
1309+
/// length.
1310+
///
1311+
/// # Examples
1312+
///
1313+
/// ```rust
1314+
/// use data_encoding::BASE64;
1315+
/// # let mut buffer = vec![0; 100];
1316+
/// let input = b"Hello world";
1317+
/// let output = &mut buffer[0 .. BASE64.encode_len(input.len())];
1318+
/// assert_eq!(BASE64.encode_mut_str(input, output), "SGVsbG8gd29ybGQ=");
1319+
/// ```
1320+
///
1321+
/// [`encode_len`]: struct.Encoding.html#method.encode_len
1322+
pub fn encode_mut_str<'a>(&self, input: &[u8], output: &'a mut [u8]) -> &'a str {
1323+
self.encode_mut(input, output);
1324+
safety_assert!(output.is_ascii());
1325+
// SAFETY: Ensured by correctness guarantees of encode_mut (and asserted above).
1326+
unsafe { core::str::from_utf8_unchecked(output) }
1327+
}
1328+
13011329
/// Appends the encoding of `input` to `output`
13021330
///
13031331
/// # Examples

0 commit comments

Comments
 (0)