blob: db4a812f6707db37fe70f1f4a3bfe50e24f1e273 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
//! Three-state fields for vendor metadata where absence and explicit null have
//! distinct meanings. Business options that collapse null still use Option.
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug, Clone, Default)]
pub enum Field<T> {
#[default]
Missing,
Null,
Value(T),
}
impl<T> Field<T> {
pub fn is_missing(&self) -> bool {
matches!(self, Self::Missing)
}
pub fn value(&self) -> Option<&T> {
match self {
Self::Value(value) => Some(value),
_ => None,
}
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Field<T> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Ok(match Option::<T>::deserialize(deserializer)? {
Some(value) => Self::Value(value),
None => Self::Null,
})
}
}
impl<T: Serialize> Serialize for Field<T> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Self::Value(value) => value.serialize(serializer),
Self::Null | Self::Missing => serializer.serialize_none(),
}
}
}