Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  attributes.rs

  Sprache: Rust
 

use std::collections::{HashMap, HashSet};

use crate::{
    default::DefaultValue,
    util::{either_attribute_arg, kw, parse_comma_separated, UniffiAttributeArgs},
};

use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::{
    parenthesized,
    parse::{Parse, ParseStream},
    punctuated::Punctuated,
    Attribute, Ident, LitStr, Meta, Path, PathArguments, PathSegment, Token,
};
use uniffi_meta::UniffiTraitDiscriminants;

#[derive(Default)]
pub struct ExportTraitArgs {
    pub(crate) async_runtime: Option<AsyncRuntime>,
    pub(crate) callback_interface: Option<kw::callback_interface>,
    pub(crate) with_foreign: Option<kw::with_foreign>,
}

impl Parse for ExportTraitArgs {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        parse_comma_separated(input)
    }
}

impl UniffiAttributeArgs for ExportTraitArgs {
    fn parse_one(input: ParseStream<'_>) -> syn::Result<Self> {
        let lookahead = input.lookahead1();
        if lookahead.peek(kw::async_runtime) {
            let _: kw::async_runtime = input.parse()?;
            let _: Token![=] = input.parse()?;
            Ok(Self {
                async_runtime: Some(input.parse()?),
                ..Self::default()
            })
        } else if lookahead.peek(kw::callback_interface) {
            Ok(Self {
                callback_interface: input.parse()?,
                ..Self::default()
            })
        } else if lookahead.peek(kw::with_foreign) {
            Ok(Self {
                with_foreign: input.parse()?,
                ..Self::default()
            })
        } else {
            Ok(Self::default())
        }
    }

    fn merge(self, other: Self) -> syn::Result<Self> {
        let merged = Self {
            async_runtime: either_attribute_arg(self.async_runtime, other.async_runtime)?,
            callback_interface: either_attribute_arg(
                self.callback_interface,
                other.callback_interface,
            )?,
            with_foreign: either_attribute_arg(self.with_foreign, other.with_foreign)?,
        };
        if merged.callback_interface.is_some() && merged.with_foreign.is_some() {
            return Err(syn::Error::new(
                merged.callback_interface.unwrap().span,
                "`callback_interface` and `with_foreign` are mutually exclusive",
            ));
        }
        Ok(merged)
    }
}

/// Attribute arguments for function
///
/// This includes top-level functions, constructors, and methods.
#[derive(Clone, Default)]
pub struct ExportFnArgs {
    pub(crate) async_runtime: Option<AsyncRuntime>,
    pub(crate) name: Option<String>,
    pub(crate) defaults: DefaultMap,
}

impl Parse for ExportFnArgs {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        parse_comma_separated(input)
    }
}

impl UniffiAttributeArgs for ExportFnArgs {
    fn parse_one(input: ParseStream<'_>) -> syn::Result<Self> {
        let lookahead = input.lookahead1();
        if lookahead.peek(kw::async_runtime) {
            let _: kw::async_runtime = input.parse()?;
            let _: Token![=] = input.parse()?;
            Ok(Self {
                async_runtime: Some(input.parse()?),
                ..Self::default()
            })
        } else if lookahead.peek(kw::name) {
            let _: kw::name = input.parse()?;
            let _: Token![=] = input.parse()?;
            let name = Some(input.parse::<LitStr>()?.value());
            Ok(Self {
                name,
                ..Self::default()
            })
        } else if lookahead.peek(kw::default) {
            Ok(Self {
                defaults: DefaultMap::parse(input)?,
                ..Self::default()
            })
        } else {
            Err(syn::Error::new(
                input.span(),
                format!("attribute `{input}` is not supported here."),
            ))
        }
    }

    fn merge(self, other: Self) -> syn::Result<Self> {
        Ok(Self {
            async_runtime: either_attribute_arg(self.async_runtime, other.async_runtime)?,
            name: either_attribute_arg(self.name, other.name)?,
            defaults: self.defaults.merge(other.defaults),
        })
    }
}

#[derive(Default)]
pub struct ExportImplArgs {
    pub(crate) async_runtime: Option<AsyncRuntime>,
}

impl Parse for ExportImplArgs {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        parse_comma_separated(input)
    }
}

impl UniffiAttributeArgs for ExportImplArgs {
    fn parse_one(input: ParseStream<'_>) -> syn::Result<Self> {
        let lookahead = input.lookahead1();
        if lookahead.peek(kw::async_runtime) {
            let _: kw::async_runtime = input.parse()?;
            let _: Token![=] = input.parse()?;
            Ok(Self {
                async_runtime: Some(input.parse()?),
            })
        } else {
            Err(syn::Error::new(
                input.span(),
                format!("uniffi::export attribute `{input}` is not supported here."),
            ))
        }
    }

    fn merge(self, other: Self) -> syn::Result<Self> {
        Ok(Self {
            async_runtime: either_attribute_arg(self.async_runtime, other.async_runtime)?,
        })
    }
}

#[derive(Default)]
pub struct ExportStructArgs {
    pub(crate) traits: HashSet<UniffiTraitDiscriminants>,
}

impl Parse for ExportStructArgs {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        parse_comma_separated(input)
    }
}

impl UniffiAttributeArgs for ExportStructArgs {
    fn parse_one(input: ParseStream<'_>) -> syn::Result<Self> {
        let lookahead = input.lookahead1();
        if lookahead.peek(kw::Debug) {
            input.parse::<Option<kw::Debug>>()?;
            Ok(Self {
                traits: HashSet::from([UniffiTraitDiscriminants::Debug]),
            })
        } else if lookahead.peek(kw::Display) {
            input.parse::<Option<kw::Display>>()?;
            Ok(Self {
                traits: HashSet::from([UniffiTraitDiscriminants::Display]),
            })
        } else if lookahead.peek(kw::Hash) {
            input.parse::<Option<kw::Hash>>()?;
            Ok(Self {
                traits: HashSet::from([UniffiTraitDiscriminants::Hash]),
            })
        } else if lookahead.peek(kw::Eq) {
            input.parse::<Option<kw::Eq>>()?;
            Ok(Self {
                traits: HashSet::from([UniffiTraitDiscriminants::Eq]),
            })
        } else {
            Err(syn::Error::new(
                input.span(),
                format!(
                    "uniffi::export struct attributes must be builtin trait names; `{input}` is invalid"
                ),
            ))
        }
    }

    fn merge(self, other: Self) -> syn::Result<Self> {
        let mut traits = self.traits;
        traits.extend(other.traits);
        Ok(Self { traits })
    }
}

#[derive(Clone)]
pub enum AsyncRuntime {
    Tokio(LitStr),
}

impl Parse for AsyncRuntime {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let lit: LitStr = input.parse()?;
        match lit.value().as_str() {
            "tokio" => Ok(Self::Tokio(lit)),
            _ => Err(syn::Error::new_spanned(
                lit,
                "unknown async runtime, currently only `tokio` is supported",
            )),
        }
    }
}

impl ToTokens for AsyncRuntime {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            AsyncRuntime::Tokio(lit) => lit.to_tokens(tokens),
        }
    }
}

#[derive(Default)]
pub(superstruct ExportedImplFnAttributes {
    pub constructor: bool,
    pub args: ExportFnArgs,
}

impl ExportedImplFnAttributes {
    pub fn new(attrs: &[Attribute]) -> syn::Result<Self> {
        let mut this = Self::default();
        for attr in attrs {
            let path = attr.path();

            if is_uniffi_path(path) {
                this.process_path(path, attr, &attr.meta)?;
            } else if is_cfg_attr(attr) {
                if let Ok(nested) =
                    attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
                {
                    for meta in &nested {
                        if let Meta::Path(path) = meta {
                            this.process_path(path, attr, meta)?
                        }
                    }
                };
            }
        }

        Ok(this)
    }

    fn process_path(&mut self, path: &Path, attr: &Attribute, meta: &Meta) -> syn::Result<()> {
        let segs = &path.segments;

        let fst = segs
            .first()
            .expect("attributes have at least one path segment");

        if fst.ident != "uniffi" {
            return Ok(());
        }
        ensure_no_path_args(fst)?;

        let args = match meta {
            Meta::List(_) => attr.parse_args::<ExportFnArgs>()?,
            _ => Default::default(),
        };
        self.args = args;

        if segs.len() != 2 {
            return Err(syn::Error::new_spanned(
                segs,
                "unsupported uniffi attribute",
            ));
        }
        let snd = &segs[1];
        ensure_no_path_args(snd)?;

        match snd.ident.to_string().as_str() {
            "constructor" => {
                if self.constructor {
                    return Err(syn::Error::new_spanned(
                        attr,
                        "duplicate constructor attribute",
                    ));
                }
                self.constructor = true;
            }
            "method" => {
                if self.constructor {
                    return Err(syn::Error::new_spanned(
                        attr,
                        "confused constructor/method attributes",
                    ));
                }
            }
            _ => return Err(syn::Error::new_spanned(snd, "unknown uniffi attribute")),
        }

        Ok(())
    }
}

fn is_uniffi_path(path: &Path) -> bool {
    path.segments
        .first()
        .map(|segment| segment.ident == "uniffi")
        .unwrap_or(false)
}

fn is_cfg_attr(attr: &Attribute) -> bool {
    attr.meta
        .path()
        .get_ident()
        .is_some_and(|ident| *ident == "cfg_attr")
}

fn ensure_no_path_args(seg: &PathSegment) -> syn::Result<()> {
    if matches!(seg.arguments, PathArguments::None) {
        Ok(())
    } else {
        Err(syn::Error::new_spanned(&seg.arguments, "unexpected syntax"))
    }
}

/// Maps arguments to defaults for functions
#[derive(Clone, Default)]
pub struct DefaultMap {
    map: HashMap<Ident, DefaultValue>,
}

impl DefaultMap {
    pub fn merge(self, other: Self) -> Self {
        let mut map = self.map;
        map.extend(other.map);
        Self { map }
    }

    pub fn remove(&mut self, ident: &Ident) -> Option<DefaultValue> {
        self.map.remove(ident)
    }

    pub fn idents(&self) -> Vec<&Ident> {
        self.map.keys().collect()
    }
}

impl Parse for DefaultMap {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let _: kw::default = input.parse()?;
        let content;
        let _ = parenthesized!(content in input);
        let pairs = content.parse_terminated(DefaultPair::parse, Token![,])?;
        Ok(Self {
            map: pairs.into_iter().map(|p| (p.name, p.value)).collect(),
        })
    }
}

pub struct DefaultPair {
    pub name: Ident,
    pub eq_token: Token![=],
    pub value: DefaultValue,
}

impl Parse for DefaultPair {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        Ok(Self {
            name: input.parse()?,
            eq_token: input.parse()?,
            value: input.parse()?,
        })
    }
}

Messung V0.5 in Prozent
C=96 H=100 G=97

¤ Dauer der Verarbeitung: 0.10 Sekunden  (vorverarbeitet am  2026-06-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik