data types CHANGE simplify data types plugins API

All callbacks are now mandatory in built-in types (so no check for the
callback presence is needed now). Also the validate and store callback
are now connected in a store callback which is (according to the
options) supposed to validate, canonize and store data. This change is
needed in the case the validation process needs to compare the current
data with some reference node,
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 7564591..d51fc43 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -29,6 +29,33 @@
 #include "xml.h"
 #include "xpath.h"
 
+/**
+ * @brief Generic comparison callback checking the canonical value.
+ *
+ * Implementation of the ly_type_compare_clb.
+ */
+static LY_ERR
+ly_type_compare_canonical(const struct lyd_value *val1, const struct lyd_value *val2)
+{
+    if (val1 == val2 || !strcmp(val1->canonized, val2->canonized)) {
+        return LY_SUCCESS;
+    }
+
+    return LY_EVALID;
+}
+
+/**
+ * @brief Free canonized value in lyd_value.
+ *
+ * Implementation of the ly_type_free_clb.
+ */
+static void
+ly_type_free_canonical(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), struct lyd_value *value)
+{
+    lydict_remove(ctx, value->canonized);
+    value->canonized = NULL;
+}
+
 API LY_ERR
 ly_type_parse_int(const char *datatype, int base, int64_t min, int64_t max, const char *value, size_t value_len, int64_t *ret, struct ly_err_item **err)
 {
@@ -352,43 +379,59 @@
     return LY_EVALID;
 }
 
-static LY_ERR
-ly_type_parse_int_builtin(LY_DATA_TYPE basetype, const char *value, size_t value_len, int options, int64_t *val, struct ly_err_item **err)
+static void
+ly_type_store_canonized(struct ly_ctx *ctx, int options, const char *value, struct lyd_value *storage, const char **canonized)
 {
-    switch (basetype) {
-    case LY_TYPE_INT8:
-        return ly_type_parse_int("int16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, INT64_C(-128), INT64_C(127), value, value_len, val, err);
-    case LY_TYPE_INT16:
-        return ly_type_parse_int("int16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, INT64_C(-32768), INT64_C(32767), value, value_len, val, err);
-    case LY_TYPE_INT32:
-        return ly_type_parse_int("int32", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10,
-                         INT64_C(-2147483648), INT64_C(2147483647), value, value_len, val, err);
-    case LY_TYPE_INT64:
-        return ly_type_parse_int("int64", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10,
-                         INT64_C(-9223372036854775807) - INT64_C(1), INT64_C(9223372036854775807), value, value_len, val, err);
-    default:
-        LOGINT(NULL);
-        return LY_EINVAL;
+    if (options & LY_TYPE_OPTS_CANONIZE) {
+store_canonized:
+        *canonized = value;
+    }
+    if ((options & LY_TYPE_OPTS_STORE) && !storage->canonized) {
+        if (options & LY_TYPE_OPTS_CANONIZE) {
+            /* already stored outside the storage */
+            storage->canonized = lydict_insert(ctx, value, strlen(value));
+        } else {
+            canonized = &storage->canonized;
+            goto store_canonized;
+        }
     }
 }
 
 /**
- * @brief Validate and canonize value of the YANG built-in signed integer types.
+ * @brief Validate, canonize and store value of the YANG built-in signed integer types.
  *
- * Implementation of the ly_type_validate_clb.
+ * Implementation of the ly_type_store_clb.
  */
 static LY_ERR
-ly_type_validate_int(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
-                     ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                     const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
-                     const char **canonized, struct ly_err_item **err, void **priv)
+ly_type_store_int(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+                  ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+                  const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+                  struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     LY_ERR ret;
     int64_t i;
     char *str;
     struct lysc_type_num *type_num = (struct lysc_type_num *)type;
 
-    LY_CHECK_RET(ly_type_parse_int_builtin(type->basetype, value, value_len, options, &i, err));
+    switch (type->basetype) {
+    case LY_TYPE_INT8:
+        LY_CHECK_RET(ly_type_parse_int("int16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, INT64_C(-128), INT64_C(127), value, value_len, &i, err));
+        break;
+    case LY_TYPE_INT16:
+        LY_CHECK_RET(ly_type_parse_int("int16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, INT64_C(-32768), INT64_C(32767), value, value_len, &i, err));
+        break;
+    case LY_TYPE_INT32:
+        LY_CHECK_RET(ly_type_parse_int("int32", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10,
+                                       INT64_C(-2147483648), INT64_C(2147483647), value, value_len, &i, err));
+        break;
+    case LY_TYPE_INT64:
+        LY_CHECK_RET(ly_type_parse_int("int64", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10,
+                                       INT64_C(-9223372036854775807) - INT64_C(1), INT64_C(9223372036854775807), value, value_len, &i, err));
+        break;
+    default:
+        LOGINT(NULL);
+        return LY_EINVAL;
+    }
     asprintf(&str, "%"PRId64, i);
 
     /* range of the number */
@@ -396,20 +439,14 @@
         LY_CHECK_ERR_RET(ret = ly_type_validate_range(type->basetype, type_num->range, i, str, err), free(str), ret);
     }
 
-    if (options & LY_TYPE_OPTS_CANONIZE) {
-        *canonized = lydict_insert_zc(ctx, str);
+    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
+        ly_type_store_canonized(ctx, options, lydict_insert_zc(ctx, str), storage, canonized);
     } else {
         free(str);
     }
 
     if (options & LY_TYPE_OPTS_STORE) {
-        /* save for the store callback */
-        *priv = malloc(sizeof i);
-        if (!(*priv)) {
-            *err = ly_err_new(LY_LLERR, LY_EMEM, 0, "Memory allocation failed.", NULL, NULL);
-            return LY_EMEM;
-        }
-        *(int64_t*)(*priv) = i;
+        storage->int64 = i;
     }
 
     if (options & LY_TYPE_OPTS_DYNAMIC) {
@@ -420,65 +457,38 @@
 }
 
 /**
- * @brief Store value of the YANG built-in signed integer types.
+ * @brief Validate and canonize value of the YANG built-in unsigned integer types.
  *
  * Implementation of the ly_type_store_clb.
  */
 static LY_ERR
-ly_type_store_int(struct ly_ctx *UNUSED(ctx), struct lysc_type *type, int options,
-                  struct lyd_value *value, struct ly_err_item **err, void **priv)
-{
-    int64_t i;
-
-    if (options & LY_TYPE_OPTS_VALIDATE) {
-        /* the value was prepared by ly_type_validate_int() */
-        i = *(int64_t*)(*priv);
-        free(*priv);
-    } else {
-        LY_CHECK_RET(ly_type_parse_int_builtin(type->basetype, value->canonized, strlen(value->canonized), options, &i, err));
-    }
-
-    /* store the result */
-    value->int64 = i;
-
-    return LY_SUCCESS;
-}
-
-static LY_ERR
-ly_type_parse_uint_builtin(LY_DATA_TYPE basetype, const char *value, size_t value_len, int options, uint64_t *val, struct ly_err_item **err)
-{
-    switch (basetype) {
-    case LY_TYPE_UINT8:
-        return ly_type_parse_uint("uint16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(255), value, value_len, val, err);
-    case LY_TYPE_UINT16:
-        return ly_type_parse_uint("uint16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(65535), value, value_len, val, err);
-    case LY_TYPE_UINT32:
-        return ly_type_parse_uint("uint32", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(4294967295), value, value_len, val, err);
-    case LY_TYPE_UINT64:
-        return ly_type_parse_uint("uint64", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(18446744073709551615), value, value_len, val, err);
-    default:
-        LOGINT(NULL);
-        return LY_EINVAL;
-    }
-}
-
-/**
- * @brief Validate and canonize value of the YANG built-in unsigned integer types.
- *
- * Implementation of the ly_type_validate_clb.
- */
-static LY_ERR
-ly_type_validate_uint(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
-                      ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                      const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
-                      const char **canonized, struct ly_err_item **err, void **priv)
+ly_type_store_uint(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+                   ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+                   const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+                   struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     LY_ERR ret;
     uint64_t u;
     struct lysc_type_num* type_num = (struct lysc_type_num*)type;
     char *str;
 
-    LY_CHECK_RET(ly_type_parse_uint_builtin(type->basetype, value, value_len, options, &u, err));
+    switch (type->basetype) {
+    case LY_TYPE_UINT8:
+        LY_CHECK_RET(ly_type_parse_uint("uint16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(255), value, value_len, &u, err));
+        break;
+    case LY_TYPE_UINT16:
+        LY_CHECK_RET(ly_type_parse_uint("uint16", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(65535), value, value_len, &u, err));
+        break;
+    case LY_TYPE_UINT32:
+        LY_CHECK_RET(ly_type_parse_uint("uint32", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(4294967295), value, value_len, &u, err));
+        break;
+    case LY_TYPE_UINT64:
+        LY_CHECK_RET(ly_type_parse_uint("uint64", (options & LY_TYPE_OPTS_SCHEMA) ? 0 : 10, UINT64_C(18446744073709551615), value, value_len, &u, err));
+        break;
+    default:
+        LOGINT(NULL);
+        return LY_EINVAL;
+    }
     asprintf(&str, "%"PRIu64, u);
 
     /* range of the number */
@@ -486,20 +496,14 @@
         LY_CHECK_ERR_RET(ret = ly_type_validate_range(type->basetype, type_num->range, u, str, err), free(str), ret);
     }
 
-    if (options & LY_TYPE_OPTS_CANONIZE) {
-        *canonized = lydict_insert_zc(ctx, str);
+    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
+        ly_type_store_canonized(ctx, options, lydict_insert_zc(ctx, str), storage, canonized);
     } else {
         free(str);
     }
 
     if (options & LY_TYPE_OPTS_STORE) {
-        /* save for the store callback */
-        *priv = malloc(sizeof u);
-        if (!(*priv)) {
-            *err = ly_err_new(LY_LLERR, LY_EMEM, 0, "Memory allocation failed.", NULL, NULL);
-            return LY_EMEM;
-        }
-        *(uint64_t*)(*priv) = u;
+        storage->uint64 = u;
     }
 
     if (options & LY_TYPE_OPTS_DYNAMIC) {
@@ -510,40 +514,15 @@
 }
 
 /**
- * @brief Store value of the YANG built-in unsigned integer types.
+ * @brief Validate, canonize and store value of the YANG built-in decimal64 types.
  *
  * Implementation of the ly_type_store_clb.
  */
 static LY_ERR
-ly_type_store_uint(struct ly_ctx *UNUSED(ctx), struct lysc_type *type, int options,
-                   struct lyd_value *value, struct ly_err_item **err, void **priv)
-{
-    uint64_t u;
-
-    if (options & LY_TYPE_OPTS_VALIDATE) {
-        /* the value was prepared by ly_type_validate_uint() */
-        u = *(uint64_t*)(*priv);
-        free(*priv);
-    } else {
-        LY_CHECK_RET(ly_type_parse_uint_builtin(type->basetype, value->canonized, strlen(value->canonized), options, &u, err));
-    }
-
-    /* store the result */
-    value->uint64 = u;
-
-    return LY_SUCCESS;
-}
-
-/**
- * @brief Validate and canonize value of the YANG built-in decimal64 types.
- *
- * Implementation of the ly_type_validate_clb.
- */
-static LY_ERR
-ly_type_validate_decimal64(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
-                           ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                           const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
-                           const char **canonized, struct ly_err_item **err, void **priv)
+ly_type_store_decimal64(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+                        ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+                        const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+                        struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     int64_t d;
     struct lysc_type_dec* type_dec = (struct lysc_type_dec*)type;
@@ -587,17 +566,12 @@
         LY_CHECK_RET(ly_type_validate_range(type->basetype, type_dec->range, d, buf, err));
     }
 
-    if (options & LY_TYPE_OPTS_CANONIZE) {
-        *canonized = lydict_insert(ctx, buf, strlen(buf));
+    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
+        ly_type_store_canonized(ctx, options, lydict_insert(ctx, buf, strlen(buf)), storage, canonized);
     }
+
     if (options & LY_TYPE_OPTS_STORE) {
-        /* save for the store callback */
-        *priv = malloc(sizeof d);
-        if (!(*priv)) {
-            *err = ly_err_new(LY_LLERR, LY_EMEM, 0, "Memory allocation failed.", NULL, NULL);
-            return LY_EMEM;
-        }
-        *(int64_t*)(*priv) = d;
+        storage->dec64 = d;
     }
 
     if (options & LY_TYPE_OPTS_DYNAMIC) {
@@ -608,42 +582,15 @@
 }
 
 /**
- * @brief Store value of the YANG built-in decimal64 types.
+ * @brief Validate, canonize and store value of the YANG built-in binary type.
  *
  * Implementation of the ly_type_store_clb.
  */
 static LY_ERR
-ly_type_store_decimal64(struct ly_ctx *UNUSED(ctx), struct lysc_type *UNUSED(type), int options,
-                        struct lyd_value *value, struct ly_err_item **UNUSED(err), void **priv)
-{
-    int64_t d;
-
-    if (options & LY_TYPE_OPTS_VALIDATE) {
-        /* the value was prepared by ly_type_validate_uint() */
-        d = *(int64_t*)(*priv);
-        free(*priv);
-    } else {
-        /* TODO if there is usecase for store without validate */
-        LOGINT(NULL);
-        return LY_EINT;
-    }
-
-    /* store the result */
-    value->dec64 = d;
-
-    return LY_SUCCESS;
-}
-
-/**
- * @brief Validate and canonize value of the YANG built-in binary type.
- *
- * Implementation of the ly_type_validate_clb.
- */
-static LY_ERR
-ly_type_validate_binary(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
-                        ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                        const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
-                        const char **canonized, struct ly_err_item **err, void **UNUSED(priv))
+ly_type_store_binary(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+                     ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+                     const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+                     struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     size_t start = 0, stop = 0, count = 0, u, termination = 0;
     struct lysc_type_bin *type_bin = (struct lysc_type_bin *)type;
@@ -709,16 +656,17 @@
         LY_CHECK_RET(ly_type_validate_range(LY_TYPE_BINARY, type_bin->length, len, buf, err));
     }
 
-    if (options & LY_TYPE_OPTS_CANONIZE) {
+    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
         if (start != 0 || (value_len && stop != value_len - 1)) {
-            *canonized = lydict_insert_zc(ctx, strndup(&value[start], stop + 1 - start));
+            ly_type_store_canonized(ctx, options, lydict_insert_zc(ctx, strndup(&value[start], stop + 1 - start)), storage, canonized);
         } else if (options & LY_TYPE_OPTS_DYNAMIC) {
-            *canonized = lydict_insert_zc(ctx, (char*)value);
+            ly_type_store_canonized(ctx, options, lydict_insert_zc(ctx, (char*)value), storage, canonized);
             value = NULL;
         } else {
-            *canonized = lydict_insert(ctx, value_len ? value : "", value_len);
+            ly_type_store_canonized(ctx, options, lydict_insert(ctx, value_len ? value : "", value_len), storage, canonized);
         }
     }
+
     if (options & LY_TYPE_OPTS_DYNAMIC) {
         free((char*)value);
     }
@@ -733,15 +681,15 @@
 }
 
 /**
- * @brief Validate value of the YANG built-in string type.
+ * @brief Validate and store value of the YANG built-in string type.
  *
- * Implementation of the ly_type_validate_clb.
+ * Implementation of the ly_type_store_clb.
  */
 static LY_ERR
-ly_type_validate_string(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
-                        ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                        const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
-                        const char **canonized, struct ly_err_item **err, void **UNUSED(priv))
+ly_type_store_string(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+                     ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+                     const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+                     struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     struct lysc_type_str *type_str = (struct lysc_type_str *)type;
 
@@ -755,12 +703,12 @@
     /* pattern restrictions */
     LY_CHECK_RET(ly_type_validate_patterns(type_str->patterns, value, value_len, err));
 
-    if (options & LY_TYPE_OPTS_CANONIZE) {
+    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
         if (options & LY_TYPE_OPTS_DYNAMIC) {
-            *canonized = lydict_insert_zc(ctx, (char*)value);
+            ly_type_store_canonized(ctx, options, lydict_insert_zc(ctx, (char*)value), storage, canonized);
             value = NULL;
         } else {
-            *canonized = lydict_insert(ctx, value_len ? value : "", value_len);
+            ly_type_store_canonized(ctx, options, lydict_insert(ctx, value_len ? value : "", value_len), storage, canonized);
         }
     }
 
@@ -772,15 +720,15 @@
 }
 
 /**
- * @brief Validate and canonize value of the YANG built-in bits type.
+ * @brief Validate, canonize and store value of the YANG built-in bits type.
  *
- * Implementation of the ly_type_validate_clb.
+ * Implementation of the ly_type_store_clb.
  */
 static LY_ERR
-ly_type_validate_bits(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
-                      ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                      const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
-                      const char **canonized, struct ly_err_item **err, void **priv)
+ly_type_store_bits(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+                   ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+                   const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+                   struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     LY_ERR ret = LY_EVALID;
     size_t item_len;
@@ -795,6 +743,7 @@
     int iscanonical = 1;
     size_t ws_count;
     size_t lws_count; /* leading whitespace count */
+    const char *can = NULL;
 
     /* remember the present items for further work */
     items = ly_set_new();
@@ -850,58 +799,56 @@
     }
     /* validation done */
 
-    if (options & LY_TYPE_OPTS_CANONIZE) {
-        if (options & LY_TYPE_OPTS_STORE) {
-            if (iscanonical) {
-                items_ordered = items;
-                items = NULL;
-            } else {
-                items_ordered = ly_set_dup(items, NULL);
-                LY_CHECK_ERR_GOTO(!items_ordered, LOGMEM(ctx); ret = LY_EMEM, error);
-                items_ordered->count = 0;
-            }
-        }
+    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
         if (iscanonical) {
+            /* items are already ordered */
+            items_ordered = items;
+            items = NULL;
+
             if (!ws_count && !lws_count && (options & LY_TYPE_OPTS_DYNAMIC)) {
-                *canonized = lydict_insert_zc(ctx, (char*)value);
+                can = lydict_insert_zc(ctx, (char*)value);
                 value = NULL;
             } else {
-                *canonized = lydict_insert(ctx, value_len ? &value[lws_count] : "", value_len - ws_count - lws_count);
+                can = lydict_insert(ctx, value_len ? &value[lws_count] : "", value_len - ws_count - lws_count);
             }
         } else {
             buf = malloc(buf_size * sizeof *buf);
             LY_CHECK_ERR_GOTO(!buf, LOGMEM(ctx); ret = LY_EMEM, error);
             index = 0;
 
+            items_ordered = ly_set_dup(items, NULL);
+            LY_CHECK_ERR_GOTO(!items_ordered, LOGMEM(ctx); ret = LY_EMEM, error);
+            items_ordered->count = 0;
+
             /* generate ordered bits list */
             LY_ARRAY_FOR(type_bits->bits, u) {
-                int i = ly_set_contains(items, &type_bits->bits[u]);
-                if (i != -1) {
+                if (ly_set_contains(items, &type_bits->bits[u]) != -1) {
                     int c = sprintf(&buf[index], "%s%s", index ? " " : "", type_bits->bits[u].name);
                     LY_CHECK_ERR_GOTO(c < 0, LOGERR(ctx, LY_ESYS, "sprintf() failed."); ret = LY_ESYS, error);
                     index += c;
-                    if (items_ordered) {
-                        ly_set_add(items_ordered, &type_bits->bits[u], LY_SET_OPT_USEASLIST);
-                    }
+                    ly_set_add(items_ordered, &type_bits->bits[u], LY_SET_OPT_USEASLIST);
                 }
             }
             assert(buf_size == index + 1);
             /* termination NULL-byte */
             buf[index] = '\0';
 
-            *canonized = lydict_insert_zc(ctx, buf);
+            can = lydict_insert_zc(ctx, buf);
             buf = NULL;
         }
-    }
 
-    if (options & LY_TYPE_OPTS_STORE) {
-        /* remember the set to store */
-        if (items_ordered) {
-            *priv = items_ordered;
-        } else {
-            *priv = items;
-            items = NULL;
+        ly_type_store_canonized(ctx, options, can, storage, canonized);
+        can = NULL;
+
+        if (options & LY_TYPE_OPTS_STORE) {
+            /* store data */
+            LY_ARRAY_CREATE_GOTO(ctx, storage->bits_items, items_ordered->count, ret, error);
+            for (u = 0; u < items_ordered->count; u++) {
+                storage->bits_items[u] = items_ordered->objs[u];
+                LY_ARRAY_INCREMENT(storage->bits_items);
+            }
         }
+        ly_set_free(items_ordered, NULL);
     }
 
     if (options & LY_TYPE_OPTS_DYNAMIC) {
@@ -917,38 +864,7 @@
     ly_set_free(items, NULL);
     ly_set_free(items_ordered, NULL);
     free(buf);
-    return ret;
-}
-
-/**
- * @brief Store value of the YANG built-in bits type.
- *
- * Implementation of the ly_type_store_clb.
- */
-static LY_ERR
-ly_type_store_bits(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), int options,
-                   struct lyd_value *value, struct ly_err_item **UNUSED(err), void **priv)
-{
-    LY_ERR ret = LY_SUCCESS;
-    struct ly_set *items = NULL;
-    unsigned int u;
-
-    if (options & LY_TYPE_OPTS_VALIDATE) {
-        /* the value was prepared by ly_type_validate_bits() */
-        items = (struct ly_set *)(*priv);
-        LY_ARRAY_CREATE_GOTO(ctx, value->bits_items, items->count, ret, cleanup);
-        for (u = 0; u < items->count; u++) {
-            value->bits_items[u] = items->objs[u];
-            LY_ARRAY_INCREMENT(value->bits_items);
-        }
-    } else {
-        /* TODO if there is usecase for store without validate */
-        LOGINT(NULL);
-        return LY_EINT;
-    }
-
-cleanup:
-    ly_set_free(items, NULL);
+    lydict_remove(ctx, can);
     return ret;
 }
 
@@ -958,23 +874,25 @@
  * Implementation of the ly_type_free_clb.
  */
 static void
-ly_type_free_bits(struct ly_ctx *UNUSED(ctx), struct lysc_type *UNUSED(type), struct lyd_value *value)
+ly_type_free_bits(struct ly_ctx *ctx, struct lysc_type *type, struct lyd_value *value)
 {
     LY_ARRAY_FREE(value->bits_items);
     value->bits_items = NULL;
+
+    ly_type_free_canonical(ctx, type, value);
 }
 
 
 /**
- * @brief Validate and canonize value of the YANG built-in enumeration type.
+ * @brief Validate, canonize and store value of the YANG built-in enumeration type.
  *
- * Implementation of the ly_type_validate_clb.
+ * Implementation of the ly_type_store_clb.
  */
 static LY_ERR
-ly_type_validate_enum(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
-                      ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                      const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
-                      const char **canonized, struct ly_err_item **err, void **priv)
+ly_type_store_enum(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+                   ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+                   const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+                   struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     unsigned int u, v;
     char *errmsg = NULL;
@@ -1002,18 +920,18 @@
 
 match:
     /* validation done */
-    if (options & LY_TYPE_OPTS_CANONIZE) {
+
+    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
         if (options & LY_TYPE_OPTS_DYNAMIC) {
-            *canonized = lydict_insert_zc(ctx, (char*)value);
+            ly_type_store_canonized(ctx, options, lydict_insert_zc(ctx, (char*)value), storage, canonized);
             value = NULL;
         } else {
-            *canonized = lydict_insert(ctx, value_len ? value : "", value_len);
+            ly_type_store_canonized(ctx, options, lydict_insert(ctx, value_len ? value : "", value_len), storage, canonized);
         }
     }
 
     if (options & LY_TYPE_OPTS_STORE) {
-        /* remember the enum definition to store */
-        *priv = &type_enum->enums[u];
+        storage->enum_item = &type_enum->enums[u];
     }
 
     if (options & LY_TYPE_OPTS_DYNAMIC) {
@@ -1030,36 +948,15 @@
 }
 
 /**
- * @brief Store value of the YANG built-in enumeration type.
+ * @brief Validate and store value of the YANG built-in boolean type.
  *
  * Implementation of the ly_type_store_clb.
  */
 static LY_ERR
-ly_type_store_enum(struct ly_ctx *UNUSED(ctx), struct lysc_type *UNUSED(type), int options,
-                   struct lyd_value *value, struct ly_err_item **UNUSED(err), void **priv)
-{
-    if (options & LY_TYPE_OPTS_VALIDATE) {
-        /* the value was prepared by ly_type_validate_enum() */
-        value->enum_item = *priv;
-    } else {
-        /* TODO if there is usecase for store without validate */
-        LOGINT(NULL);
-        return LY_EINT;
-    }
-
-    return LY_SUCCESS;
-}
-
-/**
- * @brief Validate value of the YANG built-in boolean type.
- *
- * Implementation of the ly_type_validate_clb.
- */
-static LY_ERR
-ly_type_validate_boolean(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
-                         ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                         const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
-                         const char **canonized, struct ly_err_item **err, void **priv)
+ly_type_store_boolean(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
+                      ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+                      const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+                      struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     int8_t i;
 
@@ -1074,22 +971,17 @@
         return LY_EVALID;
     }
 
-    if (options & LY_TYPE_OPTS_CANONIZE) {
-        if (i) {
-            *canonized = lydict_insert(ctx, "true", 4);
+    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
+        if (options & LY_TYPE_OPTS_DYNAMIC) {
+            ly_type_store_canonized(ctx, options, lydict_insert_zc(ctx, (char*)value), storage, canonized);
+            value = NULL;
         } else {
-            *canonized = lydict_insert(ctx, "false", 5);
+            ly_type_store_canonized(ctx, options, lydict_insert(ctx, value, value_len), storage, canonized);
         }
     }
 
     if (options & LY_TYPE_OPTS_STORE) {
-        /* save for the store callback */
-        *priv = malloc(sizeof i);
-        if (!(*priv)) {
-            *err = ly_err_new(LY_LLERR, LY_EMEM, 0, "Memory allocation failed.", NULL, NULL);
-            return LY_EMEM;
-        }
-        *(int8_t*)(*priv) = i;
+        storage->boolean = i;
     }
 
     if (options & LY_TYPE_OPTS_DYNAMIC) {
@@ -1100,37 +992,15 @@
 }
 
 /**
- * @brief Store value of the YANG built-in boolean type.
+ * @brief Validate and store value of the YANG built-in empty type.
  *
  * Implementation of the ly_type_store_clb.
  */
 static LY_ERR
-ly_type_store_boolean(struct ly_ctx *UNUSED(ctx), struct lysc_type *UNUSED(type), int options,
-                   struct lyd_value *value, struct ly_err_item **UNUSED(err), void **priv)
-{
-    if (options & LY_TYPE_OPTS_VALIDATE) {
-        /* the value was prepared by ly_type_validate_enum() */
-        value->boolean = *(int8_t*)(*priv);
-        free(*priv);
-    } else {
-        /* TODO if there is usecase for store without validate */
-        LOGINT(NULL);
-        return LY_EINT;
-    }
-
-    return LY_SUCCESS;
-}
-
-/**
- * @brief Validate value of the YANG built-in empty type.
- *
- * Implementation of the ly_type_validate_clb.
- */
-static LY_ERR
-ly_type_validate_empty(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
-                       ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
-                       const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
-                       const char **canonized, struct ly_err_item **err, void **UNUSED(priv))
+ly_type_store_empty(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), const char *value, size_t value_len, int options,
+                    ly_clb_resolve_prefix UNUSED(get_prefix), void *UNUSED(parser), LYD_FORMAT UNUSED(format),
+                    const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+                    struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     if (value_len) {
         char *errmsg;
@@ -1139,9 +1009,10 @@
         return LY_EVALID;
     }
 
-    if (options & LY_TYPE_OPTS_CANONIZE) {
-        *canonized = lydict_insert(ctx, "", 0);
+    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
+        ly_type_store_canonized(ctx, options, lydict_insert(ctx, "", 0), storage, canonized);
     }
+
     return LY_SUCCESS;
 }
 
@@ -1174,15 +1045,15 @@
 }
 
 /**
- * @brief Validate value of the YANG built-in identiytref type.
+ * @brief Validate, canonize and store value of the YANG built-in identiytref type.
  *
- * Implementation of the ly_type_validate_clb.
+ * Implementation of the ly_type_store_clb.
  */
 static LY_ERR
-ly_type_validate_identityref(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
-                             ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT UNUSED(format),
-                             const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
-                             const char **canonized, struct ly_err_item **err, void **priv)
+ly_type_store_identityref(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+                          ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT UNUSED(format),
+                          const void *UNUSED(context_node), struct lyd_node **UNUSED(trees),
+                          struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     struct lysc_type_identityref *type_ident = (struct lysc_type_identityref *)type;
     const char *id_name, *prefix = value;
@@ -1239,17 +1110,17 @@
         goto error;
     }
 
-    if (options & LY_TYPE_OPTS_CANONIZE) {
+    if (options & (LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE)) {
         if (id_name == value && (options & LY_TYPE_OPTS_DYNAMIC)) {
-            *canonized = lydict_insert_zc(ctx, (char*)value);
+            ly_type_store_canonized(ctx, options, lydict_insert_zc(ctx, (char*)value), storage, canonized);
             value = NULL;
         } else {
-            *canonized = lydict_insert(ctx, id_name, id_len);
+            ly_type_store_canonized(ctx, options, lydict_insert(ctx, id_name, id_len), storage, canonized);
         }
     }
 
     if (options & LY_TYPE_OPTS_STORE) {
-        *priv = ident;
+        storage->ident = ident;
     }
 
     if (options & LY_TYPE_OPTS_DYNAMIC) {
@@ -1264,27 +1135,6 @@
 }
 
 /**
- * @brief Store value of the YANG built-in identityref type.
- *
- * Implementation of the ly_type_store_clb.
- */
-static LY_ERR
-ly_type_store_identityref(struct ly_ctx *UNUSED(ctx), struct lysc_type *UNUSED(type), int options,
-                          struct lyd_value *value, struct ly_err_item **UNUSED(err), void **priv)
-{
-    if (options & LY_TYPE_OPTS_VALIDATE) {
-        /* the value was prepared by ly_type_validate_enum() */
-        value->ident = *priv;
-    } else {
-        /* TODO if there is usecase for store without validate */
-        LOGINT(NULL);
-        return LY_EINT;
-    }
-
-    return LY_SUCCESS;
-}
-
-/**
  * @brief Comparison callback for built-in identityref type.
  *
  * Implementation of the ly_type_compare_clb.
@@ -1299,7 +1149,7 @@
 }
 
 /**
- * @brief Helper function for ly_type_validate_instanceid() to check presence of the specific node in the (data/schema) tree.
+ * @brief Helper function for ly_type_store_instanceid() to check presence of the specific node in the (data/schema) tree.
  *
  * In the case the instance-identifier type does not require instance (@p require_instance is 0) or the data @p trees
  * are not complete (called in the middle of data parsing), the @p token is checked only to match schema tree.
@@ -1326,10 +1176,10 @@
  * @return LY_EMEM or LY_EVALID in case of failure or when the node is not present in the schema/data tree.
  */
 static LY_ERR
-ly_type_validate_instanceid_checknodeid(const char *orig, size_t orig_len, int options, int require_instance,
-                                        const char **token, struct lyd_value_prefix *prefixes, LYD_FORMAT format,
-                                        const struct lysc_node **node_s, const struct lyd_node **node_d,
-                                        struct lyd_node **trees, char **errmsg)
+ly_type_store_instanceid_checknodeid(const char *orig, size_t orig_len, int options, int require_instance,
+                                     const char **token, struct lyd_value_prefix *prefixes, LYD_FORMAT format,
+                                     const struct lysc_node **node_s, const struct lyd_node **node_d,
+                                     struct lyd_node **trees, char **errmsg)
 {
     const char *id, *prefix;
     size_t id_len, prefix_len;
@@ -1409,13 +1259,13 @@
 }
 
 /**
- * @brief Helper function for ly_type_validate_instanceid_parse_predicate_value() to provide prefix mapping for the
+ * @brief Helper function for ly_type_store_instanceid_parse_predicate_value() to provide prefix mapping for the
  * validation callbacks for the values used in instance-identifier predicates.
  *
  * Implementation of the ly_clb_resolve_prefix.
  */
 static const struct lys_module *
-ly_type_validate_instanceid_get_prefix(struct ly_ctx *UNUSED(ctx), const char *prefix, size_t prefix_len, void *private)
+ly_type_store_instanceid_get_prefix(struct ly_ctx *UNUSED(ctx), const char *prefix, size_t prefix_len, void *private)
 {
     struct lyd_value_prefix *prefixes = (struct lyd_value_prefix*)private;
     unsigned int u;
@@ -1429,7 +1279,7 @@
 }
 
 /**
- * @brief Helper function for ly_type_validate_instanceid() to prepare predicate's value structure into the lyd_value_path structure.
+ * @brief Helper function for ly_type_store_instanceid() to prepare predicate's value structure into the lyd_value_path structure.
  *
  * @param[in] ctx libyang context.
  * @param[in] key Schema key node of the predicate (list's key in case of key-predicate, leaf-list in case of leaf-list-predicate).
@@ -1442,53 +1292,33 @@
  * @return LY_ERR value.
  */
 static LY_ERR
-ly_type_validate_instanceid_parse_predicate_value(struct ly_ctx *ctx, const struct lysc_node *key, const char *val, size_t val_len,
-                                                  struct lyd_value_prefix *prefixes, LYD_FORMAT format,
-                                                  struct lyd_value_path_predicate *pred, char **errmsg)
+ly_type_store_instanceid_parse_predicate_value(struct ly_ctx *ctx, const struct lysc_node *key, const char *val, size_t val_len,
+                                               struct lyd_value_prefix *prefixes, LYD_FORMAT format,
+                                               struct lyd_value_path_predicate *pred, char **errmsg)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lysc_type *type;
     struct ly_err_item *err = NULL;
-    void *priv = NULL;
-    int options = LY_TYPE_OPTS_VALIDATE | LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE | LY_TYPE_OPTS_INCOMPLETE_DATA;
+    int options = LY_TYPE_OPTS_STORE | LY_TYPE_OPTS_INCOMPLETE_DATA;
 
     pred->value = calloc(1, sizeof *pred->value);
 
     type = ((struct lysc_node_leaf*)key)->type;
-    if (type->plugin->validate) {
-        ret = type->plugin->validate(ctx, type, val, val_len, options,
-                                    ly_type_validate_instanceid_get_prefix, prefixes, format, key, NULL,
-                                    &pred->value->canonized, &err, &priv);
-        if (ret == LY_EINCOMPLETE) {
-            /* actually expected success without complete data */
-            ret = LY_SUCCESS;
-        } else if (ret) {
-            if (err) {
-                *errmsg = err->msg;
-                err->msg = NULL;
-                ly_err_free(err);
-            } else {
-                *errmsg = strdup("Type validation failed with unknown error.");
-            }
-            goto error;
-        }
-    } else {
-        pred->value->canonized = lydict_insert(ctx, val, val_len);
-    }
     pred->value->plugin = type->plugin;
-
-    if (type->plugin->store) {
-        ret = type->plugin->store(ctx, type, options, pred->value, &err, &priv);
-        if (ret) {
-            if (err) {
-                *errmsg = err->msg;
-                err->msg = NULL;
-                ly_err_free(err);
-            } else {
-                *errmsg = strdup("Data storing failed with unknown error.");
-            }
-            goto error;
+    ret = type->plugin->store(ctx, type, val, val_len, options, ly_type_store_instanceid_get_prefix, prefixes, format, key, NULL,
+                              pred->value, NULL, &err);
+    if (ret == LY_EINCOMPLETE) {
+        /* actually expected success without complete data */
+        ret = LY_SUCCESS;
+    } else if (ret) {
+        if (err) {
+            *errmsg = err->msg;
+            err->msg = NULL;
+            ly_err_free(err);
+        } else {
+            *errmsg = strdup("Type validation failed with unknown error.");
         }
+        goto error;
     }
 
 error:
@@ -1496,13 +1326,13 @@
 }
 
 /**
- * @brief Helper function for ly_type_validate_instanceid() to correctly find the end of the predicate section.
+ * @brief Helper function for ly_type_store_instanceid() to correctly find the end of the predicate section.
  *
  * @param[in] predicate Start of the beginning section.
  * @return Pointer to the end of the predicate section.
  */
 static const char *
-ly_type_validate_instanceid_predicate_end(const char *predicate)
+ly_type_store_instanceid_predicate_end(const char *predicate)
 {
     size_t i = 0;
     while (predicate[i] != ']') {
@@ -1528,15 +1358,15 @@
 }
 
 /**
- * @brief Validate value of the YANG built-in instance-identifier type.
+ * @brief Validate and store value of the YANG built-in instance-identifier type.
  *
- * Implementation of the ly_type_validate_clb.
+ * Implementation of the ly_type_store_clb.
  */
 static LY_ERR
-ly_type_validate_instanceid(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
-                             ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
-                             const void *context_node, struct lyd_node **trees,
-                             const char **canonized, struct ly_err_item **err, void **priv)
+ly_type_store_instanceid(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+                         ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
+                         const void *context_node, struct lyd_node **trees,
+                         struct lyd_value *storage, const char **canonized, struct ly_err_item **err)
 {
     LY_ERR ret = LY_EVALID;
     struct lysc_type_instanceid *type_inst = (struct lysc_type_instanceid *)type;
@@ -1565,7 +1395,6 @@
                      "TODO");
             goto error;
         }
-        *priv = ((struct lyd_node_term*)context_node)->value.target;
         return LY_SUCCESS;
     } else {
         /* first run without prepared target, we will need all the prefixes used in the instance-identifier value */
@@ -1591,7 +1420,7 @@
             ly_set_clean(&predicates, NULL);
 
             token++;
-            if (ly_type_validate_instanceid_checknodeid(value, value_len, options, type_inst->require_instance,
+            if (ly_type_store_instanceid_checknodeid(value, value_len, options, type_inst->require_instance,
                                                         &token, prefixes, format, &node_s, &node_d, trees, &errmsg)) {
                 goto error;
             }
@@ -1603,7 +1432,7 @@
                 /* predicate follows, this must be a list or leaf-list */
                 if (node_s->nodetype != LYS_LIST && node_s->nodetype != LYS_LEAFLIST) {
                     asprintf(&errmsg, "Invalid instance-identifier \"%.*s\" value - predicate \"%.*s\" for %s is not accepted.",
-                             (int)value_len, value, (int)(ly_type_validate_instanceid_predicate_end(token) - token) + 1, token,
+                             (int)value_len, value, (int)(ly_type_store_instanceid_predicate_end(token) - token) + 1, token,
                              lys_nodetype2str(node_s->nodetype));
                     goto error;
                 }
@@ -1645,7 +1474,7 @@
                 }
 
                 /* resolve the key in predicate */
-                if (ly_type_validate_instanceid_checknodeid(value, value_len, options, type_inst->require_instance,
+                if (ly_type_store_instanceid_checknodeid(value, value_len, options, type_inst->require_instance,
                                                             &t, prefixes, format, &key_s, &key_d, trees, &errmsg)) {
                     goto error;
                 }
@@ -1671,7 +1500,7 @@
                         node_d = lyd_search(node_d->next, node_s->module, node_s->name, strlen(node_s->name), LYS_LIST, NULL, 0);
                         if (node_d) {
                             key_d = node_d;
-                            if (ly_type_validate_instanceid_checknodeid(value, value_len, options, type_inst->require_instance,
+                            if (ly_type_store_instanceid_checknodeid(value, value_len, options, type_inst->require_instance,
                                                                         &t, prefixes, format, &key_s, &key_d, trees, &errmsg)) {
                                 goto error;
                             }
@@ -1695,7 +1524,7 @@
                     /* update target path structure by adding predicate info */
                     pred->type = 1;
                     pred->key = key_s;
-                    LY_CHECK_GOTO(ly_type_validate_instanceid_parse_predicate_value(ctx, key_s, val, val_len, prefixes, format, pred, &errmsg), error);
+                    LY_CHECK_GOTO(ly_type_store_instanceid_parse_predicate_value(ctx, key_s, val, val_len, prefixes, format, pred, &errmsg), error);
                 }
                 i = predicates.count;
                 if (i != ly_set_add(&predicates, (void*)key_s, 0)) {
@@ -1756,7 +1585,7 @@
                     /* update target path structure by adding predicate info */
                     pred->type = 2;
                     pred->key = node_s;
-                    LY_CHECK_GOTO(ly_type_validate_instanceid_parse_predicate_value(ctx, node_s, val, val_len, prefixes, format, pred, &errmsg), error);
+                    LY_CHECK_GOTO(ly_type_store_instanceid_parse_predicate_value(ctx, node_s, val, val_len, prefixes, format, pred, &errmsg), error);
                 }
                 ly_set_add(&predicates, (void*)node_s, 0);
             } else {
@@ -1822,7 +1651,7 @@
         }
     }
 
-    if ((options & LY_TYPE_OPTS_CANONIZE) && !(*canonized)) {
+    if (options & LY_TYPE_OPTS_CANONIZE) {
         /* instance-identifier does not have a canonical form (lexical representation in in XML and JSON are
          * even different) - to make it clear, the canonized form is represented as NULL to make the caller
          * print it always via callback printer */
@@ -1830,11 +1659,11 @@
     }
 
     if (options & LY_TYPE_OPTS_STORE) {
-        *priv = target;
-    } else {
-        lyd_value_free_path(ctx, target);
+        storage->target = target;
+        storage->canonized = NULL;
     }
 
+    /* cleanup */
     LY_ARRAY_FOR(prefixes, u) {
         lydict_remove(ctx, prefixes[u].prefix);
     }
@@ -1866,28 +1695,6 @@
     return ret;
 }
 
-
-/**
- * @brief Store value of the YANG built-in instance-identifier type.
- *
- * Implementation of the ly_type_store_clb.
- */
-static LY_ERR
-ly_type_store_instanceid(struct ly_ctx *UNUSED(ctx), struct lysc_type *UNUSED(type), int options,
-                         struct lyd_value *value, struct ly_err_item **UNUSED(err), void **priv)
-{
-    if (options & LY_TYPE_OPTS_VALIDATE) {
-        /* the value was prepared by ly_type_validate_enum() */
-        value->target = *priv;
-    } else {
-        /* TODO if there is usecase for store without validate */
-        LOGINT(NULL);
-        return LY_EINT;
-    }
-
-    return LY_SUCCESS;
-}
-
 /**
  * @brief Comparison callback checking the instance-identifier value.
  *
@@ -1939,52 +1746,39 @@
 }
 
 /**
- * @brief Free value of the YANG built-in instance-identifier type.
+ * @brief Free value of the YANG built-in instance-identifier types.
  *
  * Implementation of the ly_type_free_clb.
  */
 static void
-ly_type_free_instanceid(struct ly_ctx *ctx, struct lysc_type *UNUSED(type), struct lyd_value *value)
+ly_type_free_instanceid(struct ly_ctx *ctx, struct lysc_type *type, struct lyd_value *value)
 {
     lyd_value_free_path(ctx, value->target);
     value->target = NULL;
-}
 
-/**
- * @brief Generic comparison callback checking the canonical value.
- *
- * Implementation of the ly_type_compare_clb.
- */
-static LY_ERR
-ly_type_compare_canonical(const struct lyd_value *val1, const struct lyd_value *val2)
-{
-    if (val1 == val2 || !strcmp(val1->canonized, val2->canonized)) {
-        return LY_SUCCESS;
-    }
-
-    return LY_EVALID;
+    ly_type_free_canonical(ctx, type, value);
 }
 
 struct lysc_type_plugin ly_builtin_type_plugins[LY_DATA_TYPE_COUNT] = {
     {0}, /* LY_TYPE_UNKNOWN */
-    {.type = LY_TYPE_BINARY, .validate = ly_type_validate_binary, .store = NULL, .compare = ly_type_compare_canonical, .free = NULL},
-    {.type = LY_TYPE_UINT8, .validate = ly_type_validate_uint, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .free = NULL},
-    {.type = LY_TYPE_UINT16, .validate = ly_type_validate_uint, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .free = NULL},
-    {.type = LY_TYPE_UINT32, .validate = ly_type_validate_uint, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .free = NULL},
-    {.type = LY_TYPE_UINT64, .validate = ly_type_validate_uint, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .free = NULL},
-    {.type = LY_TYPE_STRING, .validate = ly_type_validate_string, .store = NULL, .compare = ly_type_compare_canonical, .free = NULL},
-    {.type = LY_TYPE_BITS, .validate = ly_type_validate_bits, .store = ly_type_store_bits, .compare = ly_type_compare_canonical, .free = ly_type_free_bits},
-    {.type = LY_TYPE_BOOL, .validate = ly_type_validate_boolean, .store = ly_type_store_boolean, .compare = ly_type_compare_canonical, .free = NULL},
-    {.type = LY_TYPE_DEC64, .validate = ly_type_validate_decimal64, .store = ly_type_store_decimal64, .compare = ly_type_compare_canonical, .free = NULL},
-    {.type = LY_TYPE_EMPTY, .validate = ly_type_validate_empty, .store = NULL, .compare = ly_type_compare_empty, .free = NULL},
-    {.type = LY_TYPE_ENUM, .validate = ly_type_validate_enum, .store = ly_type_store_enum, .compare = ly_type_compare_canonical, .free = NULL},
-    {.type = LY_TYPE_IDENT, .validate = ly_type_validate_identityref, .store = ly_type_store_identityref, .compare = ly_type_compare_identityref, .free = NULL},
-    {.type = LY_TYPE_INST, .validate = ly_type_validate_instanceid, .store = ly_type_store_instanceid, .compare = ly_type_compare_instanceid, .free = ly_type_free_instanceid},
+    {.type = LY_TYPE_BINARY, .store = ly_type_store_binary, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
+    {.type = LY_TYPE_UINT8, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
+    {.type = LY_TYPE_UINT16, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
+    {.type = LY_TYPE_UINT32, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
+    {.type = LY_TYPE_UINT64, .store = ly_type_store_uint, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
+    {.type = LY_TYPE_STRING, .store = ly_type_store_string, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
+    {.type = LY_TYPE_BITS, .store = ly_type_store_bits, .compare = ly_type_compare_canonical, .free = ly_type_free_bits},
+    {.type = LY_TYPE_BOOL, .store = ly_type_store_boolean, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
+    {.type = LY_TYPE_DEC64, .store = ly_type_store_decimal64, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
+    {.type = LY_TYPE_EMPTY, .store = ly_type_store_empty, .compare = ly_type_compare_empty, .free = ly_type_free_canonical},
+    {.type = LY_TYPE_ENUM, .store = ly_type_store_enum, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
+    {.type = LY_TYPE_IDENT, .store = ly_type_store_identityref, .compare = ly_type_compare_identityref, .free = ly_type_free_canonical},
+    {.type = LY_TYPE_INST, .store = ly_type_store_instanceid, .compare = ly_type_compare_instanceid, .free = ly_type_free_instanceid},
     {0}, /* TODO LY_TYPE_LEAFREF */
     {0}, /* TODO LY_TYPE_UNION */
-    {.type = LY_TYPE_INT8, .validate = ly_type_validate_int, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = NULL},
-    {.type = LY_TYPE_INT16, .validate = ly_type_validate_int, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = NULL},
-    {.type = LY_TYPE_INT32, .validate = ly_type_validate_int, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = NULL},
-    {.type = LY_TYPE_INT64, .validate = ly_type_validate_int, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = NULL},
+    {.type = LY_TYPE_INT8, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
+    {.type = LY_TYPE_INT16, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
+    {.type = LY_TYPE_INT32, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
+    {.type = LY_TYPE_INT64, .store = ly_type_store_int, .compare = ly_type_compare_canonical, .free = ly_type_free_canonical},
 };
 
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 5556817..d1e5b87 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -52,16 +52,15 @@
  * Options applicable to ly_type_validate_clb() and ly_typestore_clb.
  * @{
  */
-#define LY_TYPE_OPTS_VALIDATE     0x01 /**< Flag announcing calling of ly_type_validate_clb() of the type */
-#define LY_TYPE_OPTS_CANONIZE     0x02 /**< Canonize the given value and store it (insert into the context's dictionary)
+#define LY_TYPE_OPTS_CANONIZE     0x01 /**< Canonize the given value and store it (insert into the context's dictionary)
                                             as the value's canonized string */
-#define LY_TYPE_OPTS_DYNAMIC      0x04 /**< Flag for the dynamically allocated string value, in this case the value is supposed to be freed
+#define LY_TYPE_OPTS_DYNAMIC      0x02 /**< Flag for the dynamically allocated string value, in this case the value is supposed to be freed
                                             or directly inserted into the context's dictionary (e.g. in case of canonization).
                                             In any case, the caller of the callback does not free the provided string value after calling
                                             the type's callbacks with this option */
-#define LY_TYPE_OPTS_STORE        0x08 /**< Flag announcing calling of ly_type_store_clb() */
-#define LY_TYPE_OPTS_SCHEMA       0x10 /**< Flag for the value used in schema instead of the data tree */
-#define LY_TYPE_OPTS_INCOMPLETE_DATA 0x20 /**< Flag for the case the data trees are not yet complete. In this case the plagin should do what it
+#define LY_TYPE_OPTS_STORE        0x04 /**< Flag announcing calling of ly_type_store_clb() */
+#define LY_TYPE_OPTS_SCHEMA       0x08 /**< Flag for the value used in schema instead of the data tree */
+#define LY_TYPE_OPTS_INCOMPLETE_DATA 0x10 /**< Flag for the case the data trees are not yet complete. In this case the plagin should do what it
                                             can (e.g. store the canonical/auxiliary value if it is requested) and in the case of need to use
                                             data trees (checking require-instance), it returns LY_EINCOMPLETE.
                                             Caller is supposed to call such validation callback again later with complete data trees. */
@@ -82,7 +81,7 @@
  */
 
 /**
- * @brief Callback to validate the given @p value according to the given @p type. Optionaly, it can be requested to canonize the value.
+ * @brief Callback to validate, canonize and store (optionally, according to the given @p options) the given @p value according to the given @p type.
  *
  * Note that the \p value string is not necessarily zero-terminated. The provided \p value_len is always correct.
  *
@@ -101,34 +100,22 @@
  * @param[in] trees ([Sized array](@ref sizedarrays)) of external data trees (e.g. when validating RPC/Notification) where the required data
  *            instance can be placed.
  *
- * @param[out] canonized If LY_TYPE_VALIDATE_CANONIZE option set, the canonized string stored in the @p ctx dictionary is returned via this parameter.
+ * @param[in,out] storage If LY_TYPE_OPTS_STORE option set, the parsed data are stored into this structure in the type's specific way.
+ *             If the @p canonized differs from the storage's canonized member, the canonized value is also stored here despite the
+ *             LY_TYPE_OPTS_CANONIZE option.
+ * @param[out] canonized If LY_TYPE_OPTS_CANONIZE option set, the canonized string stored in the @p ctx dictionary is returned via this parameter.
+ *             This is usable mainly in the case the LY_TYPE_OPTS_STORE option is not set and the canonized value is needed outside the lyd_value
+ *             structure, otherwise the canonized value is stored in the @p storage automatically.
  * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic error message is prepared instead.
  * The error structure can be created by ly_err_new().
- * @param[out] priv Type's private data passed between all the callbacks. The last callback is supposed to free the data allocated beforehand.
  * @return LY_SUCCESS on success
  * @return LY_EINCOMPLETE in case the option included LY_TYPE_OPTS_INCOMPLETE_DATA flag and the data @p trees are needed to finish the validation.
  * @return LY_ERR value if an error occurred and the value could not be canonized following the type's rules.
  */
-typedef LY_ERR (*ly_type_validate_clb)(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
-                                       ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
-                                       const void *context_node, struct lyd_node **trees,
-                                       const char **canonized, struct ly_err_item **err, void **priv);
-
-/**
- * @brief Callback for storing user type values.
- *
- * @param[in] ctx libyang ctx to enable correct manipulation with values that are in the dictionary.
- * @param[in] type Type of the value being stored.
- * @param[in] options [Type plugin options ](@ref plugintypeopts).
- * @param[in,out] value Value structure to store the data in the type's specific way. The structure already contains canonized value string to be processed.
- * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic error message is prepared instead.
- * The error structure can be created by ly_err_new().
- * @param[out] priv Type's private data passed between all the callbacks. The last callback is supposed to free the data allocated beforehand.
- * @return LY_SUCCESS on success
- * @return LY_ERR value if an error occurred and the value could not be stored for any reason.
- */
-typedef LY_ERR (*ly_type_store_clb)(struct ly_ctx *ctx, struct lysc_type *type, int options,
-                                    struct lyd_value *value, struct ly_err_item **err, void **priv);
+typedef LY_ERR (*ly_type_store_clb)(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+                                    ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format,
+                                    const void *context_node, struct lyd_node **trees,
+                                    struct lyd_value *storage, const char **canonized, struct ly_err_item **err);
 
 /**
  * @brief Callback for comparing 2 values of the same type.
@@ -145,6 +132,7 @@
 /**
  * @brief Callback for freeing the user type values stored by ly_type_store_clb().
  *
+ * Note that this callback is responsible also for freeing the canonized member in the @p value.
  *
  * @param[in] ctx libyang ctx to enable correct manipulation with values that are in the dictionary.
  * @param[in] type Type of the stored value.
@@ -161,8 +149,7 @@
  */
 struct lysc_type_plugin {
     LY_DATA_TYPE type;               /**< implemented type, use LY_TYPE_UNKNOWN for derived data types */
-    ly_type_validate_clb validate;   /**< function to validate and canonize given value */
-    ly_type_store_clb store;         /**< function to store the value in the type-specific way */
+    ly_type_store_clb store;         /**< function to validate, canonize and store (according to the options) the value in the type-specific way */
     ly_type_compare_clb compare;     /**< comparison callback to compare 2 values of the same type */
     ly_type_free_clb free;           /**< optional function to free the type-spceific way stored value */
     uint32_t flags;                  /**< [type flags ](@ref plugintypeflags). */
diff --git a/src/tree_data.c b/src/tree_data.c
index 02059b9..c186930 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -96,47 +96,27 @@
     struct ly_err_item *err = NULL;
     struct ly_ctx *ctx;
     struct lysc_type *type;
-    void *priv = NULL;
-    int options = LY_TYPE_OPTS_VALIDATE | LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE |
-            (dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
+    int options = LY_TYPE_OPTS_STORE | (dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
     assert(node);
 
     ctx = node->schema->module->ctx;
-    type = ((struct lysc_node_leaf*)node->schema)->type;
-    if (type->plugin->validate) {
-        rc = type->plugin->validate(ctx, type, value, value_len, options, get_prefix, parser, format,
-                                    trees ? (void*)node : (void*)node->schema, trees,
-                                    &node->value.canonized, &err, &priv);
-        if (rc == LY_EINCOMPLETE) {
-            ret = rc;
-            /* continue with storing, just remember what to return if storing is ok */
-        } else if (rc) {
-            ret = rc;
-            if (err) {
-                ly_err_print(err);
-                LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
-                ly_err_free(err);
-            }
-            goto error;
-        }
-    } else if (dynamic) {
-        node->value.canonized = lydict_insert_zc(ctx, (char*)value);
-    } else {
-        node->value.canonized = lydict_insert(ctx, value, value_len);
-    }
-    node->value.plugin = type->plugin;
 
-    if (type->plugin->store) {
-        rc = type->plugin->store(ctx, type, options, &node->value, &err, &priv);
-        if (rc) {
-            ret = rc;
-            if (err) {
-                ly_err_print(err);
-                LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
-                ly_err_free(err);
-            }
-            goto error;
+    type = ((struct lysc_node_leaf*)node->schema)->type;
+    node->value.plugin = type->plugin;
+    rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format,
+                             trees ? (void*)node : (void*)node->schema, trees,
+                             &node->value, NULL, &err);
+    if (rc == LY_EINCOMPLETE) {
+        ret = rc;
+        /* continue with storing, just remember what to return if storing is ok */
+    } else if (rc) {
+        ret = rc;
+        if (err) {
+            ly_err_print(err);
+            LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
+            ly_err_free(err);
         }
+        goto error;
     }
 
 error:
@@ -150,8 +130,6 @@
     LY_ERR rc = LY_SUCCESS;
     struct ly_err_item *err = NULL;
     struct lysc_type *type;
-    void *priv = NULL;
-    int options = LY_TYPE_OPTS_VALIDATE | LY_TYPE_OPTS_INCOMPLETE_DATA;
 
     LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
 
@@ -161,22 +139,20 @@
     }
 
     type = ((struct lysc_node_leaf*)node)->type;
-
-    if (type->plugin->validate) {
-        rc = type->plugin->validate(ctx ? ctx : node->module->ctx, type, value, value_len, options,
-                                     get_prefix, get_prefix_data, format, node, NULL, NULL, &err, &priv);
-        if (rc == LY_EINCOMPLETE) {
-            /* actually success since we do not provide the context tree and call validation with
-             * LY_TYPE_OPTS_INCOMPLETE_DATA */
-            rc = LY_SUCCESS;
-        } else if (rc && err) {
-            if (ctx) {
-                /* log only in case the ctx was provided as input parameter */
-                ly_err_print(err);
-                LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
-            }
-            ly_err_free(err);
+    /* just validate, no storing of enything */
+    rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, LY_TYPE_OPTS_INCOMPLETE_DATA,
+                             get_prefix, get_prefix_data, format, node, NULL, NULL, NULL, &err);
+    if (rc == LY_EINCOMPLETE) {
+        /* actually success since we do not provide the context tree and call validation with
+         * LY_TYPE_OPTS_INCOMPLETE_DATA */
+        rc = LY_SUCCESS;
+    } else if (rc && err) {
+        if (ctx) {
+            /* log only in case the ctx was provided as input parameter */
+            ly_err_print(err);
+            LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
         }
+        ly_err_free(err);
     }
 
     return rc;
@@ -189,29 +165,25 @@
     LY_ERR rc;
     struct ly_err_item *err = NULL;
     struct lysc_type *type;
-    void *priv = NULL;
-    int options = LY_TYPE_OPTS_VALIDATE | LY_TYPE_OPTS_STORE | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
+    int options = (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
 
     LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
 
     type = ((struct lysc_node_leaf*)node->schema)->type;
-
-    if (type->plugin->validate) {
-        rc = type->plugin->validate(ctx ? ctx : node->schema->module->ctx, type, value, value_len, options,
-                                     get_prefix, get_prefix_data, format, trees ? (void*)node : (void*)node->schema, trees,
-                                     NULL, &err, &priv);
-        if (rc == LY_EINCOMPLETE) {
-            return rc;
-        } else if (rc) {
-            if (err) {
-                if (ctx) {
-                    ly_err_print(err);
-                    LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
-                }
-                ly_err_free(err);
+    rc = type->plugin->store(ctx ? ctx : node->schema->module->ctx, type, value, value_len, options,
+                             get_prefix, get_prefix_data, format, trees ? (void*)node : (void*)node->schema, trees,
+                             NULL, NULL, &err);
+    if (rc == LY_EINCOMPLETE) {
+        return rc;
+    } else if (rc) {
+        if (err) {
+            if (ctx) {
+                ly_err_print(err);
+                LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
             }
-            return rc;
+            ly_err_free(err);
         }
+        return rc;
     }
 
     return LY_SUCCESS;
@@ -225,56 +197,32 @@
     struct ly_err_item *err = NULL;
     struct ly_ctx *ctx;
     struct lysc_type *type;
-    void *priv = NULL;
     struct lyd_value data = {0};
-    int options = LY_TYPE_OPTS_VALIDATE | LY_TYPE_OPTS_CANONIZE | LY_TYPE_OPTS_STORE | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
+    int options = LY_TYPE_OPTS_STORE | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
 
     LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
 
     ctx = node->schema->module->ctx;
     type = ((struct lysc_node_leaf*)node->schema)->type;
-    if (type->plugin->validate) {
-        rc = type->plugin->validate(ctx, type, value, value_len, options,
-                                     get_prefix, get_prefix_data, format, (struct lyd_node*)node, trees,
-                                     &data.canonized, &err, &priv);
-        if (rc == LY_EINCOMPLETE) {
-            ret = rc;
-            /* continue with comparing, just remember what to return if storing is ok */
-        } else if (rc) {
-            /* value to compare is invalid */
-            ret = LY_EINVAL;
-            if (err) {
-                ly_err_free(err);
-            }
-            goto cleanup;
+    rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, get_prefix_data, format, (struct lyd_node*)node,
+                             trees, &data, NULL, &err);
+    if (rc == LY_EINCOMPLETE) {
+        ret = rc;
+        /* continue with comparing, just remember what to return if storing is ok */
+    } else if (rc) {
+        /* value to compare is invalid */
+        ret = LY_EINVAL;
+        if (err) {
+            ly_err_free(err);
         }
-    } else {
-        data.canonized = lydict_insert(ctx, value, value_len);
-    }
-
-    /* store the value to compare into a dummy storage to do a comparison */
-    if (type->plugin->store) {
-        if (type->plugin->store(ctx, type, options, &data, &err, &priv)) {
-            ret = LY_EINVAL;
-            if (err) {
-                ly_err_free(err);
-            }
-            goto cleanup;
-        }
+        goto cleanup;
     }
 
     /* compare data */
-    if (type->plugin->compare) {
-        ret = type->plugin->compare(&node->value, &data);
-    } else if (data.canonized != node->value.canonized) {
-        ret = LY_EVALID;
-    }
+    ret = type->plugin->compare(&node->value, &data);
 
 cleanup:
-    if (type->plugin->free) {
-        type->plugin->free(ctx, type, &data);
-    }
-    lydict_remove(ctx, data.canonized);
+    type->plugin->free(ctx, type, &data);
 
     return ret;
 }
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
index 6e28fdb..36a11a0 100644
--- a/src/tree_data_free.c
+++ b/src/tree_data_free.c
@@ -34,10 +34,7 @@
         LY_ARRAY_FOR(path[u].predicates, v) {
             if (path[u].predicates[v].type > 0) {
                 struct lysc_type *t = ((struct lysc_node_leaf*)path[u].predicates[v].key)->type;
-                if (t->plugin->free) {
-                    t->plugin->free(ctx, t, path[u].predicates[v].value);
-                }
-                lydict_remove(ctx, path[u].predicates[v].value->canonized);
+                t->plugin->free(ctx, t, path[u].predicates[v].value);
                 free(path[u].predicates[v].value);
             }
         }
@@ -94,22 +91,6 @@
     return EXIT_SUCCESS;
 }
 
-/**
- * @brief Free the YANG data value content.
- * @param[in] ctx libyang context
- * @param[in] value Data value structure to clean - since it is mostly part of other structure, only content is freed.
- */
-static void
-lyd_free_value(struct ly_ctx *ctx, struct lyd_value *value, struct lysc_type *type)
-{
-    if (type->plugin->free) {
-        type->plugin->free(ctx, type, value);
-    }
-
-    FREE_STRING(ctx, value->canonized);
-
-}
-
 API void
 lyd_free_attr(struct ly_ctx *ctx, struct lyd_attr *attr, int recursive)
 {
@@ -148,7 +129,7 @@
         iter = iter->next;
 
         FREE_STRING(ctx, attr->name);
-        lyd_free_value(ctx, &attr->value, NULL /* TODO */);
+        /* TODO type->plugin->free(ctx, type, &attr->value); */
         free(attr);
     }
 }
@@ -205,7 +186,8 @@
         }
 #endif
     } else if (node->schema->nodetype & LYD_NODE_TERM) {
-        lyd_free_value(ctx, &((struct lyd_node_term*)node)->value, ((struct lysc_node_leaf*)node->schema)->type);
+        struct lysc_type *type = ((struct lysc_node_leaf*)node->schema)->type;
+        type->plugin->free(ctx, type, &((struct lyd_node_term*)node)->value);
     }
 
     /* free the node's attributes */
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index a2a20b3..644b79a 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -890,6 +890,9 @@
 {
     const struct lys_module *m = NULL;
 
+    if (!prefix) {
+        return (struct lys_module*)mod;
+    }
     if (mod->compiled) {
         FIND_MODULE(struct lysc_import, mod->compiled);
     } else {