-#ifndef VG_MSG_H
-#define VG_MSG_H
-#include "vg_stdint.h"
-#include "vg_platform.h"
-
+#pragma once
/*
* Example data:
* kvstr "someinfo"
* Creating the data in code:
* -----------------------------------------------------------------------------
* u8 data_buf[512];
- * vg_msg data = {0};
- * data.buf = data_buf;
- * data.max = sizeof(data_buf);
+ * vg_msg data;
+ * vg_msg_init( &data, data_buf, 512 );
+ *
* vg_msg_wkvstr( &data, "kvstr", "someinfo" );
- * vg_msg_wkvint( &data, "kvint", i32 value=200 );
+ * vg_msg_wkvu32( &data, "kvint", 200 );
*
* vg_msg_frame( &data, "person" );
* vg_msg_wkvstr( &data, "name", "jeff" );
* vg_msg_end_frame( &data );
*
* vg_msg_frame( &data, "building" );
- * vg_msg_wkvint( &data, "capacity", i32 value=1000 );
+ * vg_msg_wkvu32( &data, "capacity", 1000 );
* vg_msg_end_frame( &data );
*
* vg_msg_frame( &data, "person" );
*
* // read data_buf and data_len
*
- * vg_msg data = {0};
- * data.buf = data_buf;
- * data.len = data_len;
+ * vg_msg data;
+ * vg_msg_init( &data, data_buf, data_len );
+ *
+ *
+ * Reading data
+ * -----------------------------------------------------------------------------
+ *
+ * if( vg_msg_seekframe( &msg, "rows" ) ){
+ * while( vg_msg_seekframe( &msg, NULL ) ){
+ * vg_warn( "%s\n", vg_msg_readkvstr( &msg, "yedo" ) );
+ * vg_msg_skip_frame( &msg );
+ * }
+ * }
*
* Reading back the stream linearly
* -----------------------------------------------------------------------------
* esle if( cmd.code == k_vg_msg_kvstring )
* printf( "string: %s\n", cmd.value._buf );
* }
- *
- * Reading back the stream as frames/nodes. this is obviously slower
- * -----------------------------------------------------------------------------
- *
- * vg_msg person = data
- * while( vg_msg_seekframe( &person, "person", VG_MSG_NEXT ) ){
- * const char *name = vg_msg_seekkvstr(&person, "name", VG_MSG_NEXT);
- * const char *country = vg_msg_seekkvstr(&person, "country", VG_MSG_FIRST);
- *
- * printf( "Guy '%s' is from '%s'\n", name, country );
- * vg_msg_skip_frame(&person);
- * }
- *
- * vg_msg building = root;
- * if( vg_msg_seekframe( &building, "building", VG_MSG_FIRST ) ){
- * vg_msg_cmd capacity = vg_msg_seekkv(&building, "capacity", VG_MSG_FIRST);
- * if( capacity.code & k_vg_msg_signed )
- * print( "building capacity: %d\n", capacity.value._i32 );
- *
- * vg_msg_skip_frame( &building );
- * }
- *
*/
enum vg_msg_code{
/* masks */
k_vg_msg_array_count_bits = 0x3C,
- k_vg_msg_size_bits = 0x03,
- k_vg_msg_sized_type_bits = 0xC0,
+ k_vg_msg_type_size_bits = 0x03,
+ k_vg_msg_type_base_bits = 0xC0,
+ k_vg_msg_type_bits = k_vg_msg_type_base_bits|k_vg_msg_type_size_bits,
- /* helpers */
+ /* sizes */
k_vg_msg_8b = 0x00,
k_vg_msg_16b = 0x01,
k_vg_msg_32b = 0x02,
- k_vg_msg_64b = 0x04,
+ k_vg_msg_64b = 0x03,
+
+ /* common types */
+ k_vg_msg_u8 = k_vg_msg_unsigned|k_vg_msg_8b,
+ k_vg_msg_u16 = k_vg_msg_unsigned|k_vg_msg_16b,
+ k_vg_msg_u32 = k_vg_msg_unsigned|k_vg_msg_32b,
+ k_vg_msg_u64 = k_vg_msg_unsigned|k_vg_msg_64b,
+ k_vg_msg_i8 = k_vg_msg_signed |k_vg_msg_8b,
+ k_vg_msg_i16 = k_vg_msg_signed |k_vg_msg_16b,
+ k_vg_msg_i32 = k_vg_msg_signed |k_vg_msg_32b,
+ k_vg_msg_i64 = k_vg_msg_signed |k_vg_msg_64b,
+ k_vg_msg_f32 = k_vg_msg_float |k_vg_msg_32b,
+ k_vg_msg_f64 = k_vg_msg_float |k_vg_msg_64b,
+
+ k_vg_msg_v2f = k_vg_msg_float |k_vg_msg_32b | (1<<2),
+ k_vg_msg_v3f = k_vg_msg_float |k_vg_msg_32b | (2<<2),
+ k_vg_msg_v4f = k_vg_msg_float |k_vg_msg_32b | (3<<2)
};
typedef struct vg_msg vg_msg;
typedef struct vg_msg_cmd vg_msg_cmd;
-struct vg_msg{
- u32 cur,len,max;
+typedef struct vg_msg_cursor vg_msg_cursor;
+struct vg_msg
+{
+ u32 max;
u8 *buf;
- u32 depth;
/* reading */
- u32 rframe_depth, rframe_cur;
+ struct vg_msg_cursor
+ {
+ u32 co, depth;
+ }
+ cur;
- enum vg_msg_error{
+ enum vg_msg_error
+ {
k_vg_msg_error_OK,
k_vg_msg_error_unbalanced,
k_vg_msg_error_overflow,
error;
};
-struct vg_msg_cmd{
+struct vg_msg_cmd
+{
u8 code;
const char *key;
const void *value;
u32 value_djb2;
-};
-
-/* write a buffer from msg, rang checked. */
-static void vg_msg_wbuf( vg_msg *msg, u8 *buf, u32 len ){
- if( msg->error != k_vg_msg_error_OK ) return;
- if( msg->cur+len > msg->max ){
- msg->error = k_vg_msg_error_overflow;
- return;
- }
-
- for( u32 i=0; i<len; i++ ){
- msg->buf[ msg->cur ++ ] = buf[i];
- msg->len ++;
- }
-}
-
-/* read a buffer from msg, rang checked. */
-static void vg_msg_rbuf( vg_msg *msg, u8 *buf, u32 len ){
- if( msg->error != k_vg_msg_error_OK ) return;
- if( msg->cur+len > msg->len ){
- msg->error = k_vg_msg_error_overflow;
- return;
- }
-
- for( u32 i=0; i<len; i++ ){
- buf[i] = msg->buf[ msg->cur ++ ];
- }
-}
-
-/* write null terminated string to stream */
-static void vg_msg_wstr( vg_msg *msg, const char *str ){
- if( msg->error != k_vg_msg_error_OK ) return;
- for( u32 i=0;; i++ ){
- vg_msg_wbuf( msg, (u8[]){ str[i] }, 1 );
- if( !str[i] ) break;
- }
-}
-
-/* read null terminated string, range check and generate hash (djb2) */
-static const char *vg_msg_rstr( vg_msg *msg, u32 *djb2 ){
- if( msg->error != k_vg_msg_error_OK ) return 0;
-
- u32 hash = 5381, c;
- const char *str = (void *)(&msg->buf[ msg->cur ]);
-
- while( (c = msg->buf[ msg->cur ++ ]) ){
- if( msg->cur >= msg->max ){
- msg->error = k_vg_msg_error_overflow;
- return 0;
- }
- hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
- }
-
- *djb2 = hash;
- return str;
-}
-
-/* begin a new frame in message stream */
-static void vg_msg_frame( vg_msg *msg, const char *name ){
- if( msg->error != k_vg_msg_error_OK ) return;
-
- msg->depth ++;
- vg_msg_wbuf( msg, (u8[]){ k_vg_msg_frame }, 1 );
- vg_msg_wstr( msg, name );
-}
-
-/* shift right side of cursor by len */
-static void vg_msg_makeroom( vg_msg *msg, u32 len ){
- if( msg->error != k_vg_msg_error_OK ) return;
- if( msg->len + len > msg->max ){
- msg->error = k_vg_msg_error_overflow;
- return;
- }
- u32 i = msg->len-msg->cur;
- while( i --> 0 ){
- msg->buf[ msg->cur+len+i ] = msg->buf[ msg->cur+i ];
- }
- msg->len += len;
-}
-
-/* paste data into msg, at the cursor location */
-static void vg_msg_insert( vg_msg *msg, vg_msg *data ){
- vg_msg_makeroom( msg, data->len );
- vg_msg_wbuf( msg, data->buf, data->len );
- msg->depth += data->depth;
-}
-
-/* end frame in message stream */
-static void vg_msg_end_frame( vg_msg *msg ){
- if( msg->error != k_vg_msg_error_OK ) return;
- if( !msg->depth ){
- msg->error = k_vg_msg_error_unbalanced;
- return;
- }
- msg->depth --;
- vg_msg_wbuf( msg, (u8[]){ k_vg_msg_endframe }, 1 );
-}
-
-/* write a KV string to stream */
-static void vg_msg_wkvstr( vg_msg *msg, const char *key, const char *value ){
- vg_msg_wbuf( msg, (u8[]){ k_vg_msg_kvstring }, 1 );
- vg_msg_wstr( msg, key );
- vg_msg_wstr( msg, value );
-}
-
-/* write a binary block to stream */
-static void vg_msg_wkvbin( vg_msg *msg, const char *key, u8 *bin, u32 len ){
- vg_msg_wbuf( msg, (u8[]){ k_vg_msg_kvbin }, 1 );
- vg_msg_wstr( msg, key );
- vg_msg_wbuf( msg, (u8 *)(&len), 4 );
- vg_msg_wbuf( msg, bin, len );
-}
-
-/* get the byte count of a sized code */
-static u32 vg_msg_sized_bytecount( u8 code ){
- u32 size = 0x1 << (code & k_vg_msg_size_bits),
- count = (code & k_vg_msg_array_count_bits) + 1;
- return size * count;
-}
-/* write a sized type */
-static void vg_msg_wkvnum( vg_msg *msg, const char *key,
- u8 type, u8 count, void *data ){
- u8 code = type | ((count-1)<<2);
-
- vg_msg_wbuf( msg, &code, 1 );
- vg_msg_wstr( msg, key );
- vg_msg_wbuf( msg, data, vg_msg_sized_bytecount(code) );
-}
-
-static void vg_msg_wkvu32( vg_msg *msg, const char *key, u32 value ){
- vg_msg_wkvnum( msg, key, k_vg_msg_unsigned|k_vg_msg_32b, 1, &value );
-}
-
-/*
- * The stream reading interface
- * -----------------------------------------------------------------------------
- */
-
-/* move the cursor through the next message. it will always read in the value or
- * create an error if it runs of the end of the stream. every possible command
- * must be handled in this function */
-static int vg_msg_next( vg_msg *msg, vg_msg_cmd *cmd ){
- vg_msg_rbuf( msg, &cmd->code, 1 );
-
-#ifdef VG_MSG_V1_SUPPORT
- /* |sized| |count-1| |shift|
- * 0 1 0 0 0 1 0 0 0x44 (1 byte, float[2]. So, never used anyway)
- * converts to
- * 1 0 0 0 0 0 1 0 0x82
- */
- if( cmd->code == 0x44 ) cmd->code = 0x82;
-#endif
-
- if( msg->error != k_vg_msg_error_OK ) return 0;
-
- if( cmd->code == k_vg_msg_frame ){
- cmd->key = vg_msg_rstr( msg, &cmd->key_djb2 );
- msg->depth ++;
- }
- else if( cmd->code == k_vg_msg_endframe ){
- if( !msg->depth ){
- msg->error = k_vg_msg_error_unbalanced;
- return 0;
- }
- msg->depth --;
- }
- else if( cmd->code >= k_vg_msg_kv ){
- cmd->key = vg_msg_rstr( msg, &cmd->key_djb2 );
- cmd->value_djb2 = 0;
-
- if( cmd->code & k_vg_msg_sized_type_bits ){
- u32 bytes = vg_msg_sized_bytecount( cmd->code );
- cmd->value = &msg->buf[ msg->cur ];
- msg->cur += bytes;
- }
- else if( cmd->code == k_vg_msg_kvstring ){
- cmd->value = vg_msg_rstr( msg, &cmd->value_djb2 );
- }
- else if( cmd->code == k_vg_msg_kvbin ){
- u32 len;
- vg_msg_rbuf( msg, (u8 *)(&len), 4 );
- if( msg->error != k_vg_msg_error_OK ) return 0;
- cmd->value = &msg->buf[ msg->cur ];
- msg->cur += len;
- }
- else
- msg->error = k_vg_msg_error_unhandled_cmd;
-
- if( msg->cur > msg->max )
- msg->error = k_vg_msg_error_overflow;
- }
- else
- msg->error = k_vg_msg_error_unhandled_cmd;
-
- if( msg->error != k_vg_msg_error_OK ) return 0;
- else return 1;
-}
+ u32 len; /* set if binary type */
+};
-/* move through the frame(and subframes) until we fall out of it */
-static int vg_msg_skip_frame( vg_msg *msg ){
- vg_msg_cmd cmd;
-
- u32 depth = msg->depth-1;
- while( vg_msg_next( msg, &cmd ) ){
- if( msg->depth == depth ) return 1;
- }
- return 0;
-}
+void vg_msg_wbuf( vg_msg *msg, u8 *buf, u32 len );
+void vg_msg_rbuf( vg_msg *msg, u8 *buf, u32 len );
+void vg_msg_wstr( vg_msg *msg, const char *str );
+const char *vg_msg_rstr( vg_msg *msg, u32 *djb2 );
+void vg_msg_frame( vg_msg *msg, const char *name );
+void vg_msg_end_frame( vg_msg *msg );
+void vg_msg_wkvstr( vg_msg *msg, const char *key, const char *value );
+void vg_msg_wkvbin( vg_msg *msg, const char *key, u8 *bin, u32 len );
+void vg_msg_wkvnum( vg_msg *msg, const char *key,
+ u8 type, u8 count, void *data );
+u32 vg_msg_cmd_array_count( u8 code );
+u32 vg_msg_cmd_type_size( u8 code );
+u32 vg_msg_cmd_bytecount( u8 code );
+u8 vg_msg_count_bits( u32 count );
+
+void vg_msg_init( vg_msg *msg, u8 *buffer, u32 len );
+int vg_msg_next( vg_msg *msg, vg_msg_cmd *cmd );
+int vg_msg_skip_frame( vg_msg *msg );
+int vg_msg_seekframe( vg_msg *msg, const char *name );
+u64 vg_msg_cast_to_u64( const void *src, u8 src_base, u8 src_size );
+i64 vg_msg_cast_to_i64( const void *src, u8 src_base, u8 src_size );
+f64 vg_msg_cast_to_f64( const void *src, u8 src_base, u8 src_size );
+void vg_msg_cast( const void *src, u8 src_code, void *dst, u8 dst_code );
+
+int vg_msg_getkvcmd( vg_msg *msg, const char *key, vg_msg_cmd *cmd );
/*
- * A more friendly but slower interface
- * -----------------------------------------------------------------------------
+ * Read a integral KV out to dst, and perform conversion if needed
+ * dst is always defined, if its not found its set to 0
*/
-
-enum vg_msg_dir{
- k_vg_msg_first=0, /* reset the frame pointer and find the first thing */
- k_vg_msg_next=1 /* get next item in the stream, wont find behind cursor */
-};
-
-/* reset frame pointer and depth to the start of the frame set by seekframe */
-static void vg_msg_framereset( vg_msg *frame ){
- frame->cur = frame->rframe_cur;
- frame->depth = frame->rframe_depth;
-}
-
-/* moves to a frame, and sets the base frame in msg if it finds it */
-static int vg_msg_seekframe( vg_msg *msg, const char *name,
- enum vg_msg_dir dir )
-{
- if( dir == k_vg_msg_first ) vg_msg_framereset( msg );
-
- vg_msg_cmd cmd;
- while( vg_msg_next( msg, &cmd ) ){
- if( msg->depth < msg->rframe_depth ){
- vg_msg_framereset(msg);
- return 0;
- }
- if( msg->depth != msg->rframe_depth+1 ) continue;
- if( cmd.code == k_vg_msg_frame ){
- if( VG_STRDJB2_EQ( name, cmd.key, cmd.key_djb2 ) ){
- msg->rframe_cur = msg->cur;
- msg->rframe_depth = msg->depth;
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-/* move to the kv named key, doesnt matter what type */
-static vg_msg_cmd vg_msg_seekkv( vg_msg *msg, const char *key,
- enum vg_msg_dir dir )
-{
- if( dir == k_vg_msg_first ) vg_msg_framereset( msg );
-
- vg_msg_cmd kv;
- kv.code = k_vg_msg_end;
- kv.key = "";
- kv.key_djb2 = 0;
- kv.value = NULL;
- kv.value_djb2 = 0;
-
- vg_msg_cmd cmd;
- while( vg_msg_next( msg, &cmd ) ){
- if( msg->depth < msg->rframe_depth ){
- vg_msg_framereset(msg);
- return kv;
- }
- if( msg->depth > msg->rframe_depth ) continue;
- if( cmd.code > k_vg_msg_kv )
- if( VG_STRDJB2_EQ( key, cmd.key, cmd.key_djb2 ) )
- return cmd;
- }
-
- return kv;
-}
+int vg_msg_getkvintg( vg_msg *msg, const char *key, u8 type, void *dst );
/* helper for reading string kvs. returns NULL if not found */
-static const char *vg_msg_seekkvstr( vg_msg *msg, const char *key,
- enum vg_msg_dir dir )
-{
- vg_msg_cmd cmd = vg_msg_seekkv( msg, key, dir );
- if( cmd.code == k_vg_msg_kvstring ) return cmd.value;
- else return NULL;
-}
-
-static u32 vg_msg_seekkvu32( vg_msg *msg, const char *key, enum vg_msg_dir dir )
-{
- vg_msg_cmd cmd = vg_msg_seekkv( msg, key, dir );
- u8 sized_type = cmd.code & k_vg_msg_sized_type_bits;
-
- u32 result = 0x00;
- u8 *dst = (void *)(&result);
- const u8 *src = cmd.value;
-
- if( (sized_type == k_vg_msg_unsigned) || (sized_type == k_vg_msg_signed) ){
- u32 bytes = vg_msg_sized_bytecount( cmd.code );
- if( bytes > 4 ) bytes = 4;
- for( u32 i=0; i<bytes; i ++ ) dst[i] = src[i];
- }
-
- return result;
-}
-
-/* debug the thing */
-static void vg_msg_print( vg_msg *msg ){
- vg_msg b = *msg;
- b.cur = 0;
-
- vg_msg_cmd cmd;
- while( vg_msg_next( &b, &cmd ) ){
- if( cmd.code == k_vg_msg_frame ){
- for( u32 i=0; i<b.depth-1; i++ ) printf( " " );
- printf( "'%s'[%u]{\n", cmd.key, cmd.key_djb2 );
- }
- else {
- for( u32 i=0; i<b.depth; i++ ) printf( " " );
-
- if( cmd.code == k_vg_msg_endframe )
- printf( "}\n" );
- else if( cmd.code == k_vg_msg_kvstring ){
- printf( "'%s'[%u]: '%s'[%u]\n", cmd.key, cmd.key_djb2,
- (char *)cmd.value, cmd.value_djb2 );
- }
- else
- printf( "'%s'[%u]: <binary data>\n", cmd.key, cmd.key_djb2 );
- }
- }
-}
-
-#endif /* VG_MSG_H */
+const char *vg_msg_getkvstr( vg_msg *msg, const char *key );
+int vg_msg_getkvvecf( vg_msg *msg, const char *key, u8 type,
+ void *v, void *default_value );
+void vg_msg_print( vg_msg *msg, u32 len );