use base64::{
Engine as _, alphabet,
engine::{
DecodePaddingMode,
general_purpose::{GeneralPurpose, GeneralPurposeConfig, STANDARD as BASE64},
},
};
use serde::{Deserialize, Serialize};
use super::{PolyglotError, TursoValue};
const BLOB_DECODER: GeneralPurpose = GeneralPurpose::new(
&alphabet::STANDARD,
GeneralPurposeConfig::new().with_decode_padding_mode(DecodePaddingMode::Indifferent),
);
#[derive(Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub(super) enum WireValue {
Null,
Integer { value: String },
Float { value: f64 },
Text { value: String },
Blob { base64: String },
}
impl From<TursoValue> for WireValue {
fn from(value: TursoValue) -> Self {
match value {
TursoValue::Null => Self::Null,
TursoValue::Integer(value) => Self::Integer {
value: value.to_string(),
},
TursoValue::Real(value) => Self::Float { value },
TursoValue::Text(value) => Self::Text { value },
TursoValue::Blob(value) => Self::Blob {
base64: BASE64.encode(value),
},
}
}
}
impl TryFrom<WireValue> for TursoValue {
type Error = PolyglotError;
fn try_from(value: WireValue) -> Result<Self, Self::Error> {
match value {
WireValue::Null => Ok(Self::Null),
WireValue::Integer { value } => value
.parse()
.map(Self::Integer)
.map_err(PolyglotError::serialization),
WireValue::Float { value } => Ok(Self::Real(value)),
WireValue::Text { value } => Ok(Self::Text(value)),
WireValue::Blob { base64 } => BLOB_DECODER
.decode(base64)
.map(Self::Blob)
.map_err(PolyglotError::serialization),
}
}
}