pg_embedded_setup_unpriv/extensions/
name.rs1use std::fmt;
4
5use color_eyre::eyre::eyre;
6
7use super::extension_error;
8use crate::error::{BootstrapErrorKind, BootstrapResult};
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24pub struct ExtensionName(String);
25
26impl ExtensionName {
27 pub fn new(name: impl Into<String>) -> BootstrapResult<Self> {
34 let value = name.into();
35 if value.is_empty() || !value.bytes().all(is_name_byte) {
36 return Err(extension_error(
37 BootstrapErrorKind::ExtensionConfigInvalid,
38 eyre!(
39 "extension name {value:?} is invalid; names use lower-case letters, digits \
40 and underscores"
41 ),
42 ));
43 }
44 Ok(Self(value))
45 }
46
47 #[must_use]
49 pub fn as_str(&self) -> &str { &self.0 }
50}
51
52const fn is_name_byte(byte: u8) -> bool {
55 byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'_'
56}
57
58impl AsRef<str> for ExtensionName {
59 fn as_ref(&self) -> &str { &self.0 }
60}
61
62impl TryFrom<&str> for ExtensionName {
63 type Error = crate::error::BootstrapError;
64
65 fn try_from(value: &str) -> Result<Self, Self::Error> { Self::new(value) }
66}
67
68impl fmt::Display for ExtensionName {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.0) }
70}