Skip to content

Commit

Permalink
Merge pull request #8 from dtolnay/serialize
Browse files Browse the repository at this point in the history
Provide Serialize impl for Node<T>
  • Loading branch information
dtolnay authored Apr 28, 2021
2 parents 391687d + b194e2f commit baff38b
Show file tree
Hide file tree
Showing 7 changed files with 528 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
strategy:
fail-fast: false
matrix:
rust: [beta, stable, 1.45.0]
rust: [beta, stable, 1.46.0]
steps:
- uses: actions/checkout@v2
- uses: dtolnay/rust-toolchain@master
Expand Down
23 changes: 23 additions & 0 deletions src/dedup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use std::cell::Cell;

thread_local! {
static REFCOUNT: Cell<usize> = Cell::new(0);
}

pub(crate) struct Guard {
_private: (),
}

pub(crate) fn activate() -> Guard {
REFCOUNT.with(|refcount| refcount.set(refcount.get() + 1));
Guard { _private: () }
}

impl Drop for Guard {
fn drop(&mut self) {
let prev = REFCOUNT.with(|refcount| refcount.replace(refcount.get() - 1));
if prev == 1 {
crate::loc::thread_local_reset();
}
}
}
10 changes: 10 additions & 0 deletions src/id.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use serde::de::{Deserialize, Deserializer, Error, Unexpected, Visitor};
use serde::ser::{Serialize, Serializer};
use std::fmt::{self, Debug, Display};

#[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
Expand Down Expand Up @@ -51,3 +52,12 @@ impl<'de> Deserialize<'de> for Id {
deserializer.deserialize_str(IdVisitor)
}
}

impl Serialize for Id {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_str(self)
}
}
14 changes: 14 additions & 0 deletions src/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use serde::de::{
DeserializeSeed, Deserializer, EnumAccess, Expected, IntoDeserializer, Unexpected,
VariantAccess, Visitor,
};
use serde::ser::{Serialize, Serializer};
use serde::{forward_to_deserialize_any, Deserialize};
use std::borrow::Cow;
use std::fmt::{self, Debug, Display};
Expand Down Expand Up @@ -274,6 +275,19 @@ impl<'de> Visitor<'de> for KindVisitor {
}
}

impl Serialize for Kind {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if let Kind::null = self {
serializer.serialize_unit()
} else {
serializer.serialize_str(self.as_str())
}
}
}

pub struct ParseKindError {
_private: (),
}
Expand Down
24 changes: 24 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,23 +388,28 @@
#![doc(html_root_url = "https://docs.rs/clang-ast/0.1.2")]
#![allow(
clippy::blocks_in_if_conditions,
clippy::let_underscore_drop,
clippy::must_use_candidate,
clippy::option_if_let_else,
clippy::ptr_arg
)]

mod dedup;
mod deserializer;
mod id;
mod intern;
mod kind;
mod loc;
mod serializer;

extern crate serde;

use crate::deserializer::NodeDeserializer;
use crate::kind::AnyKind;
use crate::serializer::NodeSerializer;
use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
use serde::ser::{Serialize, SerializeMap, Serializer};
use std::fmt;
use std::marker::PhantomData;

Expand Down Expand Up @@ -522,3 +527,22 @@ where
deserializer.deserialize_map(visitor)
}
}

impl<T> Serialize for Node<T>
where
T: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let _dedup = dedup::activate();
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("id", &self.id)?;
T::serialize(&self.kind, NodeSerializer::new(&mut map))?;
if !self.inner.is_empty() {
map.serialize_entry("inner", &self.inner)?;
}
map.end()
}
}
164 changes: 164 additions & 0 deletions src/loc.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::intern::InternVisitor;
use serde::de::{Deserialize, Deserializer, Error, IgnoredAny, MapAccess, Visitor};
use serde::ser::{Serialize, SerializeMap, Serializer};
use std::cell::{Cell, RefCell};
use std::fmt::{self, Debug};
use std::sync::Arc;
Expand Down Expand Up @@ -464,6 +465,169 @@ impl SourceLocationField {
}
}

impl Serialize for SourceRange {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("begin", &self.begin)?;
map.serialize_entry("end", &self.end)?;
map.end()
}
}

impl Serialize for SourceLocation {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
fn same_bare_source_location(
spelling_loc: &BareSourceLocation,
expansion_loc: &BareSourceLocation,
) -> bool {
let BareSourceLocation {
offset: spelling_offset,
file: spelling_file,
line: spelling_line,
presumed_file: spelling_presumed_file,
presumed_line: spelling_presumed_line,
col: spelling_col,
tok_len: spelling_tok_len,
included_from: spelling_included_from,
is_macro_arg_expansion: spelling_is_macro_arg_expansion,
} = spelling_loc;
let BareSourceLocation {
offset: expansion_offset,
file: expansion_file,
line: expansion_line,
presumed_file: expansion_presumed_file,
presumed_line: expansion_presumed_line,
col: expansion_col,
tok_len: expansion_tok_len,
included_from: expansion_included_from,
is_macro_arg_expansion: expansion_is_macro_arg_expansion,
} = expansion_loc;
spelling_offset == expansion_offset
&& spelling_file == expansion_file
&& spelling_line == expansion_line
&& spelling_presumed_file == expansion_presumed_file
&& spelling_presumed_line == expansion_presumed_line
&& spelling_col == expansion_col
&& spelling_tok_len == expansion_tok_len
&& same_opt_included_from(
spelling_included_from.as_ref(),
expansion_included_from.as_ref(),
)
&& spelling_is_macro_arg_expansion == expansion_is_macro_arg_expansion
}

fn same_opt_included_from(
spelling_included_from: Option<&IncludedFrom>,
expansion_included_from: Option<&IncludedFrom>,
) -> bool {
spelling_included_from.zip(expansion_included_from).map_or(
false,
|(spelling_included_from, expansion_included_from)| {
let IncludedFrom {
included_from: spelling_included_from,
file: spelling_file,
} = spelling_included_from;
let IncludedFrom {
included_from: expansion_included_from,
file: expansion_file,
} = expansion_included_from;
same_opt_included_from(
spelling_included_from.as_ref().map(Box::as_ref),
expansion_included_from.as_ref().map(Box::as_ref),
) && spelling_file == expansion_file
},
)
}

let serialize_separately = self
.spelling_loc
.as_ref()
.zip(self.expansion_loc.as_ref())
.map_or(true, |(spelling_loc, expansion_loc)| {
!same_bare_source_location(spelling_loc, expansion_loc)
});

if serialize_separately {
let mut map = serializer.serialize_map(None)?;
if let Some(spelling_loc) = &self.spelling_loc {
map.serialize_entry("spellingLoc", spelling_loc)?;
}
if let Some(expansion_loc) = &self.expansion_loc {
map.serialize_entry("expansionLoc", expansion_loc)?;
}
map.end()
} else {
self.spelling_loc.serialize(serializer)
}
}
}

impl Serialize for BareSourceLocation {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("offset", &self.offset)?;
if LAST_LOC_FILENAME.with(|last_loc_filename| {
let mut last_loc_filename = last_loc_filename.borrow_mut();
if *last_loc_filename == self.file {
false
} else {
*last_loc_filename = Arc::clone(&self.file);
true
}
}) {
map.serialize_entry("file", &*self.file)?;
map.serialize_entry("line", &self.line)?;
} else if LAST_LOC_LINE.with(|last_loc_line| {
if last_loc_line.get() == self.line {
false
} else {
last_loc_line.set(self.line);
true
}
}) {
map.serialize_entry("line", &self.line)?;
}
if let Some(presumed_file) = &self.presumed_file {
map.serialize_entry("presumedFile", &**presumed_file)?;
}
if let Some(presumed_line) = &self.presumed_line {
map.serialize_entry("presumedLine", presumed_line)?;
}
map.serialize_entry("col", &self.col)?;
map.serialize_entry("tokLen", &self.tok_len)?;
if let Some(included_from) = &self.included_from {
map.serialize_entry("includedFrom", included_from)?;
}
if self.is_macro_arg_expansion {
map.serialize_entry("isMacroArgExpansion", &true)?;
}
map.end()
}
}

impl Serialize for IncludedFrom {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(None)?;
if let Some(included_from) = &self.included_from {
map.serialize_entry("includedFrom", included_from)?;
}
map.serialize_entry("file", &*self.file)?;
map.end()
}
}

impl Debug for SourceRange {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let SourceRange { begin, end } = self;
Expand Down
Loading

0 comments on commit baff38b

Please sign in to comment.