1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// Copyright (C) 2019-2024 Aleo Systems Inc.
// This file is part of the Leo library.

// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.

//! Provides custom serialize/deserialize implementations for `Span`.

use crate::Span;

use serde::{
    Deserializer,
    Serializer,
    de::{MapAccess, Visitor},
    ser::SerializeMap,
};
use std::fmt;

/// The AST contains a few tuple-like enum variants that contain spans.
/// #[derive(Serialize, Deserialize)] outputs these fields as anonymous
/// mappings, which makes them difficult to remove from the JSON AST.
/// This function provides a custom serialization that maps the keyword
/// `span` to the span information.
pub fn serialize<S: Serializer>(span: &Span, serializer: S) -> Result<S::Ok, S::Error> {
    let mut map = serializer.serialize_map(Some(1))?;
    map.serialize_entry("span", span)?;
    map.end()
}

/// Custom deserialization to enable removing spans from enums.
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Span, D::Error> {
    deserializer.deserialize_map(SpanMapVisitor)
}

/// This visitor is used by the deserializer to unwrap mappings
/// and extract span information.
struct SpanMapVisitor;

impl<'de> Visitor<'de> for SpanMapVisitor {
    type Value = Span;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("mapping from `span` keyword to span information")
    }

    fn visit_map<M: MapAccess<'de>>(self, mut access: M) -> Result<Self::Value, M::Error> {
        let (_, value): (String, Span) = access.next_entry()?.unwrap();
        Ok(value)
    }
}