Skip to content

Commit ceebb37

Browse files
authored
Remove unsafe code (#940)
Remove unsafe code
1 parent c6e97a7 commit ceebb37

6 files changed

Lines changed: 295 additions & 150 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2828
- [main] Prevent hang when discovery is disabled and there are no credentials or when bad credentials are given.
2929
- [main] Don't panic when parsing options. Instead list valid values and exit.
3030
- [main] `--alsa-mixer-device` and `--alsa-mixer-index` now fallback to the card and index specified in `--device`.
31+
- [core] Removed unsafe code (breaking)
3132

3233
### Removed
3334
- [playback] `alsamixer`: previously deprecated option `mixer-card` has been removed.

core/src/cache.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -351,12 +351,17 @@ impl Cache {
351351
}
352352

353353
fn file_path(&self, file: FileId) -> Option<PathBuf> {
354-
self.audio_location.as_ref().map(|location| {
355-
let name = file.to_base16();
356-
let mut path = location.join(&name[0..2]);
357-
path.push(&name[2..]);
358-
path
359-
})
354+
match file.to_base16() {
355+
Ok(name) => self.audio_location.as_ref().map(|location| {
356+
let mut path = location.join(&name[0..2]);
357+
path.push(&name[2..]);
358+
path
359+
}),
360+
Err(e) => {
361+
warn!("Invalid FileId: {}", e.utf8_error());
362+
None
363+
}
364+
}
360365
}
361366

362367
pub fn file(&self, file: FileId) -> Option<File> {

core/src/spotify_id.rs

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use std::convert::TryInto;
44
use std::fmt;
5+
use std::string::FromUtf8Error;
56

67
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
78
pub enum SpotifyAudioType {
@@ -136,15 +137,15 @@ impl SpotifyId {
136137

137138
/// Returns the `SpotifyId` as a base16 (hex) encoded, `SpotifyId::SIZE_BASE16` (32)
138139
/// character long `String`.
139-
pub fn to_base16(&self) -> String {
140+
pub fn to_base16(&self) -> Result<String, FromUtf8Error> {
140141
to_base16(&self.to_raw(), &mut [0u8; SpotifyId::SIZE_BASE16])
141142
}
142143

143144
/// Returns the `SpotifyId` as a [canonically] base62 encoded, `SpotifyId::SIZE_BASE62` (22)
144145
/// character long `String`.
145146
///
146147
/// [canonically]: https://developer.spotify.com/documentation/web-api/#spotify-uris-and-ids
147-
pub fn to_base62(&self) -> String {
148+
pub fn to_base62(&self) -> Result<String, FromUtf8Error> {
148149
let mut dst = [0u8; 22];
149150
let mut i = 0;
150151
let n = self.id;
@@ -182,10 +183,7 @@ impl SpotifyId {
182183

183184
dst.reverse();
184185

185-
unsafe {
186-
// Safety: We are only dealing with ASCII characters.
187-
String::from_utf8_unchecked(dst.to_vec())
188-
}
186+
String::from_utf8(dst.to_vec())
189187
}
190188

191189
/// Returns a copy of the `SpotifyId` as an array of `SpotifyId::SIZE` (16) bytes in
@@ -202,25 +200,26 @@ impl SpotifyId {
202200
/// be encoded as `unknown`.
203201
///
204202
/// [Spotify URI]: https://developer.spotify.com/documentation/web-api/#spotify-uris-and-ids
205-
pub fn to_uri(&self) -> String {
203+
pub fn to_uri(&self) -> Result<String, FromUtf8Error> {
206204
// 8 chars for the "spotify:" prefix + 1 colon + 22 chars base62 encoded ID = 31
207205
// + unknown size audio_type.
208206
let audio_type: &str = self.audio_type.into();
209207
let mut dst = String::with_capacity(31 + audio_type.len());
210208
dst.push_str("spotify:");
211209
dst.push_str(audio_type);
212210
dst.push(':');
213-
dst.push_str(&self.to_base62());
211+
let base62 = self.to_base62()?;
212+
dst.push_str(&base62);
214213

215-
dst
214+
Ok(dst)
216215
}
217216
}
218217

219218
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
220219
pub struct FileId(pub [u8; 20]);
221220

222221
impl FileId {
223-
pub fn to_base16(&self) -> String {
222+
pub fn to_base16(&self) -> Result<String, FromUtf8Error> {
224223
to_base16(&self.0, &mut [0u8; 40])
225224
}
226225
}
@@ -233,23 +232,20 @@ impl fmt::Debug for FileId {
233232

234233
impl fmt::Display for FileId {
235234
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236-
f.write_str(&self.to_base16())
235+
f.write_str(&self.to_base16().unwrap_or_default())
237236
}
238237
}
239238

240239
#[inline]
241-
fn to_base16(src: &[u8], buf: &mut [u8]) -> String {
240+
fn to_base16(src: &[u8], buf: &mut [u8]) -> Result<String, FromUtf8Error> {
242241
let mut i = 0;
243242
for v in src {
244243
buf[i] = BASE16_DIGITS[(v >> 4) as usize];
245244
buf[i + 1] = BASE16_DIGITS[(v & 0x0f) as usize];
246245
i += 2;
247246
}
248247

249-
unsafe {
250-
// Safety: We are only dealing with ASCII characters.
251-
String::from_utf8_unchecked(buf.to_vec())
252-
}
248+
String::from_utf8(buf.to_vec())
253249
}
254250

255251
#[cfg(test)]
@@ -366,7 +362,7 @@ mod tests {
366362
audio_type: c.kind,
367363
};
368364

369-
assert_eq!(id.to_base62(), c.base62);
365+
assert_eq!(id.to_base62().unwrap(), c.base62);
370366
}
371367
}
372368

@@ -389,7 +385,7 @@ mod tests {
389385
audio_type: c.kind,
390386
};
391387

392-
assert_eq!(id.to_base16(), c.base16);
388+
assert_eq!(id.to_base16().unwrap(), c.base16);
393389
}
394390
}
395391

@@ -415,7 +411,7 @@ mod tests {
415411
audio_type: c.kind,
416412
};
417413

418-
assert_eq!(id.to_uri(), c.uri);
414+
assert_eq!(id.to_uri().unwrap(), c.uri);
419415
}
420416
}
421417

0 commit comments

Comments
 (0)