types FEATURE add hash callback for the types plugins

Since the representation of the value can be type-specific, it make
sense to let the plugin count the hash of the value instead of always
using the canonical representation (and force the plugin to create
such a representation) instead of creating hash from its specific
(e.g. binary) representation.
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 7383373..22ffa5c 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -297,6 +297,14 @@
     return value->_canonical;
 }
 
+API const void *
+lyplg_type_hash_simple(const struct lyd_value *value, ly_bool *dynamic, size_t *key_len)
+{
+    *dynamic = 0;
+    *key_len = strlen(value->_canonical);
+    return value->_canonical;
+}
+
 API LY_ERR
 lyplg_type_dup_simple(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
 {
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 95e089b..fc49d05 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -439,7 +439,21 @@
         LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /**
- * @brief Callback to duplicate data in data structure.
+ * @brief Callback for getting the value hash key. The only requirement is that for 2 equal values this key
+ * MUST be equal. If possible, for 2 non-equal values this key should not be equal.
+ *
+ * It should always be possible to return the canonical value.
+ *
+ * @param[in] value Value to get the hash key of.
+ * @param[out] dynamic Flag if the returned hash key is dynamically allocated. In such a case the caller is responsible
+ * for freeing it.
+ * @param[out] key_len Returned hash key length in bytes.
+ * @return Hash key.
+ */
+typedef const void *(*lyplg_type_hash_clb)(const struct lyd_value *value, ly_bool *dynamic, size_t *key_len);
+
+/**
+ * @brief Callback to duplicate data in the data structure.
  *
  * @param[in] ctx libyang context of the @p dup. Note that the context of @p original and @p dup might not be the same.
  * @param[in] original Original data structure to be duplicated.
@@ -474,6 +488,7 @@
     lyplg_type_validate_clb validate;   /**< optional, validate the value in the type-specific way in data */
     lyplg_type_compare_clb compare;     /**< comparison callback to compare 2 values of the same type */
     lyplg_type_print_clb print;         /**< printer callback to get string representing the value */
+    lyplg_type_hash_clb hash;           /**< hash callback to get the hash key of the value */
     lyplg_type_dup_clb duplicate;       /**< data duplication callback */
     lyplg_type_free_clb free;           /**< optional function to free the type-spceific way stored value */
 };
@@ -515,6 +530,12 @@
         void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /**
+ * @brief Generic simple hash callback of the canonized value.
+ * Implementation of the ::lyplg_type_hash_clb.
+ */
+const void *lyplg_type_hash_simple(const struct lyd_value *value, ly_bool *dynamic, size_t *key_len);
+
+/**
  * @brief Generic simple duplication callback.
  * Implementation of the ::lyplg_type_dup_clb.
  */
@@ -791,6 +812,12 @@
         void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /**
+ * @brief Hash key callback for a leafref value.
+ * Implementation of ::lyplg_type_hash_clb.
+ */
+const void *lyplg_type_hash_leafref(const struct lyd_value *value, ly_bool *dynamic, size_t *key_len);
+
+/**
  * @brief Duplication callback of the leafref values.
  * Implementation of the ::lyplg_type_dup_clb.
  */
@@ -859,6 +886,12 @@
         void *prefix_data, ly_bool *dynamic, size_t *value_len);
 
 /**
+ * @brief Hash key callback for a union value.
+ * Implementation of ::lyplg_type_hash_clb.
+ */
+const void *lyplg_type_hash_union(const struct lyd_value *value, ly_bool *dynamic, size_t *key_len);
+
+/**
  * @brief Duplication callback of the union values.
  * Implementation of the ::lyplg_type_dup_clb.
  */
diff --git a/src/plugins_types/binary.c b/src/plugins_types/binary.c
index 16833ea..23f410b 100644
--- a/src/plugins_types/binary.c
+++ b/src/plugins_types/binary.c
@@ -144,6 +144,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple,
     },
diff --git a/src/plugins_types/bits.c b/src/plugins_types/bits.c
index c59de75..a74ada4 100644
--- a/src/plugins_types/bits.c
+++ b/src/plugins_types/bits.c
@@ -240,6 +240,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_bits,
         .plugin.free = lyplg_type_free_bits
     },
diff --git a/src/plugins_types/boolean.c b/src/plugins_types/boolean.c
index 4a8b20c..5a681ad 100644
--- a/src/plugins_types/boolean.c
+++ b/src/plugins_types/boolean.c
@@ -89,6 +89,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     },
diff --git a/src/plugins_types/date_and_time.c b/src/plugins_types/date_and_time.c
index 31ec7c7..24b5034 100644
--- a/src/plugins_types/date_and_time.c
+++ b/src/plugins_types/date_and_time.c
@@ -268,6 +268,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     },
diff --git a/src/plugins_types/decimal64.c b/src/plugins_types/decimal64.c
index ea7d5c4..54416a5 100644
--- a/src/plugins_types/decimal64.c
+++ b/src/plugins_types/decimal64.c
@@ -116,6 +116,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     },
diff --git a/src/plugins_types/empty.c b/src/plugins_types/empty.c
index 172c3ad..7eaec74 100644
--- a/src/plugins_types/empty.c
+++ b/src/plugins_types/empty.c
@@ -94,6 +94,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_empty,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     },
diff --git a/src/plugins_types/enumeration.c b/src/plugins_types/enumeration.c
index da24316..dadf51f 100644
--- a/src/plugins_types/enumeration.c
+++ b/src/plugins_types/enumeration.c
@@ -95,6 +95,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     },
diff --git a/src/plugins_types/hex_string.c b/src/plugins_types/hex_string.c
index 1a29d3e..ab8f2fa 100644
--- a/src/plugins_types/hex_string.c
+++ b/src/plugins_types/hex_string.c
@@ -93,6 +93,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     },
@@ -106,6 +107,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     },
@@ -119,6 +121,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     },
@@ -132,6 +135,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     },
diff --git a/src/plugins_types/identityref.c b/src/plugins_types/identityref.c
index 3b40c28..092d73a 100644
--- a/src/plugins_types/identityref.c
+++ b/src/plugins_types/identityref.c
@@ -214,6 +214,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_identityref,
         .plugin.print = lyplg_type_print_identityref,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     },
diff --git a/src/plugins_types/instanceid.c b/src/plugins_types/instanceid.c
index f9f4707..1fa97a4 100644
--- a/src/plugins_types/instanceid.c
+++ b/src/plugins_types/instanceid.c
@@ -324,6 +324,7 @@
         .plugin.validate = lyplg_type_validate_instanceid,
         .plugin.compare = lyplg_type_compare_instanceid,
         .plugin.print = lyplg_type_print_instanceid,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_instanceid,
         .plugin.free = lyplg_type_free_instanceid
     },
diff --git a/src/plugins_types/integer.c b/src/plugins_types/integer.c
index d1a5b1f..c042e49 100644
--- a/src/plugins_types/integer.c
+++ b/src/plugins_types/integer.c
@@ -193,6 +193,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     }, {
@@ -205,6 +206,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     }, {
@@ -217,6 +219,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     }, {
@@ -229,6 +232,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     }, {
@@ -241,6 +245,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     }, {
@@ -253,6 +258,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     }, {
@@ -265,6 +271,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     }, {
@@ -277,6 +284,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     },
diff --git a/src/plugins_types/ip_prefix.c b/src/plugins_types/ip_prefix.c
index 9eef670..3dcbe50 100644
--- a/src/plugins_types/ip_prefix.c
+++ b/src/plugins_types/ip_prefix.c
@@ -280,6 +280,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     },
@@ -293,6 +294,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     },
diff --git a/src/plugins_types/leafref.c b/src/plugins_types/leafref.c
index 03190ba..99baf84 100644
--- a/src/plugins_types/leafref.c
+++ b/src/plugins_types/leafref.c
@@ -96,6 +96,12 @@
     return value->realtype->plugin->print(ctx, value, format, prefix_data, dynamic, value_len);
 }
 
+API const void *
+lyplg_type_hash_leafref(const struct lyd_value *value, ly_bool *dynamic, size_t *key_len)
+{
+    return value->realtype->plugin->hash(value, dynamic, key_len);
+}
+
 API LY_ERR
 lyplg_type_dup_leafref(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
 {
@@ -129,6 +135,7 @@
         .plugin.validate = lyplg_type_validate_leafref,
         .plugin.compare = lyplg_type_compare_leafref,
         .plugin.print = lyplg_type_print_leafref,
+        .plugin.hash = lyplg_type_hash_leafref,
         .plugin.duplicate = lyplg_type_dup_leafref,
         .plugin.free = lyplg_type_free_leafref
     },
diff --git a/src/plugins_types/string.c b/src/plugins_types/string.c
index 1d67cfa..eb05c7d 100644
--- a/src/plugins_types/string.c
+++ b/src/plugins_types/string.c
@@ -92,6 +92,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_simple,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple
     },
diff --git a/src/plugins_types/union.c b/src/plugins_types/union.c
index 9b11dd8..aa33929 100644
--- a/src/plugins_types/union.c
+++ b/src/plugins_types/union.c
@@ -206,6 +206,12 @@
     return ret;
 }
 
+API const void *
+lyplg_type_hash_union(const struct lyd_value *value, ly_bool *dynamic, size_t *key_len)
+{
+    return value->subvalue->value.realtype->plugin->hash(value, dynamic, key_len);
+}
+
 API LY_ERR
 lyplg_type_dup_union(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
 {
@@ -258,6 +264,7 @@
         .plugin.validate = lyplg_type_validate_union,
         .plugin.compare = lyplg_type_compare_union,
         .plugin.print = lyplg_type_print_union,
+        .plugin.hash = lyplg_type_hash_union,
         .plugin.duplicate = lyplg_type_dup_union,
         .plugin.free = lyplg_type_free_union
     },
diff --git a/src/plugins_types/xpath1.0.c b/src/plugins_types/xpath1.0.c
index 3ebad18..0f6fa39 100644
--- a/src/plugins_types/xpath1.0.c
+++ b/src/plugins_types/xpath1.0.c
@@ -338,6 +338,7 @@
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
         .plugin.print = lyplg_type_print_xpath10,
+        .plugin.hash = lyplg_type_hash_simple,
         .plugin.duplicate = lyplg_type_dup_xpath10,
         .plugin.free = lyplg_type_free_xpath10
     },
diff --git a/src/tree_data_hash.c b/src/tree_data_hash.c
index b56f5b9..1704a5b 100644
--- a/src/tree_data_hash.c
+++ b/src/tree_data_hash.c
@@ -21,6 +21,7 @@
 #include "compat.h"
 #include "hash_table.h"
 #include "log.h"
+#include "plugins_types.h"
 #include "tree.h"
 #include "tree_data.h"
 #include "tree_schema.h"
@@ -29,6 +30,9 @@
 lyd_hash(struct lyd_node *node)
 {
     struct lyd_node *iter;
+    const void *hash_key;
+    ly_bool dyn;
+    size_t key_len;
 
     if (!node->schema) {
         return LY_SUCCESS;
@@ -47,14 +51,24 @@
 
             /* list hash is made up from its keys */
             for (iter = list->child; iter && (iter->schema->flags & LYS_KEY); iter = iter->next) {
-                const char *value = lyd_get_value(iter);
-                node->hash = dict_hash_multi(node->hash, value, strlen(value));
+                struct lyd_node_term *key = (struct lyd_node_term *)iter;
+
+                hash_key = key->value.realtype->plugin->hash(&key->value, &dyn, &key_len);
+                node->hash = dict_hash_multi(node->hash, hash_key, key_len);
+                if (dyn) {
+                    free((void *)hash_key);
+                }
             }
         }
     } else if (node->schema->nodetype == LYS_LEAFLIST) {
-        /* leaf-list adds its value */
-        const char *value = lyd_get_value(node);
-        node->hash = dict_hash_multi(node->hash, value, strlen(value));
+        /* leaf-list adds its hash key */
+        struct lyd_node_term *llist = (struct lyd_node_term *)node;
+
+        hash_key = llist->value.realtype->plugin->hash(&llist->value, &dyn, &key_len);
+        node->hash = dict_hash_multi(node->hash, hash_key, key_len);
+        if (dyn) {
+            free((void *)hash_key);
+        }
     }
 
     /* finish the hash */
diff --git a/src/validation.c b/src/validation.c
index 1a0c396..8895531 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -1038,8 +1038,9 @@
     LY_ARRAY_COUNT_TYPE u, v, x = 0;
     LY_ERR ret = LY_SUCCESS;
     uint32_t hash, i, size = 0;
-    ly_bool dynamic;
-    const char *str;
+    size_t key_len;
+    ly_bool dyn;
+    const void *hash_key;
     struct hash_table **uniqtables = NULL;
     struct lyd_value *val;
     struct ly_ctx *ctx = snode->module->ctx;
@@ -1104,11 +1105,11 @@
                         break;
                     }
 
-                    /* get canonical string value */
-                    str = val->realtype->plugin->print(ctx, val, LY_VALUE_JSON, NULL, &dynamic, NULL);
-                    hash = dict_hash_multi(hash, str, strlen(str));
-                    if (dynamic) {
-                        free((char *)str);
+                    /* get hash key */
+                    hash_key = val->realtype->plugin->hash(val, &dyn, &key_len);
+                    hash = dict_hash_multi(hash, hash_key, key_len);
+                    if (dyn) {
+                        free((void *)hash_key);
                     }
                 }
                 if (!val) {