spotify_id.rs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. use byteorder::{BigEndian, ByteOrder};
  2. use extprim::u128::u128;
  3. use std;
  4. use std::fmt;
  5. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
  6. pub struct SpotifyId(u128);
  7. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
  8. pub struct SpotifyIdError;
  9. const BASE62_DIGITS: &'static [u8] = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  10. const BASE16_DIGITS: &'static [u8] = b"0123456789abcdef";
  11. impl SpotifyId {
  12. pub fn from_base16(id: &str) -> Result<SpotifyId, SpotifyIdError> {
  13. let data = id.as_bytes();
  14. let mut n: u128 = u128::zero();
  15. for c in data {
  16. let d = match BASE16_DIGITS.iter().position(|e| e == c) {
  17. None => return Err(SpotifyIdError),
  18. Some(x) => x as u64,
  19. };
  20. n = n * u128::new(16);
  21. n = n + u128::new(d);
  22. }
  23. Ok(SpotifyId(n))
  24. }
  25. pub fn from_base62(id: &str) -> Result<SpotifyId, SpotifyIdError> {
  26. let data = id.as_bytes();
  27. let mut n: u128 = u128::zero();
  28. for c in data {
  29. let d = match BASE62_DIGITS.iter().position(|e| e == c) {
  30. None => return Err(SpotifyIdError),
  31. Some(x) => x as u64,
  32. };
  33. n = n * u128::new(62);
  34. n = n + u128::new(d);
  35. }
  36. Ok(SpotifyId(n))
  37. }
  38. pub fn from_raw(data: &[u8]) -> Result<SpotifyId, SpotifyIdError> {
  39. if data.len() != 16 {
  40. return Err(SpotifyIdError);
  41. };
  42. let high = BigEndian::read_u64(&data[0..8]);
  43. let low = BigEndian::read_u64(&data[8..16]);
  44. Ok(SpotifyId(u128::from_parts(high, low)))
  45. }
  46. pub fn to_base16(&self) -> String {
  47. let &SpotifyId(ref n) = self;
  48. let mut data = [0u8; 32];
  49. for i in 0..32 {
  50. data[31 - i] = BASE16_DIGITS[(n.wrapping_shr(4 * i as u32).low64() & 0xF) as usize];
  51. }
  52. std::str::from_utf8(&data).unwrap().to_owned()
  53. }
  54. pub fn to_base62(&self) -> String {
  55. let &SpotifyId(mut n) = self;
  56. let mut data = [0u8; 22];
  57. let sixty_two = u128::new(62);
  58. for i in 0..22 {
  59. data[21 - i] = BASE62_DIGITS[(n % sixty_two).low64() as usize];
  60. n /= sixty_two;
  61. }
  62. std::str::from_utf8(&data).unwrap().to_owned()
  63. }
  64. pub fn to_raw(&self) -> [u8; 16] {
  65. let &SpotifyId(ref n) = self;
  66. let mut data = [0u8; 16];
  67. BigEndian::write_u64(&mut data[0..8], n.high64());
  68. BigEndian::write_u64(&mut data[8..16], n.low64());
  69. data
  70. }
  71. }
  72. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
  73. pub struct FileId(pub [u8; 20]);
  74. impl FileId {
  75. pub fn to_base16(&self) -> String {
  76. self.0
  77. .iter()
  78. .map(|b| format!("{:02x}", b))
  79. .collect::<Vec<String>>()
  80. .concat()
  81. }
  82. }
  83. impl fmt::Debug for FileId {
  84. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  85. f.debug_tuple("FileId").field(&self.to_base16()).finish()
  86. }
  87. }
  88. impl fmt::Display for FileId {
  89. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  90. f.write_str(&self.to_base16())
  91. }
  92. }