/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::{collections::BTreeSet, hash::Hash}; use anyhow::Result; use indexmap::{IndexMap, IndexSet}; /// Trait for converting one node type to another /// /// This can be auto-implemented using `#[derive(MapNode)]` for nodes that: /// /// - Have not added any fields (removed is okay) /// - All fields implement `MapNode` for the previous node type. /// /// The `context` argument exists to support manual implementations. It allows ancestor nodes to /// pass down data for child nodes to use. For example the namespace name or current `self_type`. pub trait MapNode { fn map_node(self, context: &Context) -> Result where Self: Sized; } macro_rules! simple_nodes { ($($ty:ty),* $(,)?) => { $( impl MapNode<$ty, C> for $ty { fn map_node(self, _context: &C) -> Result { Ok(self) } } )* }; } simple_nodes!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, String, bool,); impl MapNode, Context> for Box where Input: MapNode, { fn map_node(self, context: &Context) -> Result> { Input::map_node(*self, context).map(Box::new) } } impl MapNode, Context> for Option where Input: MapNode, { fn map_node(self, context: &Context) -> Result> { self.map(|input| Input::map_node(input, context)) .transpose() } } impl MapNode, Context> for Vec where Input: MapNode, { fn map_node(self, context: &Context) -> Result> { self.into_iter() .map(|input| Input::map_node(input, context)) .collect() } } impl MapNode, Context> for BTreeSet where Input: MapNode, Output: Ord, { fn map_node(self, context: &Context) -> Result> { self.into_iter() .map(|input| Input::map_node(input, context)) .collect() } } impl MapNode, Context> for IndexSet where Input: MapNode, Output: Hash + Eq, { fn map_node(self, context: &Context) -> Result> { self.into_iter() .map(|input| Input::map_node(input, context)) .collect() } } impl MapNode, Context> for IndexMap where InputKey: MapNode, InputValue: MapNode, OutputKey: Hash + Eq, { fn map_node(self, context: &Context) -> Result> { self.into_iter() .map(|(key, value)| { Ok(( InputKey::map_node(key, context)?, InputValue::map_node(value, context)?, )) }) .collect() } }