mirror of
https://github.com/valmojr/armatak.git
synced 2026-06-13 22:53:30 +00:00
idk
This commit is contained in:
1
vendor/arma-rs-proc/.cargo-ok
vendored
Normal file
1
vendor/arma-rs-proc/.cargo-ok
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"v":1}
|
||||
6
vendor/arma-rs-proc/.cargo_vcs_info.json
vendored
Normal file
6
vendor/arma-rs-proc/.cargo_vcs_info.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"git": {
|
||||
"sha1": "adfc323899e58f20c05ebb37595d5ca4fd09367f"
|
||||
},
|
||||
"path_in_vcs": "arma-rs-proc"
|
||||
}
|
||||
42
vendor/arma-rs-proc/Cargo.toml
vendored
Normal file
42
vendor/arma-rs-proc/Cargo.toml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "arma-rs-proc"
|
||||
version = "1.11.1"
|
||||
authors = ["Brett Mayson"]
|
||||
build = false
|
||||
autolib = false
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "proc macros for arma-rs"
|
||||
readme = false
|
||||
keywords = ["arma"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/brettmayson/arma-rs"
|
||||
|
||||
[lib]
|
||||
name = "arma_rs_proc"
|
||||
path = "src/lib.rs"
|
||||
proc-macro = true
|
||||
|
||||
[dependencies.proc-macro2]
|
||||
version = "1.0.92"
|
||||
|
||||
[dependencies.quote]
|
||||
version = "1.0.37"
|
||||
|
||||
[dependencies.syn]
|
||||
version = "2.0.90"
|
||||
features = ["full"]
|
||||
17
vendor/arma-rs-proc/Cargo.toml.orig
generated
vendored
Normal file
17
vendor/arma-rs-proc/Cargo.toml.orig
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "arma-rs-proc"
|
||||
description = "proc macros for arma-rs"
|
||||
version = "1.11.1"
|
||||
edition = "2021"
|
||||
authors = ["Brett Mayson"]
|
||||
repository = "https://github.com/brettmayson/arma-rs"
|
||||
license = "MIT"
|
||||
keywords = ["arma"]
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0.92"
|
||||
quote = "1.0.37"
|
||||
syn = { version = "2.0.90", features = ["full"] }
|
||||
145
vendor/arma-rs-proc/src/derive/attributes.rs
vendored
Normal file
145
vendor/arma-rs-proc/src/derive/attributes.rs
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
use syn::{Error, Result};
|
||||
|
||||
use crate::derive::CombinedErrors;
|
||||
|
||||
pub struct ContainerAttributes {
|
||||
pub transparent: Attribute<bool>,
|
||||
pub default: Attribute<bool>,
|
||||
}
|
||||
|
||||
impl Default for ContainerAttributes {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
transparent: Attribute::new(false),
|
||||
default: Attribute::new(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseAttr for ContainerAttributes {
|
||||
fn parse_attr(&mut self, meta: syn::meta::ParseNestedMeta) -> Result<()> {
|
||||
if meta.path.is_ident("transparent") {
|
||||
return self.transparent.set(&meta, true);
|
||||
}
|
||||
|
||||
if meta.path.is_ident("default") {
|
||||
return self.default.set(&meta, true);
|
||||
}
|
||||
|
||||
Err(meta.error(format!(
|
||||
"unknown arma container attribute `{}`",
|
||||
path_to_string(&meta.path)
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FieldAttributes {
|
||||
pub default: Attribute<bool>,
|
||||
pub from_str: Attribute<bool>,
|
||||
pub to_string: Attribute<bool>,
|
||||
}
|
||||
|
||||
impl Default for FieldAttributes {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
default: Attribute::new(false),
|
||||
from_str: Attribute::new(false),
|
||||
to_string: Attribute::new(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseAttr for FieldAttributes {
|
||||
fn parse_attr(&mut self, meta: syn::meta::ParseNestedMeta) -> Result<()> {
|
||||
if meta.path.is_ident("default") {
|
||||
return self.default.set(&meta, true);
|
||||
}
|
||||
|
||||
if meta.path.is_ident("from_str") {
|
||||
return self.from_str.set(&meta, true);
|
||||
}
|
||||
|
||||
if meta.path.is_ident("to_string") {
|
||||
return self.to_string.set(&meta, true);
|
||||
}
|
||||
|
||||
Err(meta.error(format!(
|
||||
"unknown arma field attribute `{}`",
|
||||
path_to_string(&meta.path)
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ParseAttr {
|
||||
fn parse_attr(&mut self, meta: syn::meta::ParseNestedMeta) -> Result<()>;
|
||||
}
|
||||
|
||||
pub fn parse_attributes<T>(errors: &mut CombinedErrors, attrs: &[syn::Attribute]) -> T
|
||||
where
|
||||
T: ParseAttr + Default + Sized,
|
||||
{
|
||||
attrs.iter().fold(T::default(), |mut attributes, attr| {
|
||||
if !attr.path().is_ident("arma") {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
let result = attr.parse_nested_meta(|meta| {
|
||||
if let Err(err) = attributes.parse_attr(meta) {
|
||||
errors.add(err);
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
if let Err(err) = result {
|
||||
errors.add(err);
|
||||
}
|
||||
attributes
|
||||
})
|
||||
}
|
||||
|
||||
pub struct Attribute<T> {
|
||||
value: T,
|
||||
path: Option<syn::Path>,
|
||||
}
|
||||
|
||||
impl<T> Attribute<T> {
|
||||
fn new(default: T) -> Self {
|
||||
Self {
|
||||
value: default,
|
||||
path: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, meta: &syn::meta::ParseNestedMeta, value: T) -> Result<()> {
|
||||
if self.is_set() {
|
||||
return Err(meta.error(format!(
|
||||
"duplicate arma attribute `{}`",
|
||||
path_to_string(&meta.path)
|
||||
)));
|
||||
}
|
||||
self.value = value;
|
||||
self.path = Some(meta.path.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_set(&self) -> bool {
|
||||
self.path.is_some()
|
||||
}
|
||||
|
||||
pub fn value(&self) -> &T {
|
||||
&self.value
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn error(&self, message: &str) -> Error {
|
||||
Error::new_spanned(self.path.as_ref().unwrap(), message)
|
||||
}
|
||||
}
|
||||
|
||||
fn path_to_string(path: &syn::Path) -> String {
|
||||
path.segments
|
||||
.iter()
|
||||
.map(|s| s.ident.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("::")
|
||||
}
|
||||
124
vendor/arma-rs-proc/src/derive/data.rs
vendored
Normal file
124
vendor/arma-rs-proc/src/derive/data.rs
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::ToTokens;
|
||||
use syn::{Error, Result};
|
||||
|
||||
use crate::derive::{
|
||||
attributes::{parse_attributes, ContainerAttributes, FieldAttributes},
|
||||
r#struct, CombinedErrors,
|
||||
};
|
||||
|
||||
pub struct ContainerData {
|
||||
pub attributes: ContainerAttributes,
|
||||
pub ident: syn::Ident,
|
||||
pub generics: syn::Generics,
|
||||
pub data: Data,
|
||||
}
|
||||
|
||||
pub enum Data {
|
||||
Struct(StructData),
|
||||
}
|
||||
|
||||
pub enum StructData {
|
||||
Map(Vec<FieldNamed>),
|
||||
Tuple(Vec<FieldUnnamed>),
|
||||
NewType(FieldUnnamed),
|
||||
}
|
||||
|
||||
impl ContainerData {
|
||||
pub fn from_input(errors: &mut CombinedErrors, input: syn::DeriveInput) -> Result<Self> {
|
||||
let data = match input.data {
|
||||
syn::Data::Struct(data) => Data::Struct(StructData::new(errors, data)?),
|
||||
syn::Data::Enum(_) => Err(Error::new(Span::call_site(), "enums aren't supported"))?,
|
||||
syn::Data::Union(_) => Err(Error::new(Span::call_site(), "unions aren't supported"))?,
|
||||
};
|
||||
let attributes = parse_attributes::<ContainerAttributes>(errors, &input.attrs);
|
||||
|
||||
Ok(Self {
|
||||
attributes,
|
||||
ident: input.ident,
|
||||
generics: input.generics,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn validate_attributes(&self, errors: &mut CombinedErrors) {
|
||||
match self.data {
|
||||
Data::Struct(ref data) => {
|
||||
r#struct::validate_attributes(errors, &self.attributes, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn impl_into_arma(&self) -> TokenStream {
|
||||
match self.data {
|
||||
Data::Struct(ref data) => r#struct::impl_into_arma(&self.attributes, data),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn impl_from_arma(&self) -> TokenStream {
|
||||
match self.data {
|
||||
Data::Struct(ref data) => r#struct::impl_from_arma(&self.attributes, data),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FieldNamed {
|
||||
pub attributes: FieldAttributes,
|
||||
pub ident: syn::Ident,
|
||||
pub name: String,
|
||||
pub _ty: syn::Type,
|
||||
}
|
||||
|
||||
pub struct FieldUnnamed {
|
||||
pub attributes: FieldAttributes,
|
||||
pub index: syn::Index,
|
||||
pub ty: syn::Type,
|
||||
}
|
||||
|
||||
impl FieldNamed {
|
||||
pub fn new(errors: &mut CombinedErrors, field: syn::Field) -> Self {
|
||||
let ident = field.ident.unwrap();
|
||||
let name = ident.to_string();
|
||||
Self {
|
||||
attributes: parse_attributes::<FieldAttributes>(errors, &field.attrs),
|
||||
ident,
|
||||
name,
|
||||
_ty: field.ty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldUnnamed {
|
||||
pub fn new(errors: &mut CombinedErrors, field: syn::Field, index: usize) -> Self {
|
||||
Self {
|
||||
attributes: parse_attributes::<FieldAttributes>(errors, &field.attrs),
|
||||
index: syn::Index::from(index),
|
||||
ty: field.ty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Field {
|
||||
fn attributes(&self) -> &FieldAttributes;
|
||||
fn token(&self) -> TokenStream;
|
||||
}
|
||||
|
||||
impl Field for FieldNamed {
|
||||
fn attributes(&self) -> &FieldAttributes {
|
||||
&self.attributes
|
||||
}
|
||||
|
||||
fn token(&self) -> TokenStream {
|
||||
self.ident.to_token_stream()
|
||||
}
|
||||
}
|
||||
|
||||
impl Field for FieldUnnamed {
|
||||
fn attributes(&self) -> &FieldAttributes {
|
||||
&self.attributes
|
||||
}
|
||||
|
||||
fn token(&self) -> TokenStream {
|
||||
self.index.to_token_stream()
|
||||
}
|
||||
}
|
||||
72
vendor/arma-rs-proc/src/derive/mod.rs
vendored
Normal file
72
vendor/arma-rs-proc/src/derive/mod.rs
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
mod attributes;
|
||||
mod data;
|
||||
mod r#struct;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{DeriveInput, Result};
|
||||
|
||||
use data::ContainerData;
|
||||
|
||||
pub fn generate_from_arma(input: DeriveInput) -> Result<TokenStream> {
|
||||
let container = parse_container_data(input)?;
|
||||
let body = container.impl_from_arma();
|
||||
|
||||
let ident = container.ident;
|
||||
let (impl_generics, ty_generics, where_clause) = container.generics.split_for_impl();
|
||||
Ok(quote! {
|
||||
#[automatically_derived]
|
||||
impl #impl_generics arma_rs::FromArma for #ident #ty_generics #where_clause {
|
||||
fn from_arma(func_input: String) -> Result<Self, arma_rs::FromArmaError> {
|
||||
#body
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn generate_into_arma(input: DeriveInput) -> Result<TokenStream> {
|
||||
let container = parse_container_data(input)?;
|
||||
let body = container.impl_into_arma();
|
||||
|
||||
let ident = container.ident;
|
||||
let (impl_generics, ty_generics, where_clause) = container.generics.split_for_impl();
|
||||
Ok(quote! {
|
||||
#[automatically_derived]
|
||||
impl #impl_generics arma_rs::IntoArma for #ident #ty_generics #where_clause {
|
||||
fn to_arma(&self) -> arma_rs::Value {
|
||||
#body
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_container_data(input: DeriveInput) -> Result<ContainerData> {
|
||||
let mut errors = CombinedErrors::new();
|
||||
let container = ContainerData::from_input(&mut errors, input)?;
|
||||
container.validate_attributes(&mut errors);
|
||||
errors.into_result().and(Ok(container))
|
||||
}
|
||||
|
||||
pub struct CombinedErrors {
|
||||
root: Option<syn::Error>,
|
||||
}
|
||||
|
||||
impl CombinedErrors {
|
||||
fn new() -> Self {
|
||||
Self { root: None }
|
||||
}
|
||||
|
||||
pub fn add(&mut self, error: syn::Error) {
|
||||
match &mut self.root {
|
||||
Some(root) => root.combine(error),
|
||||
None => self.root = Some(error),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_result(self) -> Result<()> {
|
||||
match self.root {
|
||||
Some(error) => Err(error),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
162
vendor/arma-rs-proc/src/derive/struct/from.rs
vendored
Normal file
162
vendor/arma-rs-proc/src/derive/struct/from.rs
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
use crate::derive::{
|
||||
attributes::ContainerAttributes,
|
||||
data::{Field, FieldNamed, FieldUnnamed, StructData},
|
||||
};
|
||||
|
||||
pub fn impl_from_arma(attributes: &ContainerAttributes, data: &StructData) -> TokenStream {
|
||||
// For simplicity sake we assume that theres no conflicts and everything has already been validated
|
||||
match &data {
|
||||
StructData::Map(fields) => map_struct(attributes, fields),
|
||||
StructData::Tuple(fields) => tuple_struct(attributes, fields),
|
||||
StructData::NewType(field) => newtype_struct(attributes, field),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_struct(attributes: &ContainerAttributes, fields: &[FieldNamed]) -> TokenStream {
|
||||
if *attributes.transparent.value() {
|
||||
return newtype_struct(attributes, fields.first().unwrap());
|
||||
}
|
||||
|
||||
let mut setup = TokenStream::new();
|
||||
setup.extend(quote! {
|
||||
let mut input_as_values = std::collections::HashMap::<String, arma_rs::Value>::default();
|
||||
|
||||
let input_pairs: Vec<(String, arma_rs::Value)> = FromArma::from_arma(func_input)?;
|
||||
for (k, v) in input_pairs {
|
||||
if input_as_values.insert(k.clone(), v).is_some() {
|
||||
return Err(arma_rs::FromArmaError::DuplicateField(k));
|
||||
}
|
||||
}
|
||||
});
|
||||
if *attributes.default.value() {
|
||||
setup.extend(quote! {
|
||||
let container_default: Self = std::default::Default::default();
|
||||
});
|
||||
};
|
||||
|
||||
let field_bodies = fields.iter().map(|field| {
|
||||
let (ident, name) = (&field.ident, &field.name);
|
||||
|
||||
let some_match = if *field.attributes.from_str.value() {
|
||||
quote!(input_value
|
||||
.to_string()
|
||||
.parse()
|
||||
.map_err(arma_rs::FromArmaError::custom)?)
|
||||
} else {
|
||||
quote!(arma_rs::FromArma::from_arma(input_value.to_string())?)
|
||||
};
|
||||
|
||||
let none_match = if *field.attributes.default.value() {
|
||||
quote!(std::default::Default::default())
|
||||
} else if *attributes.default.value() {
|
||||
quote!(container_default.#ident)
|
||||
} else {
|
||||
quote!(return Err(arma_rs::FromArmaError::MissingField(#name.to_string())))
|
||||
};
|
||||
|
||||
quote! {
|
||||
#ident: match input_as_values.remove(#name) {
|
||||
Some(input_value) => #some_match,
|
||||
None => #none_match,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let check_unknown = quote! {
|
||||
if let Some(unknown) = input_as_values.keys().next() {
|
||||
return Err(arma_rs::FromArmaError::UnknownField(unknown.clone()));
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
#setup
|
||||
let result = Self {
|
||||
#(#field_bodies),*
|
||||
};
|
||||
|
||||
#check_unknown
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
fn tuple_struct(attributes: &ContainerAttributes, fields: &[FieldUnnamed]) -> TokenStream {
|
||||
let mut setup = TokenStream::new();
|
||||
setup.extend(quote! {
|
||||
let input_as_values: Vec<arma_rs::Value> = arma_rs::FromArma::from_arma(func_input)?;
|
||||
let mut input_as_values = input_as_values.into_iter();
|
||||
});
|
||||
if *attributes.default.value() {
|
||||
setup.extend(quote! {
|
||||
let container_default: Self = std::default::Default::default();
|
||||
});
|
||||
};
|
||||
|
||||
let expected_len = fields.len();
|
||||
let field_bodies = fields.iter().map(|field| {
|
||||
let index = &field.index;
|
||||
|
||||
let some_match = if *field.attributes.from_str.value() {
|
||||
quote!(input_value
|
||||
.to_string()
|
||||
.parse()
|
||||
.map_err(arma_rs::FromArmaError::custom)?)
|
||||
} else {
|
||||
quote!(arma_rs::FromArma::from_arma(input_value.to_string())?)
|
||||
};
|
||||
|
||||
let none_match = if *field.attributes.default.value() {
|
||||
quote!(std::default::Default::default())
|
||||
} else if *attributes.default.value() {
|
||||
quote!(container_default.#index)
|
||||
} else {
|
||||
quote!(return Err(arma_rs::FromArmaError::InvalidLength {
|
||||
expected: #expected_len,
|
||||
actual: #index,
|
||||
}))
|
||||
};
|
||||
|
||||
quote! {
|
||||
match input_as_values.next() {
|
||||
Some(input_value) => #some_match,
|
||||
None => #none_match,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let check_unknown = quote! {
|
||||
let remaining = input_as_values.len();
|
||||
if remaining > 0 {
|
||||
return Err(arma_rs::FromArmaError::InvalidLength {
|
||||
expected: #expected_len,
|
||||
actual: #expected_len + remaining,
|
||||
});
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
#setup
|
||||
let result = Self (
|
||||
#(#field_bodies),*
|
||||
);
|
||||
|
||||
#check_unknown
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
fn newtype_struct(_attributes: &ContainerAttributes, field: &impl Field) -> TokenStream {
|
||||
let token = field.token();
|
||||
|
||||
let field_body = if *field.attributes().from_str.value() {
|
||||
quote!(func_input.parse().map_err(arma_rs::FromArmaError::custom)?)
|
||||
} else {
|
||||
quote!(arma_rs::FromArma::from_arma(func_input)?)
|
||||
};
|
||||
|
||||
quote! {
|
||||
Ok(Self {
|
||||
#token: #field_body
|
||||
})
|
||||
}
|
||||
}
|
||||
72
vendor/arma-rs-proc/src/derive/struct/into.rs
vendored
Normal file
72
vendor/arma-rs-proc/src/derive/struct/into.rs
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
use crate::derive::{
|
||||
attributes::ContainerAttributes,
|
||||
data::{Field, FieldNamed, FieldUnnamed, StructData},
|
||||
};
|
||||
|
||||
pub fn impl_into_arma(attributes: &ContainerAttributes, data: &StructData) -> TokenStream {
|
||||
// For simplicity sake we assume that theres no conflicts and everything has already been validated
|
||||
match &data {
|
||||
StructData::Map(fields) => map_struct(attributes, fields),
|
||||
StructData::Tuple(fields) => tuple_struct(attributes, fields),
|
||||
StructData::NewType(field) => newtype_struct(attributes, field),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_struct(attributes: &ContainerAttributes, fields: &[FieldNamed]) -> TokenStream {
|
||||
if *attributes.transparent.value() {
|
||||
return newtype_struct(attributes, fields.first().unwrap());
|
||||
}
|
||||
|
||||
let field_bodies = fields.iter().map(|field| {
|
||||
let (ident, name) = (&field.ident, &field.name);
|
||||
|
||||
let (key, value) = if *field.attributes.to_string.value() {
|
||||
(quote!(#name.to_string()), quote!(self.#ident.to_string()))
|
||||
} else {
|
||||
(quote!(#name.to_string()), quote!(self.#ident))
|
||||
};
|
||||
|
||||
quote!((#key, arma_rs::IntoArma::to_arma(&#value)))
|
||||
});
|
||||
|
||||
quote! {
|
||||
std::collections::HashMap::<String, arma_rs::Value>::from([
|
||||
#(#field_bodies),*
|
||||
]).to_arma()
|
||||
}
|
||||
}
|
||||
|
||||
fn tuple_struct(_attributes: &ContainerAttributes, fields: &[FieldUnnamed]) -> TokenStream {
|
||||
let field_bodies = fields.iter().map(|field| {
|
||||
let index = &field.index;
|
||||
|
||||
if *field.attributes.to_string.value() {
|
||||
quote!(self.#index.to_string())
|
||||
} else {
|
||||
quote!(self.#index)
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
Vec::<arma_rs::Value>::from([
|
||||
#(arma_rs::IntoArma::to_arma(&#field_bodies)),*
|
||||
]).to_arma()
|
||||
}
|
||||
}
|
||||
|
||||
fn newtype_struct(_attributes: &ContainerAttributes, field: &impl Field) -> TokenStream {
|
||||
let token = field.token();
|
||||
|
||||
let field_body = if *field.attributes().to_string.value() {
|
||||
quote!(self.#token.to_string())
|
||||
} else {
|
||||
quote!(self.#token)
|
||||
};
|
||||
|
||||
quote! {
|
||||
arma_rs::IntoArma::to_arma(&#field_body)
|
||||
}
|
||||
}
|
||||
62
vendor/arma-rs-proc/src/derive/struct/mod.rs
vendored
Normal file
62
vendor/arma-rs-proc/src/derive/struct/mod.rs
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
mod from;
|
||||
mod into;
|
||||
mod validate;
|
||||
|
||||
use proc_macro2::Span;
|
||||
use syn::{Error, Result};
|
||||
|
||||
pub use from::impl_from_arma;
|
||||
pub use into::impl_into_arma;
|
||||
pub use validate::validate_attributes;
|
||||
|
||||
use crate::derive::{
|
||||
data::{FieldNamed, FieldUnnamed, StructData},
|
||||
CombinedErrors,
|
||||
};
|
||||
|
||||
impl StructData {
|
||||
pub fn new(errors: &mut CombinedErrors, data: syn::DataStruct) -> Result<Self> {
|
||||
match data.fields {
|
||||
syn::Fields::Unit => Err(Error::new(
|
||||
Span::call_site(),
|
||||
"unit-like structs aren't supported",
|
||||
)),
|
||||
syn::Fields::Named(fields) => {
|
||||
if fields.named.is_empty() {
|
||||
return Err(Error::new(
|
||||
Span::call_site(),
|
||||
"unit-like structs aren't supported",
|
||||
));
|
||||
}
|
||||
|
||||
let fields = fields
|
||||
.named
|
||||
.into_iter()
|
||||
.map(|f| FieldNamed::new(errors, f))
|
||||
.collect::<_>();
|
||||
Ok(Self::Map(fields))
|
||||
}
|
||||
syn::Fields::Unnamed(fields) => {
|
||||
if fields.unnamed.is_empty() {
|
||||
return Err(Error::new(
|
||||
Span::call_site(),
|
||||
"unit-like structs aren't supported",
|
||||
));
|
||||
}
|
||||
|
||||
if fields.unnamed.len() == 1 {
|
||||
let field = FieldUnnamed::new(errors, fields.unnamed[0].clone(), 0);
|
||||
Ok(Self::NewType(field))
|
||||
} else {
|
||||
let fields = fields
|
||||
.unnamed
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, f)| FieldUnnamed::new(errors, f, i))
|
||||
.collect::<_>();
|
||||
Ok(Self::Tuple(fields))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
89
vendor/arma-rs-proc/src/derive/struct/validate.rs
vendored
Normal file
89
vendor/arma-rs-proc/src/derive/struct/validate.rs
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
use syn::Error;
|
||||
|
||||
use crate::derive::{
|
||||
attributes::{Attribute, ContainerAttributes, FieldAttributes},
|
||||
data::StructData,
|
||||
CombinedErrors,
|
||||
};
|
||||
|
||||
pub fn validate_attributes(
|
||||
errors: &mut CombinedErrors,
|
||||
attributes: &ContainerAttributes,
|
||||
data: &StructData,
|
||||
) {
|
||||
if *attributes.transparent.value() {
|
||||
match data {
|
||||
StructData::Map(fields) if fields.len() > 1 => {
|
||||
errors.add(
|
||||
attributes
|
||||
.transparent
|
||||
.error("#[arma(transparent)] structs must have exactly one field"),
|
||||
);
|
||||
}
|
||||
StructData::Tuple(_) => {
|
||||
errors.add(
|
||||
attributes
|
||||
.transparent
|
||||
.error("#[arma(transparent)] cannot be used on tuple like structs"),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(attr) = get_default_attr(attributes, data) {
|
||||
match data {
|
||||
StructData::Map(_) if *attributes.transparent.value() => {
|
||||
errors.add(
|
||||
attr.error("#[arma(default)] and #[arma(transparent)] cannot be used together"),
|
||||
);
|
||||
}
|
||||
StructData::NewType(_) => {
|
||||
errors.add(attr.error("#[arma(default)] cannot be used on new type structs"));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if let StructData::Tuple(fields) = data {
|
||||
let mut index_first_default = None;
|
||||
for (index, field) in fields.iter().enumerate() {
|
||||
match index_first_default {
|
||||
None => {
|
||||
if field.attributes.default.is_set() {
|
||||
index_first_default = Some(index);
|
||||
}
|
||||
}
|
||||
Some(index) => {
|
||||
if !field.attributes.default.is_set() {
|
||||
errors.add(Error::new_spanned(&field.ty,
|
||||
format!("field must have #[arma(default)] because previous field {} has #[arma(default)]", index)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_default_attr<'a>(
|
||||
attributes: &'a ContainerAttributes,
|
||||
data: &'a StructData,
|
||||
) -> Option<&'a Attribute<bool>> {
|
||||
if *attributes.default.value() {
|
||||
return Some(&attributes.default);
|
||||
}
|
||||
|
||||
field_attributes(data)
|
||||
.iter()
|
||||
.find(|attr| *attr.default.value())
|
||||
.map(|f| &f.default)
|
||||
}
|
||||
|
||||
fn field_attributes(data: &StructData) -> Vec<&FieldAttributes> {
|
||||
match data {
|
||||
StructData::Map(fields) => fields.iter().map(|f| &f.attributes).collect(),
|
||||
StructData::Tuple(fields) => fields.iter().map(|f| &f.attributes).collect(),
|
||||
StructData::NewType(field) => vec![&field.attributes],
|
||||
}
|
||||
}
|
||||
159
vendor/arma-rs-proc/src/lib.rs
vendored
Normal file
159
vendor/arma-rs-proc/src/lib.rs
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
mod derive;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::{Ident, Span};
|
||||
use quote::quote;
|
||||
use syn::{DeriveInput, Error, ItemFn};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
/// Used to generate the necessary boilerplate for an Arma extension.
|
||||
/// It should be applied to a function that takes no arguments and returns an extension.
|
||||
pub fn arma(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let ast = syn::parse_macro_input!(item as ItemFn);
|
||||
let init = ast.sig.ident.clone();
|
||||
|
||||
let extern_type = if cfg!(windows) { "stdcall" } else { "C" };
|
||||
|
||||
let ext_init = quote! {
|
||||
if RV_EXTENSION.is_none() {
|
||||
RV_EXTENSION = Some(#init());
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(all(target_os = "windows", target_arch = "x86"))]
|
||||
let prefix = "safe32_";
|
||||
|
||||
#[cfg(not(all(target_os = "windows", target_arch = "x86")))]
|
||||
let prefix = "";
|
||||
|
||||
macro_rules! fn_ident {
|
||||
( $name:literal ) => {
|
||||
Ident::new(&format!("{prefix}{}", $name), Span::call_site())
|
||||
};
|
||||
}
|
||||
let versionfn = fn_ident!("RVExtensionVersion");
|
||||
let noargfn = fn_ident!("RVExtension");
|
||||
let argfn = fn_ident!("RVExtensionArgs");
|
||||
let callbackfn = fn_ident!("RVExtensionRegisterCallback");
|
||||
let contextfn = fn_ident!("RVExtensionContext");
|
||||
|
||||
TokenStream::from(quote! {
|
||||
use arma_rs::libc as arma_rs_libc;
|
||||
|
||||
static mut RV_EXTENSION: Option<Extension> = None;
|
||||
|
||||
#[cfg(all(target_os="windows", target_arch="x86"))]
|
||||
arma_rs::link_args::windows! {
|
||||
unsafe {
|
||||
raw("/EXPORT:_RVExtensionVersion@8=_safe32_RVExtensionVersion@8");
|
||||
raw("/EXPORT:_RVExtension@12=_safe32_RVExtension@12");
|
||||
raw("/EXPORT:_RVExtensionArgs@20=_safe32_RVExtensionArgs@20");
|
||||
raw("/EXPORT:_RVExtensionRegisterCallback@4=_safe32_RVExtensionRegisterCallback@4");
|
||||
raw("/EXPORT:_RVExtensionContext@8=_safe32_RVExtensionContext@8");
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns extension version, called by Arma on extension load.
|
||||
/// This function is generated by the [`arma_rs::arma`] proc macro.
|
||||
#[no_mangle]
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern #extern_type fn #versionfn(output: *mut arma_rs_libc::c_char, size: arma_rs_libc::size_t) -> arma_rs_libc::c_int {
|
||||
#ext_init
|
||||
if let Some(ext) = &RV_EXTENSION {
|
||||
arma_rs::write_cstr(ext.version().to_string(), output, size);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// Run extension function, called by Arma on `callExtension` without arguments.
|
||||
/// This function is generated by the [`arma_rs::arma`] proc macro.
|
||||
#[no_mangle]
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern #extern_type fn #noargfn(output: *mut arma_rs_libc::c_char, size: arma_rs_libc::size_t, function: *mut arma_rs_libc::c_char) {
|
||||
#ext_init
|
||||
if let Some(ext) = &RV_EXTENSION {
|
||||
if ext.allow_no_args() {
|
||||
ext.handle_call(function, output, size, None, None, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Run extension function with arguments, called by Arma on `callExtension` with arguments.
|
||||
/// This function is generated by the [`arma_rs::arma`] proc macro.
|
||||
#[no_mangle]
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern #extern_type fn #argfn(output: *mut arma_rs_libc::c_char, size: arma_rs_libc::size_t, function: *mut arma_rs_libc::c_char, args: *mut *mut arma_rs_libc::c_char, arg_count: arma_rs_libc::c_int) -> arma_rs_libc::c_int {
|
||||
#ext_init
|
||||
if let Some(ext) = &RV_EXTENSION {
|
||||
ext.handle_call(function, output, size, Some(args), Some(arg_count), true)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// Set extension callback, called by Arma on extension load.
|
||||
/// This function is generated by the [`arma_rs::arma`] proc macro.
|
||||
#[no_mangle]
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern #extern_type fn #callbackfn(callback: arma_rs::Callback) {
|
||||
#ext_init
|
||||
if let Some(ext) = &mut RV_EXTENSION {
|
||||
ext.register_callback(callback);
|
||||
ext.run_callbacks();
|
||||
}
|
||||
}
|
||||
|
||||
/// Provide extension call context, called by Arma on `callExtension`.
|
||||
/// This function is generated by the [`arma_rs::arma`] proc macro.
|
||||
#[no_mangle]
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern #extern_type fn #contextfn(args: *mut *mut arma_rs_libc::c_char, arg_count: arma_rs_libc::c_int) {
|
||||
#ext_init
|
||||
if let Some(ext) = &mut RV_EXTENSION {
|
||||
ext.handle_call_context(args, arg_count);
|
||||
}
|
||||
}
|
||||
|
||||
#ast
|
||||
})
|
||||
}
|
||||
|
||||
/// Derive implementation of `FromArma`, only supports structs.
|
||||
/// - Map structs are converted from an hashmap.
|
||||
/// - Tuple structs are converted from an array.
|
||||
/// - Newtype structs directly use's the value's `FromArma` implementation.
|
||||
/// - Unit-like structs are not supported.
|
||||
///
|
||||
/// ### Container Attributes
|
||||
/// - `#[arma(transparent)]`: treat single field map structs as if its a newtype structs.
|
||||
/// - `#[arma(default)]`: any missing field will be filled by the structs `Default` implementation.
|
||||
///
|
||||
/// ### Field Attributes
|
||||
/// - `#[arma(from_str)]`: use the types `std::str::FromStr` instead of `FromArma`.
|
||||
/// - `#[arma(default)]`: if missing use its `Default` implementation (takes precedence over container).
|
||||
#[proc_macro_derive(FromArma, attributes(arma))]
|
||||
pub fn derive_from_arma(item: TokenStream) -> TokenStream {
|
||||
let input = syn::parse_macro_input!(item as DeriveInput);
|
||||
derive::generate_from_arma(input)
|
||||
.unwrap_or_else(Error::into_compile_error)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Derive implementation of `IntoArma`, only supports structs.
|
||||
/// - Map structs are converted to an hashmap.
|
||||
/// - Tuple structs are converted to an array.
|
||||
/// - Newtype structs directly use's the value's `IntoArma` implementation.
|
||||
/// - Unit-like structs are not supported.
|
||||
///
|
||||
/// ### Container Attributes
|
||||
/// - `#[arma(transparent)]`: treat single field map structs as if its a newtype structs.
|
||||
///
|
||||
/// ### Field Attributes
|
||||
/// - `#[arma(to_string)]`: use the types `std::string::ToString` instead of `IntoArma`.
|
||||
#[proc_macro_derive(IntoArma, attributes(arma))]
|
||||
pub fn derive_into_arma(item: TokenStream) -> TokenStream {
|
||||
let input = syn::parse_macro_input!(item as DeriveInput);
|
||||
derive::generate_into_arma(input)
|
||||
.unwrap_or_else(Error::into_compile_error)
|
||||
.into()
|
||||
}
|
||||
Reference in New Issue
Block a user