blob: 0a4d66be49109a5fc606ca0920ff96416d5b5339 [file] [log] [blame]
// Copyright 2022 The Blaze Authors
//
// Licensed 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.
//! Plan serde error types
use std::{
error::Error,
fmt::{Display, Formatter},
io, result,
};
use arrow::error::ArrowError;
use datafusion::error::DataFusionError;
pub type Result<T> = result::Result<T, PlanSerDeError>;
#[derive(Debug)]
pub enum PlanSerDeError {
NotImplemented(String),
General(String),
Internal(String),
ArrowError(ArrowError),
DataFusionError(DataFusionError),
IoError(io::Error),
MissingRequiredField(String),
UnknownEnumVariant { name: String, value: i32 },
}
#[allow(clippy::from_over_into)]
impl<T> Into<Result<T>> for PlanSerDeError {
fn into(self) -> Result<T> {
Err(self)
}
}
pub fn serde_error(message: &str) -> PlanSerDeError {
PlanSerDeError::General(message.to_owned())
}
impl From<String> for PlanSerDeError {
fn from(e: String) -> Self {
PlanSerDeError::General(e)
}
}
impl From<ArrowError> for PlanSerDeError {
fn from(e: ArrowError) -> Self {
PlanSerDeError::ArrowError(e)
}
}
impl From<DataFusionError> for PlanSerDeError {
fn from(e: DataFusionError) -> Self {
PlanSerDeError::DataFusionError(e)
}
}
impl From<io::Error> for PlanSerDeError {
fn from(e: io::Error) -> Self {
PlanSerDeError::IoError(e)
}
}
impl Display for PlanSerDeError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
PlanSerDeError::NotImplemented(ref desc) => {
write!(f, "Not implemented: {}", desc)
}
PlanSerDeError::General(ref desc) => write!(f, "General error: {}", desc),
PlanSerDeError::ArrowError(ref desc) => write!(f, "Arrow error: {}", desc),
PlanSerDeError::DataFusionError(ref desc) => {
write!(f, "DataFusion error: {:?}", desc)
}
PlanSerDeError::IoError(ref desc) => write!(f, "IO error: {}", desc),
PlanSerDeError::Internal(desc) => {
write!(f, "Internal error: {}", desc)
}
Self::MissingRequiredField(name) => {
write!(f, "Missing required field {}", name)
}
Self::UnknownEnumVariant { name, value } => {
write!(f, "Unknown i32 value for {} enum: {}", name, value)
}
}
}
}
impl Error for PlanSerDeError {}
impl PlanSerDeError {
pub(crate) fn required(field: impl Into<String>) -> PlanSerDeError {
PlanSerDeError::MissingRequiredField(field.into())
}
}
/// An extension trait that adds the methods `optional` and `required` to any
/// Option containing a type implementing `TryInto<U, Error = Error>`
pub trait FromOptionalField<T> {
/// Converts an optional protobuf field to an option of a different type
///
/// Returns None if the option is None, otherwise calls [`FromField::field`]
/// on the contained data, returning any error encountered
fn optional(self) -> std::result::Result<Option<T>, PlanSerDeError>;
/// Converts an optional protobuf field to a different type, returning an
/// error if None
///
/// Returns `Error::MissingRequiredField` if None, otherwise calls
/// [`FromField::field`] on the contained data, returning any error
/// encountered
fn required(self, field: impl Into<String>) -> std::result::Result<T, PlanSerDeError>;
}
impl<T, U> FromOptionalField<U> for Option<T>
where
T: TryInto<U, Error = PlanSerDeError>,
{
fn optional(self) -> std::result::Result<Option<U>, PlanSerDeError> {
self.map(|t| t.try_into()).transpose()
}
fn required(self, field: impl Into<String>) -> std::result::Result<U, PlanSerDeError> {
match self {
None => Err(PlanSerDeError::required(field)),
Some(t) => t.try_into(),
}
}
}