mod builder;
mod streaming;
mod validation;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _};
use serde_json::{Map, Value, json};
use crate::Result;
pub use builder::{CardBuilder, CardButtonStyle, CardElement};
pub(crate) use streaming::validate_card_element_content;
pub use streaming::{
CardElementContent, CardSettings, CardStreamingConfig, CardStreamingPlatformValues,
CardStreamingPrintStrategy, MAX_CARD_ELEMENT_CONTENT_CHARS,
};
pub use validation::MAX_CARD_JSON_BYTES;
use validation::validate_card_id;
pub(crate) use validation::validate_element_id;
const CARD_SCHEMA: &str = "2.0";
#[derive(Debug, Clone, PartialEq)]
pub struct Card(Value);
impl Card {
pub fn builder() -> CardBuilder {
CardBuilder::new()
}
pub fn from_value(value: Value) -> Result<Self> {
let card = Self(value);
card.validate()?;
Ok(card)
}
pub fn raw(body: Value) -> Result<Self> {
Self::from_value(json!({
"schema": CARD_SCHEMA,
"body": body,
}))
}
pub fn as_value(&self) -> &Value {
&self.0
}
pub fn into_value(self) -> Value {
self.0
}
pub(crate) fn from_parts(
config: Map<String, Value>,
header: Option<Value>,
elements: Vec<Value>,
) -> Result<Self> {
let mut root = Map::new();
root.insert("schema".to_owned(), Value::String(CARD_SCHEMA.to_owned()));
root.insert("config".to_owned(), Value::Object(config));
if let Some(header) = header {
root.insert("header".to_owned(), header);
}
root.insert("body".to_owned(), json!({ "elements": elements }));
Self::from_value(Value::Object(root))
}
}
impl Serialize for Card {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Card {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Self::from_value(Value::deserialize(deserializer)?).map_err(D::Error::custom)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
#[serde(transparent)]
pub struct CardId(pub String);
impl CardId {
pub fn new(card_id: impl Into<String>) -> Result<Self> {
let card_id = card_id.into();
validate_card_id(&card_id)?;
Ok(Self(card_id))
}
pub fn as_str(&self) -> &str {
&self.0
}
pub(crate) fn validate(&self) -> Result<()> {
validate_card_id(&self.0)
}
}
impl<'de> Deserialize<'de> for CardId {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Self::new(String::deserialize(deserializer)?).map_err(D::Error::custom)
}
}