Add ForeignName wrapper around non-Rust names
diff --git a/syntax/attrs.rs b/syntax/attrs.rs
index d3e2bb0..4808f2e 100644
--- a/syntax/attrs.rs
+++ b/syntax/attrs.rs
@@ -1,7 +1,7 @@
use crate::syntax::namespace::Namespace;
use crate::syntax::report::Errors;
use crate::syntax::Atom::{self, *};
-use crate::syntax::{Derive, Doc};
+use crate::syntax::{Derive, Doc, ForeignName};
use proc_macro2::{Ident, TokenStream};
use quote::ToTokens;
use syn::parse::{ParseStream, Parser as _};
@@ -31,7 +31,7 @@
pub derives: Option<&'a mut Vec<Derive>>,
pub repr: Option<&'a mut Option<Atom>>,
pub namespace: Option<&'a mut Namespace>,
- pub cxx_name: Option<&'a mut Option<Ident>>,
+ pub cxx_name: Option<&'a mut Option<ForeignName>>,
pub rust_name: Option<&'a mut Option<Ident>>,
// Suppress clippy needless_update lint ("struct update has no effect, all
@@ -96,7 +96,7 @@
}
}
} else if attr.path.is_ident("cxx_name") {
- match parse_function_alias_attribute.parse2(attr.tokens.clone()) {
+ match parse_cxx_name_attribute.parse2(attr.tokens.clone()) {
Ok(attr) => {
if let Some(cxx_name) = &mut parser.cxx_name {
**cxx_name = Some(attr);
@@ -109,7 +109,7 @@
}
}
} else if attr.path.is_ident("rust_name") {
- match parse_function_alias_attribute.parse2(attr.tokens.clone()) {
+ match parse_rust_name_attribute.parse2(attr.tokens.clone()) {
Ok(attr) => {
if let Some(rust_name) = &mut parser.rust_name {
**rust_name = Some(attr);
@@ -192,7 +192,18 @@
Ok(namespace)
}
-fn parse_function_alias_attribute(input: ParseStream) -> Result<Ident> {
+fn parse_cxx_name_attribute(input: ParseStream) -> Result<ForeignName> {
+ input.parse::<Token![=]>()?;
+ if input.peek(LitStr) {
+ let lit: LitStr = input.parse()?;
+ ForeignName::parse(&lit.value(), lit.span())
+ } else {
+ let ident: Ident = input.parse()?;
+ ForeignName::parse(&ident.to_string(), ident.span())
+ }
+}
+
+fn parse_rust_name_attribute(input: ParseStream) -> Result<Ident> {
input.parse::<Token![=]>()?;
if input.peek(LitStr) {
let lit: LitStr = input.parse()?;
diff --git a/syntax/ident.rs b/syntax/ident.rs
index 78750dc..bb2281e 100644
--- a/syntax/ident.rs
+++ b/syntax/ident.rs
@@ -1,27 +1,24 @@
use crate::syntax::check::Check;
use crate::syntax::{error, Api, Pair};
-use proc_macro2::Ident;
fn check(cx: &mut Check, name: &Pair) {
for segment in &name.namespace {
- check_cxx_ident(cx, segment);
+ check_cxx_ident(cx, &segment.to_string());
}
- check_cxx_ident(cx, &name.cxx);
- check_rust_ident(cx, &name.rust);
+ check_cxx_ident(cx, &name.cxx.to_string());
+ check_rust_ident(cx, &name.rust.to_string());
- fn check_cxx_ident(cx: &mut Check, ident: &Ident) {
- let s = ident.to_string();
- if s.starts_with("cxxbridge") {
+ fn check_cxx_ident(cx: &mut Check, ident: &str) {
+ if ident.starts_with("cxxbridge") {
cx.error(ident, error::CXXBRIDGE_RESERVED.msg);
}
- if s.contains("__") {
+ if ident.contains("__") {
cx.error(ident, error::DOUBLE_UNDERSCORE.msg);
}
}
- fn check_rust_ident(cx: &mut Check, ident: &Ident) {
- let s = ident.to_string();
- if s.starts_with("cxxbridge") {
+ fn check_rust_ident(cx: &mut Check, ident: &str) {
+ if ident.starts_with("cxxbridge") {
cx.error(ident, error::CXXBRIDGE_RESERVED.msg);
}
}
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 9b4a101..57ed4fc 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -41,6 +41,7 @@
pub use self::atom::Atom;
pub use self::derive::{Derive, Trait};
pub use self::doc::Doc;
+pub use self::names::ForeignName;
pub use self::parse::parse_items;
pub use self::types::Types;
@@ -252,7 +253,7 @@
#[derive(Clone)]
pub struct Pair {
pub namespace: Namespace,
- pub cxx: Ident,
+ pub cxx: ForeignName,
pub rust: Ident,
}
diff --git a/syntax/names.rs b/syntax/names.rs
index c4cbcff..b2ae013 100644
--- a/syntax/names.rs
+++ b/syntax/names.rs
@@ -1,25 +1,37 @@
+use crate::syntax::symbol::Segment;
use crate::syntax::{Lifetimes, NamedType, Pair, Symbol};
use proc_macro2::{Ident, Span};
+use std::fmt::{self, Display};
use std::iter;
+use syn::parse::Result;
use syn::punctuated::Punctuated;
+#[derive(Clone)]
+pub struct ForeignName {
+ text: String,
+ span: Span,
+}
+
impl Pair {
pub fn to_symbol(&self) -> Symbol {
- Symbol::from_idents(self.iter_all_segments())
+ let segments = self
+ .namespace
+ .iter()
+ .map(|ident| ident as &dyn Segment)
+ .chain(iter::once(&self.cxx as &dyn Segment));
+ Symbol::from_idents(segments)
}
pub fn to_fully_qualified(&self) -> String {
let mut fully_qualified = String::new();
- for segment in self.iter_all_segments() {
+ for segment in &self.namespace {
fully_qualified += "::";
fully_qualified += &segment.to_string();
}
+ fully_qualified += "::";
+ fully_qualified += &self.cxx.to_string();
fully_qualified
}
-
- fn iter_all_segments(&self) -> impl Iterator<Item = &Ident> {
- self.namespace.iter().chain(iter::once(&self.cxx))
- }
}
impl NamedType {
@@ -36,3 +48,19 @@
self.rust.span()
}
}
+
+impl ForeignName {
+ pub fn parse(text: &str, span: Span) -> Result<Self> {
+ // TODO: support C++ names containing whitespace (`unsigned int`) or
+ // non-alphanumeric characters (`operator++`).
+ let ident: Ident = syn::parse_str(text)?;
+ let text = ident.to_string();
+ Ok(ForeignName { text, span })
+ }
+}
+
+impl Display for ForeignName {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str(&self.text)
+ }
+}
diff --git a/syntax/parse.rs b/syntax/parse.rs
index 3d2c638..795a518 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -4,9 +4,9 @@
use crate::syntax::report::Errors;
use crate::syntax::Atom::*;
use crate::syntax::{
- attrs, error, Api, Array, Derive, Doc, Enum, ExternFn, ExternType, Impl, Include, IncludeKind,
- Lang, Lifetimes, NamedType, Namespace, Pair, Receiver, Ref, Signature, SliceRef, Struct, Ty1,
- Type, TypeAlias, Var, Variant,
+ attrs, error, Api, Array, Derive, Doc, Enum, ExternFn, ExternType, ForeignName, Impl, Include,
+ IncludeKind, Lang, Lifetimes, NamedType, Namespace, Pair, Receiver, Ref, Signature, SliceRef,
+ Struct, Ty1, Type, TypeAlias, Var, Variant,
};
use proc_macro2::{Delimiter, Group, Span, TokenStream, TokenTree};
use quote::{format_ident, quote, quote_spanned};
@@ -1258,11 +1258,16 @@
})
}
-fn pair(namespace: Namespace, default: &Ident, cxx: Option<Ident>, rust: Option<Ident>) -> Pair {
- let default = || default.clone();
+fn pair(
+ namespace: Namespace,
+ default: &Ident,
+ cxx: Option<ForeignName>,
+ rust: Option<Ident>,
+) -> Pair {
Pair {
namespace,
- cxx: cxx.unwrap_or_else(default),
- rust: rust.unwrap_or_else(default),
+ cxx: cxx
+ .unwrap_or_else(|| ForeignName::parse(&default.to_string(), default.span()).unwrap()),
+ rust: rust.unwrap_or_else(|| default.clone()),
}
}
diff --git a/syntax/symbol.rs b/syntax/symbol.rs
index 9a0a4a1..a13a4f3 100644
--- a/syntax/symbol.rs
+++ b/syntax/symbol.rs
@@ -1,5 +1,5 @@
use crate::syntax::namespace::Namespace;
-use crate::syntax::Pair;
+use crate::syntax::{ForeignName, Pair};
use proc_macro2::{Ident, TokenStream};
use quote::ToTokens;
use std::fmt::{self, Display, Write};
@@ -30,7 +30,7 @@
assert!(self.0.len() > len_before);
}
- pub fn from_idents<'a, T: Iterator<Item = &'a Ident>>(it: T) -> Self {
+ pub fn from_idents<'a>(it: impl Iterator<Item = &'a dyn Segment>) -> Self {
let mut symbol = Symbol(String::new());
for segment in it {
segment.write(&mut symbol);
@@ -55,16 +55,19 @@
symbol.push(&self);
}
}
+
impl Segment for usize {
fn write(&self, symbol: &mut Symbol) {
symbol.push(&self);
}
}
+
impl Segment for Ident {
fn write(&self, symbol: &mut Symbol) {
symbol.push(&self);
}
}
+
impl Segment for Symbol {
fn write(&self, symbol: &mut Symbol) {
symbol.push(&self);
@@ -86,6 +89,14 @@
}
}
+impl Segment for ForeignName {
+ fn write(&self, symbol: &mut Symbol) {
+ // TODO: support C++ names containing whitespace (`unsigned int`) or
+ // non-alphanumeric characters (`operator++`).
+ self.to_string().write(symbol);
+ }
+}
+
impl<T> Segment for &'_ T
where
T: ?Sized + Segment + Display,