1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use holochain_dna::zome::entry_types::EntryTypeDef;
use holochain_wasm_utils::holochain_core_types::{
    hash::HashString,
    validation::{ValidationData, ValidationPackageDefinition},
};
use std::collections::HashMap;

pub type PackageCreator = Box<FnMut() -> ValidationPackageDefinition + Sync>;
pub type Validator = Box<FnMut(String, ValidationData) -> Result<(), String> + Sync>;
pub type LinkValidator =
    Box<FnMut(HashString, String, HashString, ValidationData) -> Result<(), String> + Sync>;

pub struct ValidatingEntryType {
    pub name: String,
    pub entry_type_definition: EntryTypeDef,
    pub package_creator: PackageCreator,
    pub validator: Validator,
    pub link_validators: HashMap<String, LinkValidator>,
}

/// The `entry` macro is a helper for creating `ValidatingEntryType` definitions
/// for use within the [define_zome](macro.define_zome.html) macro.
/// It has 6 component parts:
/// 1. name: `name` is simply the descriptive name of the entry type, such as "post", or "user".
///      It is what must be given as the `entry_type_name` argument when calling [commit_entry](fn.commit_entry.html) and the other data read/write functions.
/// 2. description: `description` is something that is primarily for human readers of your code, just describe this entry type
/// 3. sharing: `sharing` defines what distribution over the DHT, or not, occurs with entries of this type, possible values
///      are defined in the [Sharing](../holochain_dna/zome/entry_types/enum.Sharing.html) enum
/// 4. native_type: `native_type` references a given Rust struct, which provides a clear schema for entries of this type.
/// 5. validation_package: `validation_package` is a special identifier, which declares which data is required from peers
///      when attempting to validate entries of this type.
///      Possible values are found within [ValidationPackageDefinition](enum.ValidationPackageDefinition.html)
/// 6. validation: `validation` is a callback function which will be called any time that a 
///      source chain action is taken relating to this entry type, such as [commit_entry](fn.commit_entry.html), [update_entry](fn.update_entry.html), [remove_entry](fn.remove_entry.html).
///      It always expects two arguments, the first of which is the entry attempting to be validated,
///      the second is the validation `context`, which offers a variety of metadata useful for validation.
/// # Examples
/// The following is a standalone Rust file that exports a function which can be called
/// to get a `ValidatingEntryType` of a "post".
/// ```rust
/// use boolinator::*;
/// use hdk::{
///   self,
///   entry_definition::ValidatingEntryType,
///   holochain_dna::zome::entry_types::Sharing
/// };
/// use serde_json;
/// 
/// #[derive(Serialize, Deserialize)]
/// pub struct Post {
///     content: String,
///     date_created: String,
/// }
/// 
/// pub fn definition() -> ValidatingEntryType {
///     entry!(
///         name: "post",
///         description: "a short social media style sharing of content",
///         sharing: Sharing::Public,
///         native_type: Post,
/// 
///         validation_package: || {
///             hdk::ValidationPackageDefinition::ChainFull
///         },
/// 
///         validation: |post: Post, _ctx: hdk::ValidationData| {
///             (post.content.len() < 280)
///                 .ok_or_else(|| String::from("Content too long"))
///         }
///     )
/// }
/// ```

#[macro_export]
macro_rules! entry {
    (
        name: $name:expr,
        description: $description:expr,
        sharing: $sharing:expr,
        $(native_type: $native_type:ty,)*

        validation_package: || $package_creator:expr,
        validation: | $entry:ident : $entry_type:ty, $ctx:ident : hdk::ValidationData | $entry_validation:expr
    ) => (

        {
            let mut entry_type = ::hdk::holochain_dna::zome::entry_types::EntryTypeDef::new();
            entry_type.description = String::from($description);
            entry_type.sharing = $sharing;

            let package_creator = Box::new(|| {
                $package_creator
            });

            let validator = Box::new(|raw_entry: String, ctx: ::hdk::holochain_wasm_utils::holochain_core_types::validation::ValidationData| {
                let $ctx = ctx;
                match serde_json::from_str(&raw_entry) {
                    Ok(entry) => {
                        let entry_struct : $entry_type = entry;
                        let $entry = entry_struct;
                        $entry_validation
                    },
                    Err(_) => {
                        Err(String::from("Schema validation failed"))
                    }
                }
            });


            ::hdk::entry_definition::ValidatingEntryType {
                name: String::from($name),
                entry_type_definition: entry_type,
                package_creator,
                validator,
                link_validators: std::collections::HashMap::new(),
            }
        }
    );
}