Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions annotation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::ToTokens;
use syn::{parse, Attribute, Data, DeriveInput, Fields};
use syn::{parse, punctuated::Punctuated, Attribute, Data, DeriveInput, Fields, Meta, Token};

/// Marks a type as a type shared across the FFI boundary using typeshare.
///
Expand Down Expand Up @@ -50,11 +50,27 @@ pub fn typeshare(_attr: TokenStream, item: TokenStream) -> TokenStream {
}
}

const CONFIG_ATTRIBUTE_NAME: &str = "typeshare";

fn is_typeshare_attribute(attribute: &Attribute) -> bool {
let has_cfg_attr = || {
if attribute.path().is_ident("cfg_attr") {
if let Ok(meta) =
attribute.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
{
return meta.into_iter().any(
|meta| matches!(meta, Meta::List(meta_list) if meta_list.path.is_ident(CONFIG_ATTRIBUTE_NAME)),
);
}
}
false
};
attribute.path().is_ident(CONFIG_ATTRIBUTE_NAME) || has_cfg_attr()
}

fn strip_configuration_attribute(item: &mut DeriveInput) {
fn remove_configuration_from_attributes(attributes: &mut Vec<Attribute>) {
const CONFIG_ATTRIBUTE_NAME: &str = "typeshare";

attributes.retain(|x| x.path().to_token_stream().to_string() != CONFIG_ATTRIBUTE_NAME);
attributes.retain(|attribute| !is_typeshare_attribute(attribute));
}

fn remove_configuration_from_fields(fields: &mut Fields) {
Expand Down
40 changes: 40 additions & 0 deletions core/data/tests/cfg_if_attribute_typeshare/input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/// Example of a type that is conditionally typeshared
/// based on a feature "typeshare-support". This does not
/// conditionally typeshare but allows a conditionally
/// typeshared type to generate typeshare types when behind
/// a `cfg_attr` condition.
#[cfg_attr(feature = "typeshare-support", typeshare)]
pub struct TestStruct1 {
field: String,
}

#[cfg_attr(feature = "typeshare-support", typeshare(transparent))]
#[derive(Debug, Default, PartialEq, Eq, Clone, Hash)]
#[repr(transparent)]
pub struct Bytes(Vec<u8>);

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(
feature = "typeshare-support",
typeshare(
swift = "Equatable, Hashable",
swiftGenericConstraints = "R: Equatable & Hashable"
)
)]
pub struct TestStruct2<R> {
field_1: String,
field_2: R,
}

#[cfg_attr(
feature = "typeshare-support",
typeshare(kotlin = "JvmInline", redacted)
)]
pub struct TestStruct3(String);

#[cfg_attr(feature = "typeshare-support", typeshare)]
pub struct TestStruct4 {
#[cfg_attr(feature = "typeshare-support", typeshare(serialized_as = "I54"))]
pub field: i64,
}
38 changes: 38 additions & 0 deletions core/data/tests/cfg_if_attribute_typeshare/output.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.agilebits.onepassword

import kotlinx.serialization.Serializable
import kotlinx.serialization.SerialName

typealias Bytes = List<UByte>

@Serializable
@JvmInline
value class TestStruct3(
private val value: String
) {
fun unwrap() = value

override fun toString(): String = "***"
}

/// Example of a type that is conditionally typeshared
/// based on a feature "typeshare-support". This does not
/// conditionally typeshare but allows a conditionally
/// typeshared type to generate typeshare types when behind
/// a `cfg_attr` condition.
@Serializable
data class TestStruct1 (
val field: String
)

@Serializable
data class TestStruct2<R> (
val field1: String,
val field2: R
)

@Serializable
data class TestStruct4 (
val field: Long
)

36 changes: 36 additions & 0 deletions core/data/tests/cfg_if_attribute_typeshare/output.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Foundation

public typealias Bytes = [UInt8]

public typealias TestStruct3 = String

/// Example of a type that is conditionally typeshared
/// based on a feature "typeshare-support". This does not
/// conditionally typeshare but allows a conditionally
/// typeshared type to generate typeshare types when behind
/// a `cfg_attr` condition.
public struct TestStruct1: Codable {
public let field: String

public init(field: String) {
self.field = field
}
}

public struct TestStruct2<R: Codable & Equatable & Hashable>: Codable, Equatable, Hashable {
public let field1: String
public let field2: R

public init(field1: String, field2: R) {
self.field1 = field1
self.field2 = field2
}
}

public struct TestStruct4: Codable {
public let field: Int64

public init(field: Int64) {
self.field = field
}
}
24 changes: 24 additions & 0 deletions core/data/tests/cfg_if_attribute_typeshare/output.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export type Bytes = number[];

export type TestStruct3 = string;

/**
* Example of a type that is conditionally typeshared
* based on a feature "typeshare-support". This does not
* conditionally typeshare but allows a conditionally
* typeshared type to generate typeshare types when behind
* a `cfg_attr` condition.
*/
export interface TestStruct1 {
field: string;
}

export interface TestStruct2<R> {
field1: string;
field2: R;
}

export interface TestStruct4 {
field: number;
}

Loading
Loading