1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use super::traits::{Name, ParseBytes};
use crate::{
  field_parsing_error, impl_name,
  result::{SQLiteError, SQLiteResult},
};
use core::fmt::Display;

/// # Text encoding(4 Bytes)
///
///  The 4-byte big-endian integer at offset 56 determines the encoding used for
/// all text strings stored in the database. A value of 1 means UTF-8. A value
/// of 2 means UTF-16le. A value of 3 means UTF-16be. No other values are
/// allowed. The sqlite3.h header file defines C-preprocessor macros
/// SQLITE_UTF8 as 1, SQLITE_UTF16LE as 2, and SQLITE_UTF16BE as 3, to use in
/// place of the numeric codes for the text encoding.
#[derive(Debug)]
pub enum DatabaseTextEncoding {
  Utf8,
  Utf16Le,
  Utf16Be,
}

impl From<&DatabaseTextEncoding> for u32 {
  fn from(value: &DatabaseTextEncoding) -> Self {
    match value {
      DatabaseTextEncoding::Utf8 => 1,
      DatabaseTextEncoding::Utf16Le => 2,
      DatabaseTextEncoding::Utf16Be => 3,
    }
  }
}

impl TryFrom<u32> for DatabaseTextEncoding {
  type Error = SQLiteError;

  fn try_from(value: u32) -> Result<Self, Self::Error> {
    match value {
      1 => Ok(Self::Utf8),
      2 => Ok(Self::Utf16Le),
      3 => Ok(Self::Utf16Be),
      _ => Err(field_parsing_error! {Self::NAME}),
    }
  }
}

impl Display for DatabaseTextEncoding {
  fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
    let number = u32::from(self);
    let name = match self {
      DatabaseTextEncoding::Utf8 => "utf8",
      DatabaseTextEncoding::Utf16Le => "utf16le",
      DatabaseTextEncoding::Utf16Be => "utf16le",
    };
    write!(f, "{number} ({name})")
  }
}

impl_name! {DatabaseTextEncoding}

impl ParseBytes for DatabaseTextEncoding {
  const LENGTH_BYTES: usize = 4;

  fn parsing_handler(bytes: &[u8]) -> SQLiteResult<Self> {
    let buf: [u8; Self::LENGTH_BYTES] = bytes.try_into()?;

    let value = u32::from_be_bytes(buf);

    value.try_into()
  }
}