| // Copyright 2021 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use { |
| crate::node_path::NodePath, |
| serde::{ |
| de::{self, Deserializer, Visitor}, |
| Deserialize, Serialize, Serializer, |
| }, |
| std::{error::Error, fmt}, |
| }; |
| |
| /// Serialize `NodePath` into a path-like slash-separated a string |
| /// representation of the underlying child monikers. |
| // |
| /// Example: "/alpha:2/beta:0/gamma:1". |
| impl Serialize for NodePath { |
| fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
| where |
| S: Serializer, |
| { |
| let path = format!("/{}", self.as_vec().join("/")); |
| serializer.serialize_str(&path) |
| } |
| } |
| |
| struct NodePathVisitor; |
| |
| /// Deserialize `NodePath` from path-like slash-separated string of child |
| /// monikers. |
| impl<'de> Visitor<'de> for NodePathVisitor { |
| type Value = NodePath; |
| |
| fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { |
| formatter.write_str("A component tree node path") |
| } |
| |
| fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> |
| where |
| E: de::Error, |
| { |
| Ok(NodePath::new( |
| value |
| .split("/") |
| .filter_map( |
| |component| { |
| if component.is_empty() { |
| None |
| } else { |
| Some(component.into()) |
| } |
| }, |
| ) |
| .collect(), |
| )) |
| } |
| } |
| |
| impl<'de> Deserialize<'de> for NodePath { |
| fn deserialize<D>(deserializer: D) -> Result<NodePath, D::Error> |
| where |
| D: Deserializer<'de>, |
| { |
| deserializer.deserialize_str(NodePathVisitor) |
| } |
| } |
| |
| /// Error for use with serialization: Stores both structured error and message, |
| /// and assesses equality using structured error. |
| #[derive(Clone, Default, Deserialize, Serialize)] |
| pub struct ErrorWithMessage<E: Clone + Error + Serialize> { |
| pub error: E, |
| #[serde(default)] |
| pub message: String, |
| } |
| |
| impl<E: Clone + Error + PartialEq + Serialize> PartialEq<ErrorWithMessage<E>> |
| for ErrorWithMessage<E> |
| { |
| fn eq(&self, other: &Self) -> bool { |
| // Ignore `message` when comparing. |
| self.error == other.error |
| } |
| } |
| |
| impl<'de, E> From<E> for ErrorWithMessage<E> |
| where |
| E: Clone + Deserialize<'de> + Error + Serialize, |
| { |
| fn from(error: E) -> Self { |
| Self::from(&error) |
| } |
| } |
| |
| impl<'de, E> From<&E> for ErrorWithMessage<E> |
| where |
| E: Clone + Deserialize<'de> + Error + Serialize, |
| { |
| fn from(error: &E) -> Self { |
| let message = error.to_string(); |
| let error = error.clone(); |
| Self { error, message } |
| } |
| } |