/* * Copyright (C) 2016-2017 Redis Labs * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #ifndef __OBJECT_H__ #define __OBJECT_H__ #include #include #include #include #include #include #include "redismodule.h" #include "rmstrndup.h" // Return code from successful ops #define OBJ_OK 0 // Return code from failed ops #define OBJ_ERR 1 /** * NodeType represents the type of a node in an object. */ typedef enum { N_NULL = 0x1, // used in masks and consistent type checking N_STRING = 0x2, N_NUMBER = 0x4, N_INTEGER = 0x8, N_BOOLEAN = 0x10, N_DICT = 0x20, N_ARRAY = 0x40, N_KEYVAL = 0x80 // N_DATETIME = 0x100 // N_BINARY = 0x200 } NodeType; #define NODE_IS_SCALAR(n) (!n ? 1 : (int)(n->type & (N_STRING | N_NUMBER | N_INTEGER | N_BOOLEAN))) struct t_node; /* * Internal representation of a string with data and length */ typedef struct { const char *data; uint32_t len; } t_string; /* * Internal representation of an array, that has a length and capacity */ typedef struct { struct t_node **entries; uint32_t len; uint32_t cap; } t_array; /* * Internal representation of a key-value pair in an object. * The key is a NULL terminated C-string, the value is another node */ typedef struct { const char *key; struct t_node *val; } t_keyval; /* * Internal representation of a dictionary node. * Currently implemented as a list of key-value pairs, will be converted * to a hash-table on big objects in the future */ typedef struct { struct t_node **entries; uint32_t len; uint32_t cap; } t_dict; /* * A node in an object can be any one of the types we support. * Basically an object is just a treee of nodes that can have children * if they are of type dict or array. */ typedef struct t_node { // the actual value of the node union { int boolval; double numval; int64_t intval; t_string strval; t_array arrval; t_dict dictval; t_keyval kvval; } value; // type specifier NodeType type; } Node; typedef Node Object; /** Create a new boolean node, with 0 as false 1 as true */ Node *NewBoolNode(int val); /** Create a new double node with the given value */ Node *NewDoubleNode(double val); /** Create a new integer node with the given value */ Node *NewIntNode(int64_t val); /** * Create a new string node with the given c-string and its length. * NOTE: The string's value will be copied to a newly allocated string */ Node *NewStringNode(const char *s, uint32_t len); /** * Create a new string node from a NULL terminated c-string. #ifdef 0 * NOTE: The string's value will be copied to a newly allocated string */ Node *NewCStringNode(const char *su); /** * Create a new keyval node from a C-string and its length as key and a pointer * to a Node as value. * NOTE: The string's value will be copied to a newly allocated string */ Node *NewKeyValNode(const char *key, uint32_t len, Node *n); /** Create a new zero length array node with the given capacity */ Node *NewArrayNode(uint32_t cap); /** Create a new dict node with the given capacity */ Node *NewDictNode(uint32_t cap); /** Free a node, and if needed free its allocated data and its children recursively */ void Node_Free(Node *n); /** Reports the length of the node's value if defined. Return a positive integer, and -1 otherwise. */ int Node_Length(const Node *n); /** Pretty-print a node. Not JSON compliant but will produce something almost JSON-ish */ void Node_Print(Node *n, int depth); /** Concatenates the src string node to the dst string node. */ int Node_StringAppend(Node *dst, Node *src); /** Deletes (and frees) the count of nodes from an array starting at index. */ int Node_ArrayDelRange(Node *arr, const int index, const int count); /** Insert nodes in sub to an array before the node at index. If the index is geq the array's * length the nodes are appended to the end of the array. Negative index values are interpreted as * beginning from the end. A negative index geq to the length is assumed as 0. * NOTE: the sub array is destroyed. */ int Node_ArrayInsert(Node *arr, int index, Node *sub); /** Append a node to an array node. */ int Node_ArrayAppend(Node *arr, Node *n); /** Prepend a node to an array node. */ int Node_ArrayPrepend(Node *arr, Node *n); /** * Set an array's member at a given index to a new node. * If the index is out of range, we will return an error */ int Node_ArraySet(Node *arr, int index, Node *n); /** * Retrieve an array item into Node n's pointer by index * Returns OBJ_ERR if the index is out of range */ int Node_ArrayItem(Node *arr, int index, Node **n); /** Searches for the scalar n in arr between indices the inclusive start index and the exclusive * stop index. Index values can be negative. Out of range errors are treated by rounding the index to * the arrays start/end. An inverse index range will return unfound. * Returns the index of of the value if found, -1 if n is not a scalar or unfound */ int Node_ArrayIndex(Node *arr, Node *n, int start, int stop); /** * Set an item in a dictionary for a given key. * If an existing item is at the key, we replace it and free the old value */ int Node_DictSet(Node *obj, const char *key, Node *n); /** * Set a keyval node in a dictionary. * If an existing node has the same key, we replace it and free the old keyval node */ int Node_DictSetKeyVal(Node *obj, Node *kv); /** * Delete an item from the dict node by key. Returns OBJ_ERR if the key was * not found */ int Node_DictDel(Node *objm, const char *key); /** * Get a dict node item by key, and put it Node val's pointer. * Return OBJ_ERR if the key was not found. Can put NULL into val * if it is a NULL node */ int Node_DictGet(Node *obj, const char *key, Node **val); /* The type signature of visitor callbacks for node trees */ typedef void (*NodeVisitor)(Node *, void *); void __objTraverse(Node *n, NodeVisitor f, void *ctx); void __arrTraverse(Node *n, NodeVisitor f, void *ctx); /** * Traverse a node recursively with a visitor callback. * We will pass the provided ctx to the callback */ void Node_Traverse(Node *n, NodeVisitor f, void *ctx); /* The type signature of serializer callbacks for node trees */ typedef void (*NodeSerializerValue)(Node *, void *); typedef void (*NodeSerializerContainer)(void *); /* The options container for the serializer */ typedef struct { NodeSerializerValue fBegin; // begin node serializer callback NodeSerializerValue fEnd; // end node serializer callback NodeSerializerContainer fDelim; // container node delimiter callback int xBegin, xEnd, xDelim; // node type bitmasks } NodeSerializerOpt; /** * Scan a node without recursion but with callbacks. * We will pass the provided ctx to the callback */ void Node_Serializer(const Node *n, const NodeSerializerOpt *o, void *ctx); #endif