use qubit_budget::ResourceQuantity;
use qubit_budget::json::JsonResource;
use qubit_budget::json::JsonValueBudget;
use qubit_budget::json::JsonValueLimits;
use qubit_budget::json::JsonValueTransaction;
use serde::Serialize;
use serde_json::Value;
use self::internal::JsonValueEncodeContext;
use self::internal::JsonValueEncodeFailure;
use self::internal::JsonValueSerializer;
use crate::encode::JsonSerializationError;
use crate::value::JsonValueEncodeError;
use crate::value::SafeJsonValue;
mod internal;
#[derive(Debug, Clone, Copy, Default)]
pub struct JsonValueEncoder {
private: (),
}
impl JsonValueEncoder {
#[must_use]
#[inline(always)]
pub const fn new() -> Self {
Self { private: () }
}
pub fn encode<T>(&self, value: &T) -> Result<Value, JsonSerializationError>
where
T: Serialize + ?Sized,
{
let () = self.private;
let mut budget = JsonValueBudget::new(JsonValueLimits::<JsonResource, usize>::new());
let mut transaction = budget.transaction();
let owner = match self.encode_in_transaction(value, &mut transaction) {
Ok(owner) => owner,
Err(JsonValueEncodeError::Serialization(error)) => return Err(error),
Err(JsonValueEncodeError::Budget(_)) => {
return Err(JsonSerializationError::new(
crate::encode::JsonSerializationErrorKind::CustomSerialization,
));
}
Err(JsonValueEncodeError::PrivateTextLimitExceeded { .. }) => {
return Err(JsonSerializationError::new(
crate::encode::JsonSerializationErrorKind::CustomSerialization,
));
}
};
transaction.commit().map_err(|_| {
JsonSerializationError::new(
crate::encode::JsonSerializationErrorKind::CustomSerialization,
)
})?;
Ok(owner.into_value())
}
pub fn encode_in_transaction<T, R, Q>(
&self,
value: &T,
transaction: &mut JsonValueTransaction<'_, R, Q>,
) -> Result<SafeJsonValue, JsonValueEncodeError<R, Q>>
where
T: Serialize + ?Sized,
R: Clone,
Q: ResourceQuantity,
{
self.encode_in_transaction_impl(value, transaction, None)
}
pub fn encode_in_transaction_with_private_text_limit<T, R, Q>(
&self,
value: &T,
transaction: &mut JsonValueTransaction<'_, R, Q>,
max_private_text_bytes: usize,
) -> Result<SafeJsonValue, JsonValueEncodeError<R, Q>>
where
T: Serialize + ?Sized,
R: Clone,
Q: ResourceQuantity,
{
self.encode_in_transaction_impl(value, transaction, Some(max_private_text_bytes))
}
fn encode_in_transaction_impl<T, R, Q>(
&self,
value: &T,
transaction: &mut JsonValueTransaction<'_, R, Q>,
max_private_text_bytes: Option<usize>,
) -> Result<SafeJsonValue, JsonValueEncodeError<R, Q>>
where
T: Serialize + ?Sized,
R: Clone,
Q: ResourceQuantity,
{
let context = std::cell::RefCell::new(JsonValueEncodeContext::new(
transaction,
max_private_text_bytes,
));
let result = value.serialize(JsonValueSerializer::new(&context, 1));
if let Err(error) = result.as_ref() {
let _ = context.borrow_mut().record_serialization_error(*error);
}
match context.into_inner().take_failure() {
Some(JsonValueEncodeFailure::Budget(error)) => Err(JsonValueEncodeError::Budget(error)),
Some(JsonValueEncodeFailure::Serialization(error)) => {
Err(JsonValueEncodeError::Serialization(error))
}
Some(JsonValueEncodeFailure::PrivateTextLimitExceeded { maximum }) => {
Err(JsonValueEncodeError::PrivateTextLimitExceeded { maximum })
}
None => result.map_err(JsonValueEncodeError::Serialization),
}
}
}