use std::error::Error;
use std::fmt;
pub const EXACT_TEXT_PROFILE_VERSION_V1: u16 = 1;
pub const EXACT_TEXT_PROVIDER_STATE_SCHEMA_HASH_V1: [u8; 32] = [
0x9b, 0x8a, 0x2f, 0x7e, 0xd9, 0xfd, 0xf1, 0xc5, 0xd9, 0x68, 0x8f, 0xbd, 0x39, 0xad, 0x3d, 0x86,
0x20, 0x70, 0xa7, 0x17, 0x74, 0xdc, 0x77, 0x4d, 0x0c, 0xe0, 0x0e, 0xdb, 0x69, 0x1a, 0x1e, 0x40,
];
pub const EXACT_TEXT_PROVIDER_STATE_SCHEMA_HASH_V2: [u8; 32] = [
0x58, 0xa4, 0x1e, 0x51, 0x2c, 0x04, 0xef, 0x93, 0xe7, 0xc1, 0xfd, 0xb2, 0xbf, 0xfb, 0x2d, 0x44,
0xbb, 0x54, 0xfc, 0x76, 0xac, 0x61, 0xab, 0x8e, 0x47, 0x93, 0xf1, 0xf0, 0x1d, 0x2b, 0x2f, 0x8a,
];
pub const EXACT_TEXT_PROVIDER_STATE_SCHEMA_HASH_V3: [u8; 32] = [
0xda, 0x13, 0x39, 0xc5, 0x30, 0x4c, 0x8d, 0x9d, 0x90, 0x58, 0x74, 0x74, 0x1d, 0xf8, 0xd8, 0xa2,
0x9a, 0xe8, 0xa6, 0x14, 0xbd, 0x11, 0xe5, 0x53, 0xc7, 0xd9, 0xfc, 0xd0, 0x06, 0x8f, 0xcc, 0x4b,
];
pub const EXACT_PREDICATE_PROVIDER_STATE_SCHEMA_HASH_V4: [u8; 32] = [
0x60, 0xe6, 0x99, 0xf7, 0x7d, 0x47, 0x2b, 0xb0, 0xc1, 0xa7, 0xc7, 0x78, 0x48, 0x8a, 0x6e, 0xf8,
0x9e, 0xe7, 0x7e, 0x04, 0x83, 0xdc, 0x62, 0x5e, 0x85, 0xdd, 0xc4, 0x0b, 0x88, 0xc2, 0x0a, 0x28,
];
pub const EXACT_PREDICATE_PROVIDER_STATE_SCHEMA_HASH_V5: [u8; 32] = [
0x7e, 0x64, 0x5e, 0x51, 0x89, 0x2e, 0x83, 0xca, 0x4e, 0x05, 0xaa, 0x24, 0xa4, 0x7a, 0xa9, 0x21,
0xc4, 0xc5, 0x86, 0xbc, 0xb9, 0x9d, 0x2a, 0x7e, 0x0b, 0x4a, 0x0f, 0x13, 0x39, 0x47, 0xc0, 0xa1,
];
pub const MAX_EXACT_TEXT_VALUE_BYTES_V1: usize = 256;
pub const MAX_EXACT_TEXT_OUTPUT_ROW_BYTES_V1: usize = 64 * 1024;
pub const MAX_EXACT_TEXT_NEEDLE_BYTES_V1: usize = 64;
pub const MAX_EXACT_TEXT_ROWS_PER_PARTITION_V1: usize = 4_096;
pub const MAX_EXACT_TEXT_TERMS_PER_ROW_V1: usize =
MAX_EXACT_TEXT_VALUE_BYTES_V1 * (MAX_EXACT_TEXT_VALUE_BYTES_V1 + 1) / 2;
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum ExactTextProfileV1 {
BinaryUtf8V1 = 1,
UnicodeFoldV1 = 2,
}
impl ExactTextProfileV1 {
#[must_use]
pub const fn from_discriminant(value: u8) -> Option<Self> {
match value {
1 => Some(Self::BinaryUtf8V1),
2 => Some(Self::UnicodeFoldV1),
_ => None,
}
}
#[must_use]
pub fn matched_form(self, value: &str) -> String {
match self {
Self::BinaryUtf8V1 => value.to_owned(),
Self::UnicodeFoldV1 => crate::unicode_fold_v1(value),
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum ExactTextOperatorV1 {
Equals = 1,
StartsWith = 2,
EndsWith = 3,
Contains = 4,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum ExactTextOrderV1 {
ValueAscEntityKey = 1,
ValueDescEntityKey = 2,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ExactTextFieldValueV1<'a> {
Missing,
Null,
Value(&'a str),
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ExactTextNeedleV1(String);
impl ExactTextNeedleV1 {
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
#[must_use]
pub fn to_canonical_bytes(&self) -> Vec<u8> {
let bytes = self.0.as_bytes();
let mut output = Vec::with_capacity(8 + bytes.len());
output.extend_from_slice(b"RXTN");
output.extend_from_slice(&EXACT_TEXT_PROFILE_VERSION_V1.to_be_bytes());
output.extend_from_slice(&(bytes.len() as u16).to_be_bytes());
output.extend_from_slice(bytes);
output
}
}
impl ExactTextProfileV1 {
pub fn bind_needle(self, value: &str) -> Result<ExactTextNeedleV1, ExactTextBindErrorV1> {
if value.is_empty() {
return Err(ExactTextBindErrorV1::EmptyNeedle);
}
let bound = self.matched_form(value);
if bound.len() > MAX_EXACT_TEXT_NEEDLE_BYTES_V1 {
return Err(ExactTextBindErrorV1::NeedleTooLong);
}
if bound.is_empty() {
return Err(ExactTextBindErrorV1::EmptyNeedle);
}
Ok(ExactTextNeedleV1(bound))
}
#[must_use]
pub fn matches(
self,
operator: ExactTextOperatorV1,
value: ExactTextFieldValueV1<'_>,
needle: &ExactTextNeedleV1,
) -> bool {
let ExactTextFieldValueV1::Value(value) = value else {
return false;
};
match operator {
ExactTextOperatorV1::Equals => value == needle.as_str(),
ExactTextOperatorV1::StartsWith => value.starts_with(needle.as_str()),
ExactTextOperatorV1::EndsWith => value.ends_with(needle.as_str()),
ExactTextOperatorV1::Contains => value.contains(needle.as_str()),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ExactTextBindErrorV1 {
EmptyNeedle,
NeedleTooLong,
}
impl fmt::Display for ExactTextBindErrorV1 {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(match self {
Self::EmptyNeedle => "exact text needle must not be empty",
Self::NeedleTooLong => "exact text needle exceeds its compiled bound",
})
}
}
impl Error for ExactTextBindErrorV1 {}
crate::inspect_owned_capacity_copy_v1!(ExactTextOperatorV1);
crate::inspect_owned_capacity_copy_v1!(ExactTextOrderV1);
crate::inspect_owned_capacity_copy_v1!(ExactTextProfileV1);