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

Quelle  group.rs   Sprache: unbekannt

 
/* 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 std::collections::{BTreeSet, HashMap};

use crate::*;
use anyhow::{bail, Result};

type MetadataGroupMap = HashMap<String, MetadataGroup>;

// Create empty metadata groups based on the metadata items.
pub fn create_metadata_groups(items: &[Metadata]) -> MetadataGroupMap {
    // Map crate names to MetadataGroup instances
    items
        .iter()
        .filter_map(|i| match i {
            Metadata::Namespace(namespace) => {
                let group = MetadataGroup {
                    namespace: namespace.clone(),
                    namespace_docstring: None,
                    items: BTreeSet::new(),
                };
                Some((namespace.crate_name.clone(), group))
            }
            Metadata::UdlFile(udl) => {
                let namespace = NamespaceMetadata {
                    crate_name: udl.module_path.clone(),
                    name: udl.namespace.clone(),
                };
                let group = MetadataGroup {
                    namespace,
                    namespace_docstring: None,
                    items: BTreeSet::new(),
                };
                Some((udl.module_path.clone(), group))
            }
            _ => None,
        })
        .collect::<HashMap<_, _>>()
}

/// Consume the items into the previously created metadata groups.
pub fn group_metadata(group_map: &mut MetadataGroupMap, items: Vec<Metadata>) -> Result<()> {
    for item in items {
        if matches!(&item, Metadata::Namespace(_)) {
            continue;
        }

        let crate_name = calc_crate_name(item.module_path()).to_owned(); // XXX - kill clone?

        let item = fixup_external_type(item, group_map);
        let group = match group_map.get_mut(&crate_name) {
            Some(ns) => ns,
            None => bail!("Unknown namespace for {item:?} ({crate_name})"),
        };
        if group.items.contains(&item) {
            bail!("Duplicate metadata item: {item:?}");
        }
        group.add_item(item);
    }
    Ok(())
}

#[derive(Debug)]
pub struct MetadataGroup {
    pub namespace: NamespaceMetadata,
    pub namespace_docstring: Option<String>,
    pub items: BTreeSet<Metadata>,
}

impl MetadataGroup {
    pub fn add_item(&mut self, item: Metadata) {
        self.items.insert(item);
    }
}

pub fn fixup_external_type(item: Metadata, group_map: &MetadataGroupMap) -> Metadata {
    let crate_name = calc_crate_name(item.module_path()).to_owned();
    let converter = ExternalTypeConverter {
        crate_name: &crate_name,
        crate_to_namespace: group_map,
    };
    converter.convert_item(item)
}

/// Convert metadata items by replacing types from external crates with Type::External
struct ExternalTypeConverter<'a> {
    crate_name: &'a str,
    crate_to_namespace: &'a MetadataGroupMap,
}

impl<'a> ExternalTypeConverter<'a> {
    fn crate_to_namespace(&self, crate_name: &str) -> String {
        self.crate_to_namespace
            .get(crate_name)
            .unwrap_or_else(|| panic!("Can't find namespace for module {crate_name}"))
            .namespace
            .name
            .clone()
    }

    fn convert_item(&self, item: Metadata) -> Metadata {
        match item {
            Metadata::Func(meta) => Metadata::Func(FnMetadata {
                inputs: self.convert_params(meta.inputs),
                return_type: self.convert_optional(meta.return_type),
                throws: self.convert_optional(meta.throws),
                ..meta
            }),
            Metadata::Method(meta) => Metadata::Method(MethodMetadata {
                inputs: self.convert_params(meta.inputs),
                return_type: self.convert_optional(meta.return_type),
                throws: self.convert_optional(meta.throws),
                ..meta
            }),
            Metadata::TraitMethod(meta) => Metadata::TraitMethod(TraitMethodMetadata {
                inputs: self.convert_params(meta.inputs),
                return_type: self.convert_optional(meta.return_type),
                throws: self.convert_optional(meta.throws),
                ..meta
            }),
            Metadata::Constructor(meta) => Metadata::Constructor(ConstructorMetadata {
                inputs: self.convert_params(meta.inputs),
                throws: self.convert_optional(meta.throws),
                ..meta
            }),
            Metadata::Record(meta) => Metadata::Record(RecordMetadata {
                fields: self.convert_fields(meta.fields),
                ..meta
            }),
            Metadata::Enum(meta) => Metadata::Enum(self.convert_enum(meta)),
            _ => item,
        }
    }

    fn convert_params(&self, params: Vec<FnParamMetadata>) -> Vec<FnParamMetadata> {
        params
            .into_iter()
            .map(|param| FnParamMetadata {
                ty: self.convert_type(param.ty),
                ..param
            })
            .collect()
    }

    fn convert_fields(&self, fields: Vec<FieldMetadata>) -> Vec<FieldMetadata> {
        fields
            .into_iter()
            .map(|field| FieldMetadata {
                ty: self.convert_type(field.ty),
                ..field
            })
            .collect()
    }

    fn convert_enum(&self, enum_: EnumMetadata) -> EnumMetadata {
        EnumMetadata {
            variants: enum_
                .variants
                .into_iter()
                .map(|variant| VariantMetadata {
                    fields: self.convert_fields(variant.fields),
                    ..variant
                })
                .collect(),
            ..enum_
        }
    }

    fn convert_optional(&self, ty: Option<Type>) -> Option<Type> {
        ty.map(|ty| self.convert_type(ty))
    }

    fn convert_type(&self, ty: Type) -> Type {
        match ty {
            // Convert `ty` if it's external
            Type::Enum { module_path, name } | Type::Record { module_path, name }
                if self.is_module_path_external(&module_path) =>
            {
                Type::External {
                    namespace: self.crate_to_namespace(&module_path),
                    module_path,
                    name,
                    kind: ExternalKind::DataClass,
                    tagged: false,
                }
            }
            Type::Custom {
                module_path, name, ..
            } if self.is_module_path_external(&module_path) => {
                // For now, it's safe to assume that all custom types are data classes.
                // There's no reason to use a custom type with an interface.
                Type::External {
                    namespace: self.crate_to_namespace(&module_path),
                    module_path,
                    name,
                    kind: ExternalKind::DataClass,
                    tagged: false,
                }
            }
            Type::Object {
                module_path, name, ..
            } if self.is_module_path_external(&module_path) => Type::External {
                namespace: self.crate_to_namespace(&module_path),
                module_path,
                name,
                kind: ExternalKind::Interface,
                tagged: false,
            },
            Type::CallbackInterface { module_path, name }
                if self.is_module_path_external(&module_path) =>
            {
                panic!("External callback interfaces not supported ({name})")
            }
            // Convert child types
            Type::Custom {
                module_path,
                name,
                builtin,
                ..
            } => Type::Custom {
                module_path,
                name,
                builtin: Box::new(self.convert_type(*builtin)),
            },
            Type::Optional { inner_type } => Type::Optional {
                inner_type: Box::new(self.convert_type(*inner_type)),
            },
            Type::Sequence { inner_type } => Type::Sequence {
                inner_type: Box::new(self.convert_type(*inner_type)),
            },
            Type::Map {
                key_type,
                value_type,
            } => Type::Map {
                key_type: Box::new(self.convert_type(*key_type)),
                value_type: Box::new(self.convert_type(*value_type)),
            },
            // Existing External types probably need namespace fixed.
            Type::External {
                namespace,
                module_path,
                name,
                kind,
                tagged,
            } => {
                assert!(namespace.is_empty());
                Type::External {
                    namespace: self.crate_to_namespace(&module_path),
                    module_path,
                    name,
                    kind,
                    tagged,
                }
            }

            // Otherwise, just return the type unchanged
            _ => ty,
        }
    }

    fn is_module_path_external(&self, module_path: &str) -> bool {
        calc_crate_name(module_path) != self.crate_name
    }
}

fn calc_crate_name(module_path: &str) -> &str {
    module_path.split("::").next().unwrap()
}

[ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ]