bad char
[vg.git] / vg_msg.h
index cc38e859cc0a9b34eb217e9c88da2af3d24ded87..0b1302418ef710f55fa11faa58787e30a0034e42 100644 (file)
--- a/vg_msg.h
+++ b/vg_msg.h
-#ifndef VG_MSG_H
-#define VG_MSG_H
-#include "vg_stdint.h"
+#pragma once
+/*
+ * Example data:
+ *   kvstr "someinfo"
+ *   kvint 200
+ *   frame "person"{
+ *      name "jeff"
+ *      country "england"
+ *   }
+ *   frame "building"{
+ *      capacity 1000
+ *   }
+ *   frame "person"{
+ *      country "wales"
+ *      name "micheal"
+ *   }
+ *
+ * Creating the data in code:
+ * -----------------------------------------------------------------------------
+ *   u8 data_buf[512];
+ *   vg_msg data;
+ *   vg_msg_init( &data, data_buf, 512 );
+ *
+ *   vg_msg_wkvstr( &data, "kvstr", "someinfo" );
+ *   vg_msg_wkvu32( &data, "kvint", 200 );
+ *
+ *   vg_msg_frame( &data, "person" );
+ *      vg_msg_wkvstr( &data, "name", "jeff" );
+ *      vg_msg_wkvstr( &data, "country", "england" );
+ *   vg_msg_end_frame( &data );
+ *
+ *   vg_msg_frame( &data, "building" );
+ *      vg_msg_wkvu32( &data, "capacity", 1000 );
+ *   vg_msg_end_frame( &data );
+ *
+ *   vg_msg_frame( &data, "person" );
+ *      vg_msg_wkvstr( &data, "country", "wales" );
+ *      vg_msg_wkvstr( &data, "name", "micheal" );
+ *   vg_msg_end_frame( &data );
+ *
+ * Saving the data out
+ * -----------------------------------------------------------------------------
+ *
+ *   if( data.error == k_vg_msg_error_OK ){
+ *      // write data_buf, for length data.cur
+ *   }
+ *
+ * Load the data
+ * -----------------------------------------------------------------------------
+ *
+ *   u8 data_buf[512];
+ *   u32 data_len;
+ *
+ *   // read data_buf and 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
+ * -----------------------------------------------------------------------------
+ * 
+ *   vg_msg_cmd cmd;
+ *   while( vg_msg_next( &data, &cmd ) ){
+ *           if( cmd.code == k_vg_msg_frame ) printf( "{" );
+ *      else if( cmd.code == k_vg_msg_endframe ) printf( "}" );
+ *      esle if( cmd.code == k_vg_msg_kvstring )
+ *         printf( "string: %s\n", cmd.value._buf );
+ *   }
+ */
 
 enum vg_msg_code{
-   k_vg_msg_code_end      = 0,
-   k_vg_msg_code_frame    = 1,
-   k_vg_msg_code_endframe = 2,
-   k_vg_msg_code_kv       = 10,
-   k_vg_msg_code_kvstring = 11,
-   k_vg_msg_code_kvbin    = 12,
-   k_vg_msg_code_signed   = 0x80,   /* byte sizes stored in lower 4 bits */
-   k_vg_msg_code_unsigned = 0x40,
-   k_vg_msg_code_float    = 0x20
+   /* low types */
+   k_vg_msg_end      = 0,
+   k_vg_msg_frame    = 1,
+   k_vg_msg_endframe = 2,
+   k_vg_msg_kv       = 10,
+   k_vg_msg_kvstring = 11,
+   k_vg_msg_kvbin    = 12,
+
+   /* variable sized types */
+   k_vg_msg_float    = 0x40,
+   k_vg_msg_unsigned = 0x80,
+   k_vg_msg_signed   = 0xC0,
+
+   /* masks */
+   k_vg_msg_array_count_bits = 0x3C,
+   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,
+
+   /* sizes */
+   k_vg_msg_8b  = 0x00,
+   k_vg_msg_16b = 0x01,
+   k_vg_msg_32b = 0x02,
+   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,max;
+typedef struct vg_msg_cursor vg_msg_cursor;
+struct vg_msg
+{
+   u32 max;
    u8 *buf;
-   u32 depth;
+
+   /* reading */
+   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,
@@ -30,177 +147,53 @@ struct vg_msg{
    error;
 };
 
-struct vg_msg_cmd{
+struct vg_msg_cmd
+{
    u8 code;
 
    const char *key;
    u32 key_djb2;
 
-   union{ const void *_buf;
-          u8  _u8;  i8  _i8;
-          u16 _u16; i16 _i16;
-          u32 _u32; i32 _i32; f32 _f32; 
-          u64 _u64; i64 _i64; f64 _f64;
-         } value;
+   const void *value;
    u32 value_djb2;
-};
-
-static void vg_msg_init( vg_msg *msg, u8 *buf, u32 max ){
-   msg->cur = 0;
-   msg->max = max;
-   msg->buf = buf;
-   msg->depth = 0;
-   msg->error = k_vg_msg_error_OK;
-}
-
-static void vg_msg_exchbuf( vg_msg *msg, int write, 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++ ){
-      if( write ) msg->buf[ msg->cur ++ ] = buf[i];
-      else        buf[i] = msg->buf[ msg->cur ++ ];
-   }
-}
-
-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_exchbuf( msg, 1, (u8[]){ str[i] }, 1 );
-      if( !str[i] ) break;
-   }
-}
-
-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;
-}
-
-static void vg_msg_frame( vg_msg *msg, const char *name ){
-   if( msg->error != k_vg_msg_error_OK ) return;
-
-   msg->depth ++;
-   vg_msg_exchbuf( msg, 1, (u8[]){ k_vg_msg_code_frame }, 1 );
-   vg_msg_wstr( msg, name );
-}
-
-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_exchbuf( msg, 1, (u8[]){ k_vg_msg_code_endframe }, 1 );
-}
-
-static void vg_msg_wkvstr( vg_msg *msg, const char *key, const char *value ){
-   vg_msg_exchbuf( msg, 1, (u8[]){ k_vg_msg_code_kvstring }, 1 );
-   vg_msg_wstr( msg, key );
-   vg_msg_wstr( msg, value );
-}
-
-static void vg_msg_wkvbin( vg_msg *msg, const char *key, u8 *bin, u32 len ){
-   vg_msg_exchbuf( msg, 1, (u8[]){ k_vg_msg_code_kvbin }, 1 );
-   vg_msg_wstr( msg, key );
-   vg_msg_exchbuf( msg, 1, (u8 *)(&len), 4 );
-   vg_msg_exchbuf( msg, 1, bin, len );
-}
-
-static void vg__msg_wkvgen( vg_msg *msg, const char *key, 
-                            u8 basecode, void *value, u32 size ){
-   u8 code = basecode | size;
-   vg_msg_exchbuf( msg, 1, &code, 1 );
-   vg_msg_wstr( msg, key );
-   vg_msg_exchbuf( msg, 1, value, size );
-}
-
-#define vg_msg_wkvint( MSGPTR, KEY, DECL ){ \
-   DECL; \
-   vg__msg_wkvgen(MSGPTR, KEY, k_vg_msg_code_signed, &value, sizeof(value));\
-   }
-#define vg_msg_wkvuint( MSGPTR, KEY, DECL ){ \
-   DECL; \
-   vg__msg_wkvgen(MSGPTR, KEY, k_vg_msg_code_unsigned, &value, sizeof(value));\
-   }
-#define vg_msg_wkvfloat( MSGPTR, KEY, DECL ){ \
-   DECL; \
-   vg__msg_wkvgen(MSGPTR, KEY, k_vg_msg_code_float, &value, sizeof(value));\
-   }
-
-static int vg_msg_next( vg_msg *msg, vg_msg_cmd *cmd ){
-   vg_msg_exchbuf( msg, 0, &cmd->code, 1 );
-   if( msg->error != k_vg_msg_error_OK ) return 0;
-
-   if( cmd->code == k_vg_msg_code_frame ){
-      cmd->key = vg_msg_rstr( msg, &cmd->key_djb2 );
-      msg->depth ++;
-   }
-   else if( cmd->code == k_vg_msg_code_endframe ){
-      if( !msg->depth ){
-         msg->error = k_vg_msg_error_unbalanced;
-         return 0;
-      }
-      msg->depth --;
-   }
-   else if( cmd->code >= k_vg_msg_code_kv ){
-      cmd->key = vg_msg_rstr( msg, &cmd->key_djb2 );
-      cmd->value_djb2 = 0;
-      cmd->value._u64 = 0;
-
-      if( cmd->code & (k_vg_msg_code_float|k_vg_msg_code_unsigned|
-                       k_vg_msg_code_signed )){
-         u8 len = cmd->code & 0xf;
-         vg_msg_exchbuf( msg, 0, (u8 *)(&cmd->value._u64), len );
-      }
-      else if( cmd->code == k_vg_msg_code_kvstring ){
-         cmd->value._buf = vg_msg_rstr( msg, &cmd->value_djb2 );
-      }
-      else if( cmd->code == k_vg_msg_code_kvbin ){
-         u32 len;
-         vg_msg_exchbuf( msg, 0, (u8 *)(&len), 4 );
-         if( msg->error != k_vg_msg_error_OK ) return 0;
-         cmd->value._buf = &msg->buf[ msg->cur ];
-         msg->cur += len;
-         if( msg->cur > msg->max ){
-            msg->error = k_vg_msg_error_overflow;
-         }
-      }
-      else{
-         msg->error = k_vg_msg_error_unhandled_cmd;
-      }
-   }
-   else{
-      msg->error = k_vg_msg_error_unhandled_cmd;
-   }
-
-   if( msg->error != k_vg_msg_error_OK ) return 0;
-   else return 1;
-}
-
-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;
-}
+   u32 len; /* set if binary type */
+};
 
-#endif /* VG_MSG_H */
+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 );
+
+/*
+ * Read a integral KV out to dst, and perform conversion if needed
+ */
+int vg_msg_getkvintg( vg_msg *msg, const char *key, u8 type, void *dst,
+                      void *default_value );
+
+/* helper for reading string kvs. returns NULL if not found */
+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 );