Skip to content

Commit 54a8557

Browse files
allow for recursive defintions
1 parent 615527e commit 54a8557

File tree

10 files changed

+326
-158
lines changed

10 files changed

+326
-158
lines changed

core/data/tests/excluded_by_target_os/input.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,7 @@ pub struct OtherExcluded;
7676
#[typeshare]
7777
#[cfg(not(target_os = "android"))]
7878
pub struct AndroidExcluded;
79+
80+
#[typeshare]
81+
#[cfg(all(feature = "my-feature", not(target_os = "ios")))]
82+
pub struct NestedNotTarget1;

core/data/tests/excluded_by_target_os/output.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ type ManyStruct struct {
1111
}
1212
type MultipleTargets struct {
1313
}
14+
type NestedNotTarget1 struct {
15+
}
1416
type OtherExcluded struct {
1517
}
1618
type SomeEnum string

core/data/tests/excluded_by_target_os/output.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ object ManyStruct
1717
@Serializable
1818
object MultipleTargets
1919

20+
@Serializable
21+
object NestedNotTarget1
22+
2023
@Serializable
2124
object OtherExcluded
2225

core/data/tests/excluded_by_target_os/output.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ class ManyStruct extends Serializable
1212

1313
class MultipleTargets extends Serializable
1414

15+
class NestedNotTarget1 extends Serializable
16+
1517
class OtherExcluded extends Serializable
1618

1719
sealed trait SomeEnum {

core/data/tests/excluded_by_target_os/output.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ public struct MultipleTargets: Codable {
2020
public init() {}
2121
}
2222

23+
public struct NestedNotTarget1: Codable {
24+
public init() {}
25+
}
26+
2327
public struct OtherExcluded: Codable {
2428
public init() {}
2529
}

core/data/tests/excluded_by_target_os/output.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ export interface ManyStruct {
1111
export interface MultipleTargets {
1212
}
1313

14+
export interface NestedNotTarget1 {
15+
}
16+
1417
export interface OtherExcluded {
1518
}
1619

core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub mod language;
1111
pub mod parser;
1212
/// Codifying Rust types and how they convert to various languages.
1313
pub mod rust_types;
14+
mod target_os_check;
1415
mod topsort;
1516
mod visitors;
1617

core/src/parser.rs

Lines changed: 5 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,20 @@ use crate::{
66
RustEnumVariantShared, RustField, RustItem, RustStruct, RustType, RustTypeAlias,
77
RustTypeParseError,
88
},
9+
target_os_check::accept_target_os,
910
visitors::{ImportedType, TypeShareVisitor},
1011
};
1112
use itertools::Either;
12-
use log::{debug, error, log_enabled};
13+
use log::debug;
1314
use proc_macro2::Ident;
14-
use quote::ToTokens;
1515
use std::{
1616
collections::{BTreeSet, HashMap, HashSet},
1717
convert::TryFrom,
1818
path::PathBuf,
1919
};
2020
use syn::{
2121
ext::IdentExt, parse::ParseBuffer, punctuated::Punctuated, visit::Visit, Attribute, Expr,
22-
ExprLit, Fields, GenericParam, ItemEnum, ItemStruct, ItemType, Lit, LitStr, Meta, MetaList,
22+
ExprLit, Fields, GenericParam, ItemEnum, ItemStruct, ItemType, LitStr, Meta, MetaList,
2323
MetaNameValue, Token,
2424
};
2525
use thiserror::Error;
@@ -540,7 +540,7 @@ pub(crate) fn get_name_value_meta_items<'a>(
540540

541541
/// Returns all arguments passed into `#[{ident}(...)]` where `{ident}` can be `serde` or `typeshare` attributes
542542
#[inline(always)]
543-
fn get_meta_items(attr: &syn::Attribute, ident: &str) -> impl Iterator<Item = Meta> {
543+
pub(crate) fn get_meta_items(attr: &syn::Attribute, ident: &str) -> impl Iterator<Item = Meta> {
544544
if attr.path().is_ident(ident) {
545545
Either::Left(
546546
attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
@@ -611,21 +611,7 @@ fn is_skipped(attrs: &[syn::Attribute], target_os: &[String]) -> bool {
611611
.any(|arg| matches!(arg, Meta::Path(path) if path.is_ident("skip")))
612612
});
613613

614-
let target_rejected = || {
615-
!target_os.is_empty()
616-
&& target_os
617-
.iter()
618-
.any(|target| attrs.iter().any(|attr| target_os_reject(attr, target)))
619-
};
620-
621-
let target_accepted = || {
622-
target_os.is_empty()
623-
|| target_os
624-
.iter()
625-
.any(|target| attrs.iter().all(|attr| target_os_accept(attr, target)))
626-
};
627-
628-
typeshare_skip || target_rejected() || !target_accepted()
614+
typeshare_skip || !accept_target_os(attrs, target_os)
629615
}
630616

631617
// `#[typeshare(redacted)]`
@@ -636,127 +622,6 @@ fn is_redacted(attrs: &[syn::Attribute]) -> bool {
636622
})
637623
}
638624

639-
/// Check if this attribute rejects our optional `target_os` arguments.
640-
///
641-
/// Examples:
642-
/// - `#[cfg(not(target_os = "windows"))]`
643-
/// - `#[cfg(not(any(target_os = "windows", target_os = "macos", feature = "my-feature")))]`
644-
/// - `#[cfg(not(all(target_os = "windows", feature = "my-feature")))]`
645-
#[inline]
646-
pub(crate) fn target_os_reject(attr: &Attribute, target_os: &str) -> bool {
647-
if log_enabled!(log::Level::Debug) {
648-
debug!(
649-
"\tchecking attribute {} for {target_os} reject",
650-
attr.into_token_stream()
651-
);
652-
}
653-
654-
let reject = get_meta_items(attr, "cfg").any(|meta| match &meta {
655-
// Check for "not"
656-
Meta::List(meta_list) if meta_list.path.is_ident("not") => {
657-
debug!("\t\tparsing not");
658-
target_os_parse_not(meta_list, target_os)
659-
}
660-
// If this attribute is not a target_os we accept
661-
_ => false,
662-
});
663-
debug!("\t\treject {reject}");
664-
reject
665-
}
666-
667-
/// Check if this attribute can accept our optional `target_os` arguments.
668-
///
669-
/// Examples:
670-
/// - `#[cfg(target_os = "windows")]`
671-
/// - `#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]`
672-
/// - `#[cfg(all(target_os = "windows", feature = "my-feature"))]`
673-
#[inline]
674-
pub(crate) fn target_os_accept(attr: &Attribute, target_os: &str) -> bool {
675-
if log_enabled!(log::Level::Debug) {
676-
debug!(
677-
"\tchecking attribute {} for {target_os} accept",
678-
attr.into_token_stream()
679-
);
680-
}
681-
682-
let accept = get_meta_items(attr, "cfg").all(|meta| match &meta {
683-
// a single #[cfg(target_os = "target")]
684-
Meta::NameValue(MetaNameValue {
685-
path,
686-
value: Expr::Lit(ExprLit {
687-
lit: Lit::Str(v), ..
688-
}),
689-
..
690-
}) if path.is_ident("target_os") => v.value() == target_os,
691-
// Combined with any or all
692-
// Ex: #[cfg(any(target_os = "target", feature = "test"))]
693-
Meta::List(meta_list)
694-
if meta_list.path.is_ident("any") || meta_list.path.is_ident("all") =>
695-
{
696-
argument_values("target_os", meta_list).any(|t| t == target_os)
697-
}
698-
// If this attribute is not a target_os we accept
699-
_ => true,
700-
});
701-
debug!("\t\taccept {accept}");
702-
accept
703-
}
704-
705-
/// Here we have a `#[cfg(not(..))]` attribute. There can be an `any` or `all` as well. We'll
706-
/// take any `target_os` and see if it matches the target_os parameter.
707-
#[inline]
708-
fn target_os_parse_not(list: &MetaList, target_os: &str) -> bool {
709-
// Try to parse "any" or "all".
710-
let nested_meta_list =
711-
list.parse_args_with(Punctuated::<MetaList, Token![,]>::parse_terminated);
712-
713-
match nested_meta_list {
714-
Ok(punctuated_meta) => punctuated_meta.iter().any(|meta| {
715-
if log_enabled!(log::Level::Debug) {
716-
if let Some(ident) = meta.path.get_ident() {
717-
debug!("condition: {ident}");
718-
}
719-
}
720-
721-
// The "all" here is treated as any. The assumption is there
722-
// will be one "target_os" combined with "feature" or some other
723-
// attribute that is not another "target_os".
724-
(meta.path.is_ident("any") || meta.path.is_ident("all"))
725-
&& argument_values("target_os", meta).any(|target| target == target_os)
726-
}),
727-
Err(_err) => {
728-
debug!("Parsing MetaNameValue");
729-
// "not" is not combined with "any" or "all".
730-
argument_values("target_os", list).any(|target| target == target_os)
731-
}
732-
}
733-
}
734-
735-
/// Yields all values for a given `arg_name`.
736-
#[inline]
737-
fn argument_values<'a>(arg_name: &'a str, list: &'a MetaList) -> impl Iterator<Item = String> + 'a {
738-
let name_values =
739-
list.parse_args_with(Punctuated::<MetaNameValue, Token![,]>::parse_terminated);
740-
741-
match name_values {
742-
Ok(nvps) => Either::Left(nvps.into_iter().filter_map(|nvp| {
743-
nvp.path
744-
.is_ident(arg_name)
745-
.then_some(&nvp.value)
746-
.and_then(|value| match value {
747-
Expr::Lit(ExprLit {
748-
lit: Lit::Str(val), ..
749-
}) => Some(val.value()),
750-
_ => None,
751-
})
752-
})),
753-
Err(err) => {
754-
error!("Failed to parse meta list for {arg_name}: {err}");
755-
Either::Right(std::iter::empty())
756-
}
757-
}
758-
}
759-
760625
fn serde_attr(attrs: &[syn::Attribute], ident: &str) -> bool {
761626
attrs.iter().any(|attr| {
762627
get_meta_items(attr, SERDE)

0 commit comments

Comments
 (0)