pub use crate::declaration::{
COUNT_LIMIT, Container, ContentDeclaration, FieldDeclaration, Formats, GroupDeclaration,
ItemKind, Limits, depth,
};
use crate::form::CheckedSlot;
pub use crate::form::{CheckedValue, GroupFields};
use crate::{FieldValue, Upload, field_value::Charset};
use std::any::Any;
#[diagnostic::on_unimplemented(
message = "`{Self}` cannot be a field of a `Content` declaration",
label = "not a field type",
note = "a field is `String`, `Vec<u8>`, an integer, `f32`, `f64`, `bool`, a `FieldValue`, an `Upload`, or a struct deriving `Content`, in `Option` when it may be omitted, or `Vec` for an array"
)]
pub trait ItemDeclaration {
const KIND: ItemKind;
}
pub trait Item<H>: ItemDeclaration + Sized {
fn build(value: CheckedValue<H>) -> Self;
}
pub trait Declaration {
const DECLARATION: ContentDeclaration;
}
impl<T: FieldValue> ItemDeclaration for T {
const KIND: ItemKind = ItemKind::Scalar(convert_text::<T>);
}
impl<H, T: FieldValue> Item<H> for T {
fn build(value: CheckedValue<H>) -> Self {
scalar(value)
}
}
impl ItemDeclaration for Vec<u8> {
const KIND: ItemKind = ItemKind::Scalar(convert_bytes);
}
impl<H> Item<H> for Vec<u8> {
fn build(value: CheckedValue<H>) -> Self {
scalar(value)
}
}
impl<H> ItemDeclaration for Upload<H> {
const KIND: ItemKind = ItemKind::Upload;
}
impl<H> Item<H> for Upload<H> {
fn build(value: CheckedValue<H>) -> Self {
match value {
CheckedValue::Upload(upload) => upload,
_ => unreachable!("an upload field holds an upload"),
}
}
}
fn convert_text<T: FieldValue>(bytes: Vec<u8>, charset: Charset) -> Option<Box<dyn Any>> {
let text = charset.decode(bytes)?;
let value = T::from_field_text(&text).ok()?;
Some(Box::new(value))
}
fn convert_bytes(bytes: Vec<u8>, _charset: Charset) -> Option<Box<dyn Any>> {
Some(Box::new(bytes))
}
fn scalar<T: 'static, H>(value: CheckedValue<H>) -> T {
match value {
CheckedValue::Scalar(value) => *value
.downcast()
.expect("a scalar field holds the value its declaration converted"),
_ => unreachable!("a scalar field holds a converted value"),
}
}
pub fn group_fields<H>(value: CheckedValue<H>) -> GroupFields<H> {
match value {
CheckedValue::Group(slots) => GroupFields::new(slots),
_ => unreachable!("a nested group's field holds a group"),
}
}
pub fn required<H, T: Item<H>>(fields: &mut GroupFields<H>) -> T {
match fields.next_slot() {
CheckedSlot::Single(value) => T::build(value),
_ => unreachable!("a required field that was checked has a value"),
}
}
pub fn optional<H, T: Item<H>>(fields: &mut GroupFields<H>) -> Option<T> {
match fields.next_slot() {
CheckedSlot::Absent => None,
CheckedSlot::Single(value) => Some(T::build(value)),
CheckedSlot::Array(_) => unreachable!("an optional field holds one value"),
}
}
pub fn array<H, T: Item<H>>(fields: &mut GroupFields<H>) -> Vec<T> {
match fields.next_slot() {
CheckedSlot::Array(values) => values.into_iter().map(T::build).collect(),
_ => unreachable!("a required array that was checked has elements"),
}
}
pub fn optional_array<H, T: Item<H>>(fields: &mut GroupFields<H>) -> Option<Vec<T>> {
match fields.next_slot() {
CheckedSlot::Absent => None,
CheckedSlot::Array(values) => Some(values.into_iter().map(T::build).collect()),
CheckedSlot::Single(_) => unreachable!("an array field holds elements"),
}
}