Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/uniffi/src/cli/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 10 kB image not shown  

Quelle  uniffi_bindgen.rs   Sprache: unbekannt

 
Spracherkennung für: .rs vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use anyhow::{bail, Context, Result};
use camino::Utf8PathBuf;
use clap::{Parser, Subcommand};
use std::fmt;
use uniffi_bindgen::bindings::*;

/// Enumeration of all foreign language targets currently supported by our CLI.
///
#[derive(Copy, Clone, Eq, PartialEq, Hash, clap::ValueEnum)]
enum TargetLanguage {
    Kotlin,
    Swift,
    Python,
    Ruby,
}

impl fmt::Display for TargetLanguage {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Kotlin => write!(f, "kotlin"),
            Self::Swift => write!(f, "swift"),
            Self::Python => write!(f, "python"),
            Self::Ruby => write!(f, "ruby"),
        }
    }
}

impl TryFrom<&str> for TargetLanguage {
    type Error = anyhow::Error;
    fn try_from(value: &str) -> Result<Self> {
        Ok(match value.to_ascii_lowercase().as_str() {
            "kotlin" | "kt" | "kts" => TargetLanguage::Kotlin,
            "swift" => TargetLanguage::Swift,
            "python" | "py" => TargetLanguage::Python,
            "ruby" | "rb" => TargetLanguage::Ruby,
            _ => bail!("Unknown or unsupported target language: \"{value}\""),
        })
    }
}

impl TryFrom<&std::ffi::OsStr> for TargetLanguage {
    type Error = anyhow::Error;
    fn try_from(value: &std::ffi::OsStr) -> Result<Self> {
        match value.to_str() {
            None => bail!("Unreadable target language"),
            Some(s) => s.try_into(),
        }
    }
}

impl TryFrom<String> for TargetLanguage {
    type Error = anyhow::Error;
    fn try_from(value: String) -> Result<Self> {
        TryFrom::try_from(value.as_str())
    }
}

// Structs to help our cmdline parsing. Note that docstrings below form part
// of the "help" output.

/// Scaffolding and bindings generator for Rust
#[derive(Parser)]
#[clap(name = "uniffi-bindgen")]
#[clap(version = clap::crate_version!())]
#[clap(propagate_version = true)]
struct Cli {
    #[clap(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Generate foreign language bindings
    Generate {
        /// Foreign language(s) for which to build bindings.
        #[clap(long, short, value_enum)]
        language: Vec<TargetLanguage>,

        /// Directory in which to write generated files. Default is same folder as .udl file.
        #[clap(long, short)]
        out_dir: Option<Utf8PathBuf>,

        /// Do not try to format the generated bindings.
        #[clap(long, short)]
        no_format: bool,

        /// Path to optional uniffi config file. This config is merged with the `uniffi.toml` config present in each crate, with its values taking precedence.
        #[clap(long, short)]
        config: Option<Utf8PathBuf>,

        /// Extract proc-macro metadata from a native lib (cdylib or staticlib) for this crate.
        #[clap(long)]
        lib_file: Option<Utf8PathBuf>,

        /// Pass in a cdylib path rather than a UDL file
        #[clap(long = "library")]
        library_mode: bool,

        /// When `--library` is passed, only generate bindings for one crate.
        /// When `--library` is not passed, use this as the crate name instead of attempting to
        /// locate and parse Cargo.toml.
        #[clap(long = "crate")]
        crate_name: Option<String>,

        /// Path to the UDL file, or cdylib if `library-mode` is specified
        source: Utf8PathBuf,

        /// Whether we should exclude dependencies when running "cargo metadata".
        /// This will mean external types may not be resolved if they are implemented in crates
        /// outside of this workspace.
        /// This can be used in environments when all types are in the namespace and fetching
        /// all sub-dependencies causes obscure platform specific problems.
        #[clap(long)]
        metadata_no_deps: bool,
    },

    /// Generate Rust scaffolding code
    Scaffolding {
        /// Directory in which to write generated files. Default is same folder as .udl file.
        #[clap(long, short)]
        out_dir: Option<Utf8PathBuf>,

        /// Do not try to format the generated bindings.
        #[clap(long, short)]
        no_format: bool,

        /// Path to the UDL file.
        udl_file: Utf8PathBuf,
    },

    /// Print a debug representation of the interface from a dynamic library
    PrintRepr {
        /// Path to the library file (.so, .dll, .dylib, or .a)
        path: Utf8PathBuf,
    },
}

fn gen_library_mode(
    library_path: &camino::Utf8Path,
    crate_name: Option<String>,
    languages: Vec<TargetLanguage>,
    cfo: Option<&camino::Utf8Path>,
    out_dir: &camino::Utf8Path,
    fmt: bool,
    metadata_no_deps: bool,
) -> anyhow::Result<()> {
    use uniffi_bindgen::library_mode::generate_bindings;

    #[cfg(feature = "cargo-metadata")]
    let config_supplier = {
        use uniffi_bindgen::cargo_metadata::CrateConfigSupplier;
        let mut cmd = cargo_metadata::MetadataCommand::new();
        if metadata_no_deps {
            cmd.no_deps();
        }
        let metadata = cmd.exec().context("error running cargo metadata")?;
        CrateConfigSupplier::from(metadata)
    };
    #[cfg(not(feature = "cargo-metadata"))]
    let config_supplier = uniffi_bindgen::EmptyCrateConfigSupplier;

    for language in languages {
        // to help avoid mistakes we check the library is actually a cdylib, except
        // for swift where static libs are often used to extract the metadata.
        if !matches!(language, TargetLanguage::Swift) && !uniffi_bindgen::is_cdylib(library_path) {
            anyhow::bail!(
                "Generate bindings for {language} requires a cdylib, but {library_path} was given"
            );
        }

        // Type-bounds on trait implementations makes selecting between languages a bit tedious.
        match language {
            TargetLanguage::Kotlin => generate_bindings(
                library_path,
                crate_name.clone(),
                &KotlinBindingGenerator,
                &config_supplier,
                cfo,
                out_dir,
                fmt,
            )?
            .len(),
            TargetLanguage::Python => generate_bindings(
                library_path,
                crate_name.clone(),
                &PythonBindingGenerator,
                &config_supplier,
                cfo,
                out_dir,
                fmt,
            )?
            .len(),
            TargetLanguage::Ruby => generate_bindings(
                library_path,
                crate_name.clone(),
                &RubyBindingGenerator,
                &config_supplier,
                cfo,
                out_dir,
                fmt,
            )?
            .len(),
            TargetLanguage::Swift => generate_bindings(
                library_path,
                crate_name.clone(),
                &SwiftBindingGenerator,
                &config_supplier,
                cfo,
                out_dir,
                fmt,
            )?
            .len(),
        };
    }
    Ok(())
}

fn gen_bindings(
    udl_file: &camino::Utf8Path,
    cfo: Option<&camino::Utf8Path>,
    languages: Vec<TargetLanguage>,
    odo: Option<&camino::Utf8Path>,
    library_file: Option<&camino::Utf8Path>,
    crate_name: Option<&str>,
    fmt: bool,
) -> anyhow::Result<()> {
    use uniffi_bindgen::generate_bindings;
    for language in languages {
        match language {
            TargetLanguage::Kotlin => generate_bindings(
                udl_file,
                cfo,
                KotlinBindingGenerator,
                odo,
                library_file,
                crate_name,
                fmt,
            )?,
            TargetLanguage::Python => generate_bindings(
                udl_file,
                cfo,
                PythonBindingGenerator,
                odo,
                library_file,
                crate_name,
                fmt,
            )?,
            TargetLanguage::Ruby => generate_bindings(
                udl_file,
                cfo,
                RubyBindingGenerator,
                odo,
                library_file,
                crate_name,
                fmt,
            )?,
            TargetLanguage::Swift => generate_bindings(
                udl_file,
                cfo,
                SwiftBindingGenerator,
                odo,
                library_file,
                crate_name,
                fmt,
            )?,
        };
    }
    Ok(())
}

pub fn run_main() -> anyhow::Result<()> {
    let cli = Cli::parse();
    match cli.command {
        Commands::Generate {
            language,
            out_dir,
            no_format,
            config,
            lib_file,
            source,
            crate_name,
            library_mode,
            metadata_no_deps,
        } => {
            if library_mode {
                if lib_file.is_some() {
                    panic!("--lib-file is not compatible with --library.")
                }
                let out_dir = out_dir.expect("--out-dir is required when using --library");
                if language.is_empty() {
                    panic!("please specify at least one language with --language")
                }
                gen_library_mode(
                    &source,
                    crate_name,
                    language,
                    config.as_deref(),
                    &out_dir,
                    !no_format,
                    metadata_no_deps,
                )?;
            } else {
                if metadata_no_deps {
                    panic!("--metadata-no-deps makes no sense when not in library mode")
                }
                gen_bindings(
                    &source,
                    config.as_deref(),
                    language,
                    out_dir.as_deref(),
                    lib_file.as_deref(),
                    crate_name.as_deref(),
                    !no_format,
                )?;
            }
        }
        Commands::Scaffolding {
            out_dir,
            no_format,
            udl_file,
        } => {
            uniffi_bindgen::generate_component_scaffolding(
                &udl_file,
                out_dir.as_deref(),
                !no_format,
            )?;
        }
        Commands::PrintRepr { path } => {
            uniffi_bindgen::print_repr(&path)?;
        }
    };
    Ok(())
}

[ Dauer der Verarbeitung: 0.45 Sekunden  ]