datagen-rs 0.1.0

A random data generator written in rust
Documentation
#[cfg(feature = "map-schema")]
use crate::generate::generated_schema::GeneratedSchema;
#[cfg(feature = "map-schema")]
use crate::generate::resolved_reference::ResolvedReference;
#[cfg(feature = "map-schema")]
use crate::generate::schema_path::SchemaPath;
#[cfg(feature = "map-schema")]
use crate::generate::schema_value::SchemaProperties;
use crate::generate::schema_value::SchemaValue;
use crate::plugins::plugin::Plugin;
use crate::plugins::plugin_list::PluginList;
use crate::schema::schema_definition::SchemaOptions;
use crate::util::types::Result;
#[cfg(feature = "generate")]
use std::collections::BTreeMap;
use std::sync::atomic::AtomicBool;
#[cfg(feature = "map-schema")]
use std::sync::atomic::Ordering;
use std::sync::{Arc, Mutex};

#[derive(Debug)]
#[cfg_attr(not(feature = "generate"), allow(dead_code))]
pub struct CurrentSchema {
    parent: Option<CurrentSchemaRef>,
    value: Arc<Mutex<SchemaValue>>,
    options: Arc<SchemaOptions>,
    plugins: Arc<PluginList>,
    finalized: AtomicBool,
}

unsafe impl Send for CurrentSchema {}
unsafe impl Sync for CurrentSchema {}

pub type CurrentSchemaRef = Arc<CurrentSchema>;

impl CurrentSchema {
    #[cfg(feature = "generate")]
    pub fn root(options: Arc<SchemaOptions>, plugins: Arc<PluginList>) -> CurrentSchemaRef {
        Self {
            parent: None,
            value: Arc::new(Mutex::new(SchemaValue {
                properties: Arc::new(Mutex::new(BTreeMap::new())),
                path: SchemaPath::root(),
            })),
            options,
            plugins,
            finalized: AtomicBool::default(),
        }
        .into()
    }

    #[cfg(feature = "map-schema")]
    pub fn child(
        parent: CurrentSchemaRef,
        sibling: Option<CurrentSchemaRef>,
        path: String,
    ) -> CurrentSchema {
        CurrentSchema {
            parent: Some(parent.clone()),
            value: Arc::new(Mutex::new(SchemaValue {
                properties: sibling
                    .map(|s| s.value.lock().unwrap().properties.clone())
                    .unwrap_or_default(),
                path: parent.value.lock().unwrap().path.append(path),
            })),
            options: parent.options.clone(),
            plugins: parent.plugins.clone(),
            finalized: AtomicBool::default(),
        }
    }

    #[cfg(feature = "map-schema")]
    fn get_global_properties(&self) -> Arc<Mutex<SchemaProperties>> {
        if let Some(parent) = self.parent.as_ref() {
            parent.get_global_properties()
        } else {
            self.value.lock().unwrap().properties.clone()
        }
    }

    #[cfg(feature = "map-schema")]
    fn get_all_schemas(props: &SchemaProperties, path: &str) -> ResolvedReference {
        if let Some(props) = props.get(path) {
            if props.len() == 1 {
                ResolvedReference::Single(props.get(0).unwrap().clone())
            } else {
                ResolvedReference::multiple(props.clone().into())
            }
        } else {
            ResolvedReference::none()
        }
    }

    #[cfg(feature = "map-schema")]
    fn resolve_child_ref(&self, reference: String) -> Result<ResolvedReference> {
        if reference.starts_with("../") {
            self.parent
                .as_ref()
                .ok_or(format!(
                    "The current schema at path '{}' has no parent",
                    self.value.lock().unwrap().path
                ))?
                .resolve_child_ref(reference.strip_prefix("../").unwrap().to_string())
        } else {
            let properties = &self.value.lock().unwrap().properties;
            let properties = properties.lock().unwrap();

            Ok(Self::get_all_schemas(&properties, &reference))
        }
    }

    #[cfg(feature = "map-schema")]
    pub fn resolve_ref(&self, reference: String) -> Result<ResolvedReference> {
        if reference.starts_with("ref:") {
            let stripped = reference.strip_prefix("ref:").unwrap().to_string();
            if stripped.starts_with("./") {
                let properties = &self.value.lock().unwrap().properties;
                let properties = properties.lock().unwrap();

                Ok(Self::get_all_schemas(
                    &properties,
                    stripped.strip_prefix("./").unwrap(),
                ))
            } else if stripped.starts_with("../") {
                self.resolve_child_ref(stripped)
            } else {
                let global_properties = self.get_global_properties();
                let properties = global_properties.lock().unwrap();

                Ok(Self::get_all_schemas(&properties, &stripped))
            }
        } else {
            Ok(ResolvedReference::single(GeneratedSchema::String(
                reference,
            )))
        }
    }

    #[cfg(feature = "map-schema")]
    fn finalize_inner(&self, schema: Arc<GeneratedSchema>, path: &SchemaPath, remove: i32) {
        self.value.lock().unwrap().finalize(
            &self.options,
            schema.clone(),
            path.pop(remove).to_normalized_path(),
        );

        if let Some(parent) = self.parent.as_ref() {
            parent.finalize_inner(schema, path, remove - 1);
        }
    }

    #[cfg(feature = "map-schema")]
    pub fn finalize(&self, schema: Arc<GeneratedSchema>) -> Arc<GeneratedSchema> {
        if self.finalized.load(Ordering::SeqCst) {
            return schema;
        }

        let path = self.value.lock().unwrap().path().clone();
        self.finalize_inner(schema.clone(), &path, (path.len() as i32) - 1);
        self.finalized.store(true, Ordering::SeqCst);

        schema
    }

    #[cfg(feature = "map-schema")]
    pub fn path(&self) -> SchemaPath {
        self.value.lock().unwrap().path.clone()
    }

    pub fn get_plugin<'a>(&'a self, key: &String) -> Result<&'a dyn Plugin> {
        self.plugins.get(key)
    }

    #[allow(dead_code)]
    pub fn plugin_exists(&self, key: &String) -> bool {
        self.plugins.exists(key)
    }

    pub fn options(&self) -> &Arc<SchemaOptions> {
        &self.options
    }
}