Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of ThingerClient by
Revision 4:de51256455f7, committed 2015-12-26
- Comitter:
- alvarolb
- Date:
- Sat Dec 26 13:18:01 2015 +0000
- Parent:
- 3:58e0153dbb37
- Commit message:
- Adapter pson to properly work in ARM Mbed old compiler
Changed in this revision
--- a/thinger/pson.h Fri Dec 25 18:21:02 2015 +0000 +++ b/thinger/pson.h Sat Dec 26 13:18:01 2015 +0000 @@ -1,902 +1,940 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 THINGER LTD -// Author: alvarolb@gmail.com (Alvaro Luis Bustamante) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef PSON_HPP -#define PSON_HPP - -#include <stdint.h> -#include <string.h> -#include <math.h> -#include <stdlib.h> - -namespace protoson { - - class memory_allocator{ - public: - virtual void *allocate(size_t size) = 0; - virtual void deallocate(void *) = 0; - }; - - template<size_t buffer_size> - class circular_memory_allocator : public memory_allocator{ - private: - uint8_t buffer_[buffer_size]; - size_t index_; - public: - circular_memory_allocator() : index_(0) { - } - - virtual void *allocate(size_t size) { - if (index_ + size > buffer_size) { - index_ = 0; - } - void *position = &buffer_[index_]; - index_ += size; - return position; - } - - virtual void deallocate(void *) { - - } - }; - - class dynamic_memory_allocator : public memory_allocator{ - public: - virtual void *allocate(size_t size) { - return malloc(size); - } - - virtual void deallocate(void *ptr) { - free(ptr); - } - }; - - extern memory_allocator& pool; -} - -inline void* operator new(size_t sz, protoson::memory_allocator& a) -{ - return a.allocate(sz); -} - -inline void operator delete(void* p, protoson::memory_allocator& a) -{ - a.deallocate(p); -} - -template<class T> -void destroy(T* p, protoson::memory_allocator& a) -{ - if (p) { - p->~T(); - a.deallocate(p); - } -} - -namespace protoson { - - enum pb_wire_type{ - varint = 0, - fixed_64 = 1, - length_delimited = 2, - fixed_32 = 5, - pson_type = 6 - }; - - template<class T> - class pson_container { - - struct list_item{ - T item_; - list_item* next_; - }; - - public: - - class iterator{ - public: - iterator(list_item *current) : current(current) { - } - - private: - list_item * current; - - public: - bool next(){ - if(current==NULL) return false; - current = current->next_; - return true; - } - - bool has_next(){ - return current!=NULL && current->next_!=NULL; - } - - bool valid(){ - return current!=NULL; - } - - T& item(){ - return current->item_; - } - }; - - private: - list_item* item_; - - public: - iterator begin() const{ - return iterator(item_); - } - - pson_container() : item_(NULL) { - } - - ~pson_container(){ - clear(); - } - - size_t size() const{ - size_t size = 0; - list_item* current = item_; - while(current!=NULL){ - current = current->next_; - size++; - } - return size; - } - - T* operator[](size_t index){ - list_item* current = item_; - size_t current_index = 0; - while(current!=NULL){ - if(current_index==index){ - return ¤t->item_; - } - current = current->next_; - current_index++; - } - return NULL; - } - - void clear(){ - list_item* current = item_; - while(current!=NULL){ - list_item* next = current->next_; - destroy(current, pool); - current = next; - } - item_ = NULL; - } - - T& create_item(){ - list_item* new_list_item = new(pool) list_item(); - if(item_==NULL){ - item_ = new_list_item; - } - else{ - list_item * last = item_; - while(last->next_!=NULL) last = last->next_; - last->next_ = new_list_item; - } - return new_list_item->item_; - } - }; - - class pson_object; - class pson_array; - - class pson { - public: - enum field_type { - null_field = 0, - varint_field = 1, - svarint_field = 2, - float_field = 3, - double_field = 4, - true_field = 5, - false_field = 6, - zero_field = 7, - one_field = 8, - string_field = 9, - empty_string = 10, - bytes_field = 11, - empty_bytes = 12, - object_field = 13, - array_field = 14, - empty = 15, - // a message tag is encoded in a 128-base varint [1-bit][3-bit wire type][4-bit field] - // we have up to 4 bits (0-15) for encoding fields in the first byte - }; - - bool is_boolean() const{ - return field_type_ == true_field || field_type_ == false_field; - } - - bool is_string() const{ - return field_type_ == string_field; - } - - bool is_bytes() const{ - return field_type_ == bytes_field; - } - - bool is_number() const{ - return field_type_ == varint_field || - field_type_ == svarint_field || - field_type_ == float_field || - field_type_ == double_field || - field_type_ == zero_field || - field_type_ == one_field; - } - - bool is_object() const{ - return field_type_ == object_field; - } - - bool is_array() const{ - return field_type_ == array_field; - } - - bool is_null() const{ - return field_type_ == null_field; - } - - bool is_empty() const{ - return field_type_ == empty; - } - - pson() : field_type_(empty), value_(NULL) { - } - - template<class T> - pson(T value) : field_type_(empty), value_(NULL){ - *this = value; - } - - ~pson(){ - if(field_type_==object_field){ - destroy((pson_object *) value_, pool); - }else if(field_type_==array_field) { - destroy((pson_array *) value_, pool); - }else{ - pool.deallocate(value_); - } - } - - template<class T> - void operator=(T value) - { - if(value==0){ - field_type_ = zero_field; - }else if(value==1) { - field_type_ = one_field; - }else{ - if(value<0){ - field_type_ = svarint_field; - }else{ - field_type_ = varint_field; - } - uint64_t uint_value = value>0 ? value : -value; - value_ = pool.allocate(pson::get_varint_size(uint_value)); - pb_encode_varint(uint_value); - } - } - - void operator=(bool value){ - field_type_ = value ? true_field : false_field; - } - - void operator=(float value) { - if(value==(int32_t)value){ - *this = (int32_t) value; - }else{ - field_type_ = float_field; - set(value); - } - } - - void operator=(double value) { - if(value==(int64_t)value) { - *this = (int64_t) value; - }else if(fabs(value-(float)value)<=0.00001){ - field_type_ = float_field; - set((float)value); - }else{ - field_type_ = double_field; - set(value); - } - } - - void operator=(const char *str) { - size_t str_size = strlen(str); - if(str_size==0){ - field_type_ = empty_string; - }else{ - field_type_ = string_field; - memcpy(allocate(str_size+1), str, str_size+1); - } - } - - operator const char *() { - switch(field_type_){ - case string_field: - return (const char*) value_; - case empty: - field_type_ = empty_string; - default: - return ""; - } - } - - void set_bytes(const void* bytes, size_t size) { - if(size>0){ - size_t varint_size = get_varint_size(size); - value_ = pool.allocate(varint_size+size); - pb_encode_varint(size); - memcpy(((uint8_t*)value_)+varint_size, bytes, size); - field_type_ = bytes_field; - }else{ - field_type_ = empty_bytes; - } - } - - bool get_bytes(const void*& bytes, size_t& size){ - switch(field_type_){ - case bytes_field: - size = pb_decode_varint(); - bytes = (uint8_t*) value_ + get_varint_size(size); - return true; - case empty: - field_type_ = empty_bytes; - default: - return false; - } - } - - void* allocate(size_t size){ - value_ = pool.allocate(size); - return value_; - } - - operator pson_object &(); - operator pson_array &(); - pson & operator[](const char *name); - - operator bool(){ - switch(field_type_){ - case zero_field: - case false_field: - return false; - case one_field: - case true_field: - return true; - case empty: - field_type_ = false_field; - default: - return false; - } - } - - template<class T> - operator T() { - switch(field_type_){ - case zero_field: - case false_field: - return 0; - case one_field: - case true_field: - return 1; - case float_field: - return *(float*)value_; - case double_field: - return *(double*)value_; - case varint_field: - return pb_decode_varint(); - case svarint_field: - return -pb_decode_varint(); - case empty: - field_type_ = zero_field; - default: - return 0; - } - } - - void* get_value(){ - return value_; - } - - void set_value(void* value){ - value_ = value; - } - - field_type get_type() const{ - return field_type_; - } - - void set_null(){ - field_type_ = null_field; - } - - void set_type(field_type type){ - field_type_ = type; - } - - uint8_t get_varint_size(uint64_t value) const{ - uint8_t size = 1; - while(value>>=7) size++; - return size; - } - - void pb_encode_varint(uint64_t value) const - { - uint8_t count = 0; - do - { - uint8_t byte = (uint8_t)(value & 0x7F); - value >>= 7; - if(value) byte |= 0x80; - ((uint8_t*)value_)[count] = byte; - count++; - }while(value); - } - - uint64_t pb_decode_varint() const - { - if(value_==NULL) return 0; - uint64_t value = 0; - uint8_t pos = 0; - uint8_t byte = 0; - do{ - byte = ((uint8_t*)value_)[pos]; - value |= (uint64_t)(byte&0x7F) << pos*7; - pos++; - }while(byte>=0x80); - return value; - } - - private: - void* value_; - field_type field_type_; - - template<class T> - void set(T value) { - memcpy(allocate(sizeof(T)), &value, sizeof(T)); - } - }; - - class pson_pair{ - private: - char* name_; - pson value_; - public: - pson_pair() : name_(NULL){ - } - - ~pson_pair(){ - destroy(name_, pool); - } - - void set_name(const char *name) { - size_t name_size = strlen(name) + 1; - memcpy(allocate_name(name_size), name, name_size); - } - - char* allocate_name(size_t size){ - name_ = (char*)pool.allocate(size); - return name_; - } - - pson& value(){ - return value_; - } - - char* name() const{ - return name_; - } - }; - - class pson_object : public pson_container<pson_pair> { - public: - pson &operator[](const char *name) { - for(iterator it=begin(); it.valid(); it.next()){ - if(strcmp(it.item().name(), name)==0){ - return it.item().value(); - } - } - pson_pair & pair = create_item(); - pair.set_name(name); - return pair.value(); - }; - }; - - class pson_array : public pson_container<pson> { - public: - template<class T> - pson_array& add(T item_value){ - create_item() = item_value; - return *this; - } - }; - - inline pson::operator pson_object &() { - if (field_type_ != object_field) { - value_ = new(pool) pson_object; - field_type_ = object_field; - } - return *((pson_object *)value_); - } - - inline pson::operator pson_array &() { - if (field_type_ != array_field) { - value_ = new(pool) pson_array; - field_type_ = array_field; - } - return *((pson_array *)value_); - } - - inline pson &pson::operator[](const char *name) { - return ((pson_object &) *this)[name]; - } - - //////////////////////////// - /////// PSON_DECODER /////// - //////////////////////////// - - class pson_decoder { - - protected: - size_t read_; - - virtual bool read(void* buffer, size_t size){ - read_+=size; - return true; - } - - public: - - pson_decoder() : read_(0) { - - } - - void reset(){ - read_ = 0; - } - - size_t bytes_read(){ - return read_; - } - - bool pb_decode_tag(pb_wire_type& wire_type, uint32_t& field_number) - { - uint32_t temp = pb_decode_varint32(); - wire_type = (pb_wire_type)(temp & 0x07); - field_number = temp >> 3; - return true; - } - - uint32_t pb_decode_varint32() - { - uint32_t varint = 0; - if(try_pb_decode_varint32(varint)){ - return varint; - } - return 0; - } - - bool try_pb_decode_varint32(uint32_t& varint){ - varint = 0; - uint8_t byte; - uint8_t bit_pos = 0; - do{ - if(!read(&byte, 1) || bit_pos>=32){ - return false; - } - varint |= (uint32_t)(byte&0x7F) << bit_pos; - bit_pos += 7; - }while(byte>=0x80); - return true; - } - - uint64_t pb_decode_varint64() - { - uint64_t varint = 0; - uint8_t byte; - uint8_t bit_pos = 0; - do{ - if(!read(&byte, 1) || bit_pos>=64){ - return varint; - } - varint |= (uint32_t)(byte&0x7F) << bit_pos; - bit_pos += 7; - }while(byte>=0x80); - return varint; - } - - bool pb_skip(size_t size){ - uint8_t byte; - bool success = true; - for(size_t i=0; i<size; i++){ - success &= read(&byte, 1); - } - return success; - } - - bool pb_skip_varint(){ - uint8_t byte; - bool success = true; - do{ - success &= read(&byte, 1); - }while(byte>0x80); - return success; - } - - bool pb_read_string(char *str, size_t size){ - bool success = read(str, size); - str[size]=0; - return success; - } - - bool pb_read_varint(pson& value) - { - uint8_t temp[10]; - uint8_t byte=0; - uint8_t bytes_read=0; - do{ - if(!read(&byte, 1)) return false; - temp[bytes_read] = byte; - bytes_read++; - }while(byte>=0x80); - memcpy(value.allocate(bytes_read), temp, bytes_read); - return true; - } - - public: - - void decode(pson_object & object, size_t size){ - size_t start_read = bytes_read(); - while(size-(bytes_read()-start_read)>0){ - decode(object.create_item()); - } - } - - void decode(pson_array & array, size_t size){ - size_t start_read = bytes_read(); - while(size-(bytes_read()-start_read)>0){ - decode(array.create_item()); - } - } - - void decode(pson_pair & pair){ - uint32_t name_size = pb_decode_varint32(); - pb_read_string(pair.allocate_name(name_size+1), name_size); - decode(pair.value()); - } - - void decode(pson& value) { - uint32_t field_number; - pb_wire_type wire_type; - pb_decode_tag(wire_type, field_number); - value.set_type((pson::field_type)field_number); - if(wire_type==length_delimited){ - uint32_t size = pb_decode_varint32(); - switch(field_number){ - case pson::string_field: - pb_read_string((char*)value.allocate(size + 1), size); - break; - case pson::bytes_field: { - uint8_t varint_size = value.get_varint_size(size); - read((char*)value.allocate(size + varint_size) + varint_size, size); - value.pb_encode_varint(size); - } - break; - case pson::object_field: - value.set_value(new (pool) pson_object); - decode(*(pson_object *)value.get_value(), size); - break; - case pson::array_field: - value.set_value(new (pool) pson_array); - decode(*(pson_array *)value.get_value(), size); - break; - default: - pb_skip(size); - break; - } - }else { - switch (field_number) { - case pson::svarint_field: - case pson::varint_field: - pb_read_varint(value); - break; - case pson::float_field: - read(value.allocate(4), 4); - break; - case pson::double_field: - read(value.allocate(8), 8); - break; - default: - break; - } - } - } - }; - - //////////////////////////// - /////// PSON_ENCODER /////// - //////////////////////////// - - class pson_encoder { - - protected: - size_t written_; - - virtual void write(const void* buffer, size_t size){ - written_+=size; - } - - public: - - pson_encoder() : written_(0) { - } - - void reset(){ - written_ = 0; - } - - size_t bytes_written(){ - return written_; - } - - void pb_encode_tag(pb_wire_type wire_type, uint32_t field_number){ - uint64_t tag = ((uint64_t)field_number << 3) | wire_type; - pb_encode_varint(tag); - } - - void pb_encode_varint(uint32_t field, uint64_t value) - { - pb_encode_tag(varint, field); - pb_encode_varint(value); - } - - uint8_t pb_write_varint(void * buffer) - { - uint8_t byte=0; - uint8_t bytes_written=0; - do{ - byte = *((uint8_t*)buffer + bytes_written); - bytes_written++; - }while(byte>=0x80); - write(buffer, bytes_written); - return bytes_written; - } - - void pb_encode_varint(uint64_t value) - { - do - { - uint8_t byte = (uint8_t)(value & 0x7F); - value >>= 7; - if(value>0) byte |= 0x80; - write(&byte, 1); - }while(value>0); - } - - void pb_encode_string(const char* str, uint32_t field_number){ - pb_encode_tag(length_delimited, field_number); - pb_encode_string(str); - } - - void pb_encode_string(const char* str){ - size_t string_size = strlen(str); - pb_encode_varint(string_size); - write(str, string_size); - } - - template<class T> - void pb_encode_submessage(T& element, uint32_t field_number) - { - pb_encode_tag(length_delimited, field_number); - pson_encoder sink; - sink.encode(element); - pb_encode_varint(sink.bytes_written()); - encode(element); - } - - void pb_encode_fixed32(void* value){ - write(value, 4); - } - - void pb_encode_fixed64(void* value){ - write(value, 8); - } - - void pb_encode_fixed32(uint32_t field, void*value) - { - pb_encode_tag(fixed_32, field); - pb_encode_fixed32(value); - } - - void pb_encode_fixed64(uint32_t field, void*value) - { - pb_encode_tag(fixed_64, field); - pb_encode_fixed64(value); - } - - public: - - void encode(pson_object & object){ - pson_container<pson_pair>::iterator it = object.begin(); - while(it.valid()){ - encode(it.item()); - it.next(); - } - } - - void encode(pson_array & array){ - pson_container<pson>::iterator it = array.begin(); - while(it.valid()){ - encode(it.item()); - it.next(); - } - } - - void encode(pson_pair & pair){ - pb_encode_string(pair.name()); - encode(pair.value()); - } - - void encode(pson & value) { - switch (value.get_type()) { - case pson::string_field: - pb_encode_string((const char*)value.get_value(), pson::string_field); - break; - case pson::bytes_field: - pb_encode_tag(length_delimited, pson::bytes_field); - write(((const char *) value.get_value()) + pb_write_varint(value.get_value()), value.pb_decode_varint()); - break; - case pson::svarint_field: - case pson::varint_field: - pb_encode_tag(varint, value.get_type()); - pb_write_varint(value.get_value()); - break; - case pson::float_field: - pb_encode_fixed32(pson::float_field, value.get_value()); - break; - case pson::double_field: - pb_encode_fixed64(pson::double_field, value.get_value()); - break; - case pson::object_field: - pb_encode_submessage(*(pson_object *) value.get_value(), pson::object_field); - break; - case pson::array_field: - pb_encode_submessage(*(pson_array *) value.get_value(), pson::array_field); - break; - default: - pb_encode_tag(varint, value.get_type()); - break; - } - } - }; -} - -#endif +// The MIT License (MIT) +// +// Copyright (c) 2015 THINGER LTD +// Author: alvarolb@gmail.com (Alvaro Luis Bustamante) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef PSON_HPP +#define PSON_HPP + +#include <stdint.h> +#include <string.h> +#include <math.h> +#include <stdlib.h> + +namespace protoson { + + class memory_allocator{ + public: + virtual void *allocate(size_t size) = 0; + virtual void deallocate(void *) = 0; + }; + + template<size_t buffer_size> + class circular_memory_allocator : public memory_allocator{ + private: + uint8_t buffer_[buffer_size]; + size_t index_; + public: + circular_memory_allocator() : index_(0) { + } + + virtual void *allocate(size_t size) { + if (index_ + size > buffer_size) { + index_ = 0; + } + void *position = &buffer_[index_]; + index_ += size; + return position; + } + + virtual void deallocate(void *) { + + } + }; + + class dynamic_memory_allocator : public memory_allocator{ + public: + virtual void *allocate(size_t size) { + return malloc(size); + } + + virtual void deallocate(void *ptr) { + free(ptr); + } + }; + + extern memory_allocator& pool; +} + +inline void* operator new(size_t sz, protoson::memory_allocator& a) +{ + return a.allocate(sz); +} + +inline void operator delete(void* p, protoson::memory_allocator& a) +{ + a.deallocate(p); +} + +template<class T> +void destroy(T* p, protoson::memory_allocator& a) +{ + if (p) { + p->~T(); + a.deallocate(p); + } +} + +namespace protoson { + + enum pb_wire_type{ + varint = 0, + fixed_64 = 1, + length_delimited = 2, + fixed_32 = 5, + pson_type = 6 + }; + + template<class T> + class pson_container { + + struct list_item{ + T item_; + list_item* next_; + }; + + public: + + class iterator{ + public: + iterator(list_item *current) : current(current) { + } + + private: + list_item * current; + + public: + bool next(){ + if(current==NULL) return false; + current = current->next_; + return true; + } + + bool has_next(){ + return current!=NULL && current->next_!=NULL; + } + + bool valid(){ + return current!=NULL; + } + + T& item(){ + return current->item_; + } + }; + + private: + list_item* item_; + + public: + iterator begin() const{ + return iterator(item_); + } + + pson_container() : item_(NULL) { + } + + ~pson_container(){ + clear(); + } + + size_t size() const{ + size_t size = 0; + list_item* current = item_; + while(current!=NULL){ + current = current->next_; + size++; + } + return size; + } + + T* operator[](size_t index){ + list_item* current = item_; + size_t current_index = 0; + while(current!=NULL){ + if(current_index==index){ + return ¤t->item_; + } + current = current->next_; + current_index++; + } + return NULL; + } + + void clear(){ + list_item* current = item_; + while(current!=NULL){ + list_item* next = current->next_; + destroy(current, pool); + current = next; + } + item_ = NULL; + } + + T& create_item(){ + list_item* new_list_item = new(pool) list_item(); + if(item_==NULL){ + item_ = new_list_item; + } + else{ + list_item * last = item_; + while(last->next_!=NULL) last = last->next_; + last->next_ = new_list_item; + } + return new_list_item->item_; + } + }; + + class pson_object; + class pson_array; + + class pson { + public: + enum field_type { + null_field = 0, + varint_field = 1, + svarint_field = 2, + float_field = 3, + double_field = 4, + true_field = 5, + false_field = 6, + zero_field = 7, + one_field = 8, + string_field = 9, + empty_string = 10, + bytes_field = 11, + empty_bytes = 12, + object_field = 13, + array_field = 14, + empty = 15, + // a message tag is encoded in a 128-base varint [1-bit][3-bit wire type][4-bit field] + // we have up to 4 bits (0-15) for encoding fields in the first byte + }; + + bool is_boolean() const{ + return field_type_ == true_field || field_type_ == false_field; + } + + bool is_string() const{ + return field_type_ == string_field; + } + + bool is_bytes() const{ + return field_type_ == bytes_field; + } + + bool is_number() const{ + return field_type_ == varint_field || + field_type_ == svarint_field || + field_type_ == float_field || + field_type_ == double_field || + field_type_ == zero_field || + field_type_ == one_field; + } + + bool is_object() const{ + return field_type_ == object_field; + } + + bool is_array() const{ + return field_type_ == array_field; + } + + bool is_null() const{ + return field_type_ == null_field; + } + + bool is_empty() const{ + return field_type_ == empty; + } + + pson() : value_(NULL), field_type_(empty) { + } + + template<class T> + pson(T value) : value_(NULL), field_type_(empty){ + *this = value; + } + + ~pson(){ + if(field_type_==object_field){ + destroy((pson_object *) value_, pool); + }else if(field_type_==array_field) { + destroy((pson_array *) value_, pool); + }else{ + pool.deallocate(value_); + } + } + + template<class T> + void operator=(T value) + { + if(value==0){ + field_type_ = zero_field; + }else if(value==1) { + field_type_ = one_field; + }else{ + field_type_ = value>0 ? varint_field : svarint_field; + uint64_t uint_value = value>0 ? value : -value; + value_ = pool.allocate(pson::get_varint_size(uint_value)); + pb_encode_varint(uint_value); + } + } + + void operator=(bool value){ + field_type_ = value ? true_field : false_field; + } + + void operator=(float value) { + if(value==(int32_t)value){ + *this = (int32_t) value; + }else{ + field_type_ = float_field; + set(value); + } + } + + void operator=(double value) { + if(value==(int64_t)value) { + *this = (int64_t) value; + }else if(fabs(value-(float)value)<=0.00001){ + field_type_ = float_field; + set((float)value); + }else{ + field_type_ = double_field; + set(value); + } + } + + void operator=(const char *str) { + size_t str_size = strlen(str); + if(str_size==0){ + field_type_ = empty_string; + }else{ + field_type_ = string_field; + memcpy(allocate(str_size+1), str, str_size+1); + } + } + + void set_bytes(const void* bytes, size_t size) { + if(size>0){ + size_t varint_size = get_varint_size(size); + value_ = pool.allocate(varint_size+size); + pb_encode_varint(size); + memcpy(((uint8_t*)value_)+varint_size, bytes, size); + field_type_ = bytes_field; + }else{ + field_type_ = empty_bytes; + } + } + + bool get_bytes(const void*& bytes, size_t& size){ + switch(field_type_){ + case bytes_field: + size = pb_decode_varint(); + bytes = (uint8_t*) value_ + get_varint_size(size); + return true; + case empty: + field_type_ = empty_bytes; + default: + return false; + } + } + + void* allocate(size_t size){ + value_ = pool.allocate(size); + return value_; + } + + operator pson_object &(); + operator pson_array &(); + pson & operator[](const char *name); + + operator const char *() { + switch(field_type_){ + case string_field: + return (const char*) value_; + case empty: + field_type_ = empty_string; + default: + return ""; + } + } + + operator bool(){ + switch(field_type_){ + case zero_field: + case false_field: + return false; + case one_field: + case true_field: + return true; + case empty: + field_type_ = false_field; + default: + return 0; + } + } + + operator char(){ + return get_value<char>(); + } + + operator unsigned char(){ + return get_value<unsigned char>(); + } + + operator short(){ + return get_value<short>(); + } + + operator unsigned short(){ + return get_value<unsigned short>(); + } + + operator int(){ + return get_value<int>(); + } + + operator unsigned int(){ + return get_value<int>(); + } + + operator long(){ + return get_value<long>(); + } + + operator unsigned long(){ + return get_value<unsigned long>(); + } + + operator float(){ + return get_value<float>(); + } + + operator double(){ + return get_value<double>(); + } + + template<class T> + operator T() { + return get_value<T>(); + } + + template<class T> + T get_value(){ + switch(field_type_){ + case one_field: + case true_field: + return 1; + case float_field: + return *(float*)value_; + case double_field: + return *(double*)value_; + case varint_field: + return pb_decode_varint(); + case svarint_field: + return -pb_decode_varint(); + case empty: + field_type_ = zero_field; + default: + return 0; + } + } + + void* get_value(){ + return value_; + } + + void set_value(void* value){ + value_ = value; + } + + field_type get_type() const{ + return field_type_; + } + + void set_null(){ + field_type_ = null_field; + } + + void set_type(field_type type){ + field_type_ = type; + } + + uint8_t get_varint_size(uint64_t value) const{ + uint8_t size = 1; + while(value>>=7) size++; + return size; + } + + void pb_encode_varint(uint64_t value) const + { + uint8_t count = 0; + do + { + uint8_t byte = (uint8_t)(value & 0x7F); + value >>= 7; + if(value) byte |= 0x80; + ((uint8_t*)value_)[count] = byte; + count++; + }while(value); + } + + uint64_t pb_decode_varint() const + { + if(value_==NULL) return 0; + uint64_t value = 0; + uint8_t pos = 0; + uint8_t byte = 0; + do{ + byte = ((uint8_t*)value_)[pos]; + value |= (uint64_t)(byte&0x7F) << pos*7; + pos++; + }while(byte>=0x80); + return value; + } + + private: + void* value_; + field_type field_type_; + + template<class T> + void set(T value) { + memcpy(allocate(sizeof(T)), &value, sizeof(T)); + } + }; + + class pson_pair{ + private: + char* name_; + pson value_; + public: + pson_pair() : name_(NULL){ + } + + ~pson_pair(){ + destroy(name_, pool); + } + + void set_name(const char *name) { + size_t name_size = strlen(name) + 1; + memcpy(allocate_name(name_size), name, name_size); + } + + char* allocate_name(size_t size){ + name_ = (char*)pool.allocate(size); + return name_; + } + + pson& value(){ + return value_; + } + + char* name() const{ + return name_; + } + }; + + class pson_object : public pson_container<pson_pair> { + public: + pson &operator[](const char *name) { + for(iterator it=begin(); it.valid(); it.next()){ + if(strcmp(it.item().name(), name)==0){ + return it.item().value(); + } + } + pson_pair & pair = create_item(); + pair.set_name(name); + return pair.value(); + }; + }; + + class pson_array : public pson_container<pson> { + public: + template<class T> + pson_array& add(T item_value){ + create_item() = item_value; + return *this; + } + }; + + inline pson::operator pson_object &() { + if (field_type_ != object_field) { + value_ = new(pool) pson_object; + field_type_ = object_field; + } + return *((pson_object *)value_); + } + + inline pson::operator pson_array &() { + if (field_type_ != array_field) { + value_ = new(pool) pson_array; + field_type_ = array_field; + } + return *((pson_array *)value_); + } + + inline pson &pson::operator[](const char *name) { + return ((pson_object &) *this)[name]; + } + + //////////////////////////// + /////// PSON_DECODER /////// + //////////////////////////// + + class pson_decoder { + + protected: + size_t read_; + + virtual bool read(void* buffer, size_t size){ + read_+=size; + return true; + } + + public: + + pson_decoder() : read_(0) { + + } + + void reset(){ + read_ = 0; + } + + size_t bytes_read(){ + return read_; + } + + bool pb_decode_tag(pb_wire_type& wire_type, uint32_t& field_number) + { + uint32_t temp = pb_decode_varint32(); + wire_type = (pb_wire_type)(temp & 0x07); + field_number = temp >> 3; + return true; + } + + uint32_t pb_decode_varint32() + { + uint32_t varint = 0; + if(try_pb_decode_varint32(varint)){ + return varint; + } + return 0; + } + + bool try_pb_decode_varint32(uint32_t& varint){ + varint = 0; + uint8_t byte; + uint8_t bit_pos = 0; + do{ + if(!read(&byte, 1) || bit_pos>=32){ + return false; + } + varint |= (uint32_t)(byte&0x7F) << bit_pos; + bit_pos += 7; + }while(byte>=0x80); + return true; + } + + uint64_t pb_decode_varint64() + { + uint64_t varint = 0; + uint8_t byte; + uint8_t bit_pos = 0; + do{ + if(!read(&byte, 1) || bit_pos>=64){ + return varint; + } + varint |= (uint32_t)(byte&0x7F) << bit_pos; + bit_pos += 7; + }while(byte>=0x80); + return varint; + } + + bool pb_skip(size_t size){ + uint8_t byte; + bool success = true; + for(size_t i=0; i<size; i++){ + success &= read(&byte, 1); + } + return success; + } + + bool pb_skip_varint(){ + uint8_t byte; + bool success = true; + do{ + success &= read(&byte, 1); + }while(byte>0x80); + return success; + } + + bool pb_read_string(char *str, size_t size){ + bool success = read(str, size); + str[size]=0; + return success; + } + + bool pb_read_varint(pson& value) + { + uint8_t temp[10]; + uint8_t byte=0; + uint8_t bytes_read=0; + do{ + if(!read(&byte, 1)) return false; + temp[bytes_read] = byte; + bytes_read++; + }while(byte>=0x80); + memcpy(value.allocate(bytes_read), temp, bytes_read); + return true; + } + + public: + + void decode(pson_object & object, size_t size){ + size_t start_read = bytes_read(); + while(size-(bytes_read()-start_read)>0){ + decode(object.create_item()); + } + } + + void decode(pson_array & array, size_t size){ + size_t start_read = bytes_read(); + while(size-(bytes_read()-start_read)>0){ + decode(array.create_item()); + } + } + + void decode(pson_pair & pair){ + uint32_t name_size = pb_decode_varint32(); + pb_read_string(pair.allocate_name(name_size+1), name_size); + decode(pair.value()); + } + + void decode(pson& value) { + uint32_t field_number; + pb_wire_type wire_type; + pb_decode_tag(wire_type, field_number); + value.set_type((pson::field_type)field_number); + if(wire_type==length_delimited){ + uint32_t size = pb_decode_varint32(); + switch(field_number){ + case pson::string_field: + pb_read_string((char*)value.allocate(size + 1), size); + break; + case pson::bytes_field: { + uint8_t varint_size = value.get_varint_size(size); + read((char*)value.allocate(size + varint_size) + varint_size, size); + value.pb_encode_varint(size); + } + break; + case pson::object_field: + value.set_value(new (pool) pson_object); + decode(*(pson_object *)value.get_value(), size); + break; + case pson::array_field: + value.set_value(new (pool) pson_array); + decode(*(pson_array *)value.get_value(), size); + break; + default: + pb_skip(size); + break; + } + }else { + switch (field_number) { + case pson::svarint_field: + case pson::varint_field: + pb_read_varint(value); + break; + case pson::float_field: + read(value.allocate(4), 4); + break; + case pson::double_field: + read(value.allocate(8), 8); + break; + default: + break; + } + } + } + }; + + //////////////////////////// + /////// PSON_ENCODER /////// + //////////////////////////// + + class pson_encoder { + + protected: + size_t written_; + + virtual void write(const void* buffer, size_t size){ + written_+=size; + } + + public: + + pson_encoder() : written_(0) { + } + + void reset(){ + written_ = 0; + } + + size_t bytes_written(){ + return written_; + } + + void pb_encode_tag(pb_wire_type wire_type, uint32_t field_number){ + uint64_t tag = ((uint64_t)field_number << 3) | wire_type; + pb_encode_varint(tag); + } + + void pb_encode_varint(uint32_t field, uint64_t value) + { + pb_encode_tag(varint, field); + pb_encode_varint(value); + } + + uint8_t pb_write_varint(void * buffer) + { + uint8_t byte=0; + uint8_t bytes_written=0; + do{ + byte = *((uint8_t*)buffer + bytes_written); + bytes_written++; + }while(byte>=0x80); + write(buffer, bytes_written); + return bytes_written; + } + + void pb_encode_varint(uint64_t value) + { + do + { + uint8_t byte = (uint8_t)(value & 0x7F); + value >>= 7; + if(value>0) byte |= 0x80; + write(&byte, 1); + }while(value>0); + } + + void pb_encode_string(const char* str, uint32_t field_number){ + pb_encode_tag(length_delimited, field_number); + pb_encode_string(str); + } + + void pb_encode_string(const char* str){ + size_t string_size = strlen(str); + pb_encode_varint(string_size); + write(str, string_size); + } + + template<class T> + void pb_encode_submessage(T& element, uint32_t field_number) + { + pb_encode_tag(length_delimited, field_number); + pson_encoder sink; + sink.encode(element); + pb_encode_varint(sink.bytes_written()); + encode(element); + } + + void pb_encode_fixed32(void* value){ + write(value, 4); + } + + void pb_encode_fixed64(void* value){ + write(value, 8); + } + + void pb_encode_fixed32(uint32_t field, void*value) + { + pb_encode_tag(fixed_32, field); + pb_encode_fixed32(value); + } + + void pb_encode_fixed64(uint32_t field, void*value) + { + pb_encode_tag(fixed_64, field); + pb_encode_fixed64(value); + } + + public: + + void encode(pson_object & object){ + pson_container<pson_pair>::iterator it = object.begin(); + while(it.valid()){ + encode(it.item()); + it.next(); + } + } + + void encode(pson_array & array){ + pson_container<pson>::iterator it = array.begin(); + while(it.valid()){ + encode(it.item()); + it.next(); + } + } + + void encode(pson_pair & pair){ + pb_encode_string(pair.name()); + encode(pair.value()); + } + + void encode(pson & value) { + switch (value.get_type()) { + case pson::string_field: + pb_encode_string((const char*)value.get_value(), pson::string_field); + break; + case pson::bytes_field: + pb_encode_tag(length_delimited, pson::bytes_field); + write(((const char *) value.get_value()) + pb_write_varint(value.get_value()), value.pb_decode_varint()); + break; + case pson::svarint_field: + case pson::varint_field: + pb_encode_tag(varint, value.get_type()); + pb_write_varint(value.get_value()); + break; + case pson::float_field: + pb_encode_fixed32(pson::float_field, value.get_value()); + break; + case pson::double_field: + pb_encode_fixed64(pson::double_field, value.get_value()); + break; + case pson::object_field: + pb_encode_submessage(*(pson_object *) value.get_value(), pson::object_field); + break; + case pson::array_field: + pb_encode_submessage(*(pson_array *) value.get_value(), pson::array_field); + break; + default: + pb_encode_tag(varint, value.get_type()); + break; + } + } + }; +} + +#endif \ No newline at end of file
--- a/thinger/thinger_decoder.hpp Fri Dec 25 18:21:02 2015 +0000 +++ b/thinger/thinger_decoder.hpp Sat Dec 26 13:18:01 2015 +0000 @@ -1,137 +1,125 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 THINGER LTD -// Author: alvarolb@gmail.com (Alvaro Luis Bustamante) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef THINGER_DECODER_HPP -#define THINGER_DECODER_HPP - -#include "pson.h" -#include "thinger_io.hpp" -#include "thinger_message.hpp" - -namespace thinger{ - - class thinger_decoder : public protoson::pson_decoder{ - public: - void decode(thinger_message& message, size_t size){ - size_t start_read = bytes_read(); - while(size-(bytes_read()-start_read)>0) { - protoson::pb_wire_type wire_type; - uint32_t field_number; - pb_decode_tag(wire_type, field_number); - switch (wire_type) { - case protoson::length_delimited:{ - uint32_t size = pb_decode_varint32(); - void *data = NULL; - switch (field_number) { - /* - case thinger_message::THING_ID: - data = protoson::pool.allocate(size + 1); - pb_read_string((char *) data, size); - message.set_thing_id((const char *) data); - break; - */ - default: - pb_skip(size); - break; - } - } - break; - case protoson::varint: { - switch (field_number) { - case thinger_message::SIGNAL_FLAG: - message.set_signal_flag((thinger_message::signal_flag)pb_decode_varint32()); - break; - case thinger_message::STREAM_ID: - message.set_stream_id(pb_decode_varint32()); - break; - default: - pb_skip_varint(); - break; - } - break; - } - case protoson::pson_type: - switch(field_number){ - case thinger_message::RESOURCE: - protoson::pson_decoder::decode(message.get_resources()); - break; - case thinger_message::PSON_PAYLOAD: - protoson::pson_decoder::decode(((protoson::pson&) message)); - break; - default: - break; - } - break; - case protoson::fixed_32: - pb_skip(4); - break; - case protoson::fixed_64: - pb_skip(8); - break; - default: - break; - } - } - } - }; - - class thinger_read_decoder : public thinger_decoder{ - public: - thinger_read_decoder(thinger_io& io) : io_(io) - {} - - protected: - virtual bool read(void* buffer, size_t size){ - io_.read((char*)buffer, size); - protoson::pson_decoder::read(buffer, size); - return true; - } - - private: - thinger_io& io_; - }; - - class thinger_memory_decoder : public thinger_decoder{ - - public: - thinger_memory_decoder(uint8_t* buffer, size_t size) : buffer_(buffer), size_(size){} - - protected: - virtual bool read(void* buffer, size_t size){ - if(read_+size<=size_){ - memcpy(buffer, buffer_ + read_, size); - return protoson::pson_decoder::read(buffer, size); - }else{ - return false; - } - } - - private: - uint8_t* buffer_; - size_t size_; - - }; - -} - -#endif +// The MIT License (MIT) +// +// Copyright (c) 2015 THINGER LTD +// Author: alvarolb@gmail.com (Alvaro Luis Bustamante) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef THINGER_DECODER_HPP +#define THINGER_DECODER_HPP + +#include "pson.h" +#include "thinger_io.hpp" +#include "thinger_message.hpp" + +namespace thinger{ + + class thinger_decoder : public protoson::pson_decoder{ + public: + void decode(thinger_message& message, size_t size){ + size_t start_read = bytes_read(); + while(size-(bytes_read()-start_read)>0) { + protoson::pb_wire_type wire_type; + uint32_t field_number; + pb_decode_tag(wire_type, field_number); + switch (wire_type) { + case protoson::length_delimited:{ + uint32_t size = pb_decode_varint32(); + pb_skip(size); + } + break; + case protoson::varint: { + switch (field_number) { + case thinger_message::SIGNAL_FLAG: + message.set_signal_flag((thinger_message::signal_flag)pb_decode_varint32()); + break; + case thinger_message::STREAM_ID: + message.set_stream_id(pb_decode_varint32()); + break; + default: + pb_skip_varint(); + break; + } + break; + } + case protoson::pson_type: + switch(field_number){ + case thinger_message::RESOURCE: + protoson::pson_decoder::decode(message.get_resources()); + break; + case thinger_message::PSON_PAYLOAD: + protoson::pson_decoder::decode(((protoson::pson&) message)); + break; + default: + break; + } + break; + case protoson::fixed_32: + pb_skip(4); + break; + case protoson::fixed_64: + pb_skip(8); + break; + default: + break; + } + } + } + }; + + class thinger_read_decoder : public thinger_decoder{ + public: + thinger_read_decoder(thinger_io& io) : io_(io) + {} + + protected: + virtual bool read(void* buffer, size_t size){ + io_.read((char*)buffer, size); + protoson::pson_decoder::read(buffer, size); + return true; + } + + private: + thinger_io& io_; + }; + + class thinger_memory_decoder : public thinger_decoder{ + + public: + thinger_memory_decoder(uint8_t* buffer, size_t size) : buffer_(buffer), size_(size){} + + protected: + virtual bool read(void* buffer, size_t size){ + if(read_+size<=size_){ + memcpy(buffer, buffer_ + read_, size); + return protoson::pson_decoder::read(buffer, size); + }else{ + return false; + } + } + + private: + uint8_t* buffer_; + size_t size_; + + }; + +} + +#endif \ No newline at end of file
--- a/thinger/thinger_resource.hpp Fri Dec 25 18:21:02 2015 +0000 +++ b/thinger/thinger_resource.hpp Sat Dec 26 13:18:01 2015 +0000 @@ -1,275 +1,281 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 THINGER LTD -// Author: alvarolb@gmail.com (Alvaro Luis Bustamante) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef THINGER_RESOURCE_HPP -#define THINGER_RESOURCE_HPP - -#include "thinger_map.hpp" -#include "pson.h" -#include "thinger_message.hpp" - -namespace thinger{ - - -class thinger_resource { - -public: - enum io_type { - none = 0, - run = 1, - pson_in = 2, - pson_out = 3, - pson_in_pson_out = 4 - }; - - enum access_type{ - PRIVATE = 0, - PROTECTED = 1, - PUBLIC = 2, - NONE = 3 - }; - - static int get_streaming_counter(){ - return streaming_count_; - } - -private: - - // calback for function, input, output, or input/output - union callback{ - void (*run)(); - void (*pson_in)(protoson::pson& in); - void (*pson_out)(protoson::pson& out); - void (*pson_in_pson_out)(protoson::pson& in, protoson::pson& out); - }; - - // used for defining the resource - io_type io_type_; - access_type access_type_; - callback callback_; - - // used for allowing resource streaming (both periodically or by events) - uint16_t stream_id_; - - // used for periodic stream events - unsigned long streaming_freq_; - unsigned long last_streaming_; - - // used to know the total number of streams - static unsigned int streaming_count_; - - // TODO change to pointer so it is not using more than a pointer size if not used? - thinger_map<thinger_resource> sub_resources_; - - void enable_streaming(uint16_t stream_id, unsigned long streaming_freq){ - stream_id_ = stream_id; - streaming_freq_ = streaming_freq; - last_streaming_ = 0; - streaming_count_++; - } - -public: - thinger_resource() : io_type_(none), access_type_(PRIVATE), stream_id_(0), streaming_freq_(0), last_streaming_(0) - {} - - void disable_streaming(){ - stream_id_ = 0; - streaming_freq_ = 0; - streaming_count_--; - } - - bool stream_enabled(){ - return stream_id_ > 0; - } - - uint32_t get_stream_id(){ - return stream_id_; - } - - bool stream_required(unsigned long timestamp){ - // sample interval is activated - if(streaming_freq_>0){ - if(timestamp-last_streaming_>=streaming_freq_){ - last_streaming_ = timestamp; - return true; - } - } - return false; - } - - thinger_resource * find(const char* res) - { - return sub_resources_.find(res); - } - - thinger_resource & operator[](const char* res){ - return sub_resources_[res]; - } - - thinger_resource & operator()(access_type type){ - access_type_ = type; - return *this; - } - - io_type get_io_type(){ - return io_type_; - } - - access_type get_access_type(){ - return access_type_; - } - - void fill_api(protoson::pson_object& content){ - if(io_type_!=none){ - content["al"] = access_type_; - content["fn"] = io_type_; - } - thinger_map<thinger_resource>::entry* current = sub_resources_.begin(); - if(current!=NULL){ - protoson::pson_object& actions = content["/"]; - do{ - current->value_.fill_api(actions[current->key_]); - current = current->next_; - }while(current!=NULL); - } - } - - void fill_api_io(protoson::pson_object& content){ - if(io_type_ == pson_in){ - callback_.pson_in(content["in"]); - }else if(io_type_ == pson_out){ - callback_.pson_out(content["out"]); - }else if(io_type_ == pson_in_pson_out){ - callback_.pson_in_pson_out(content["in"], content["out"]); - } - } - -public: - - /** - * Establish a function without input or output parameters - */ - void operator=(void (*run_function)()){ - io_type_ = run; - callback_.run = run_function; - } - - /** - * Establish a function without input or output parameters - */ - void set_function(void (*run_function)()){ - io_type_ = run; - callback_.run = run_function; - } - - /** - * Establish a function with input parameters - */ - void operator<<(void (*in_function)(protoson::pson& in)){ - io_type_ = pson_in; - callback_.pson_in = in_function; - } - - /** - * Establish a function with input parameters - */ - void set_input(void (*in_function)(protoson::pson& in)){ - io_type_ = pson_in; - callback_.pson_in = in_function; - } - - /** - * Establish a function that only generates an output - */ - void operator>>(void (*out_function)(protoson::pson& out)){ - io_type_ = pson_out; - callback_.pson_out = out_function; - } - - /** - * Establish a function that only generates an output - */ - void set_output(void (*out_function)(protoson::pson& out)){ - io_type_ = pson_out; - callback_.pson_out = out_function; - } - - /** - * Establish a function that can receive input parameters and generate an output - */ - void operator=(void (*pson_in_pson_out_function)(protoson::pson& in, protoson::pson& out)){ - io_type_ = pson_in_pson_out; - callback_.pson_in_pson_out = pson_in_pson_out_function; - } - - /** - * Establish a function that can receive input parameters and generate an output - */ - void set_input_output(void (*pson_in_pson_out_function)(protoson::pson& in, protoson::pson& out)){ - io_type_ = pson_in_pson_out; - callback_.pson_in_pson_out = pson_in_pson_out_function; - } - - /** - * Handle a request and fill a possible response - */ - void handle_request(thinger_message& request, thinger_message& response){ - switch(request.get_signal_flag()){ - // default action over the stream (run the resource) - case thinger_message::NONE: - switch (io_type_){ - case run: - callback_.run(); - break; - case pson_in: - callback_.pson_in(request); - break; - case pson_out: - callback_.pson_out(response); - break; - case pson_in_pson_out: - callback_.pson_in_pson_out(request, response); - break; - case none: - break; - } - break; - // flag for starting a resource stream - case thinger_message::START_STREAM: - enable_streaming(request.get_stream_id(), request.get_data()); - break; - // flat for stopping a resource stream - case thinger_message::STOP_STREAM: - disable_streaming(); - break; - default: - break; - } - } -}; - - unsigned int thinger_resource::streaming_count_ = 0; - -} - -#endif +// The MIT License (MIT) +// +// Copyright (c) 2015 THINGER LTD +// Author: alvarolb@gmail.com (Alvaro Luis Bustamante) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef THINGER_RESOURCE_HPP +#define THINGER_RESOURCE_HPP + +#include "thinger_map.hpp" +#include "pson.h" +#include "thinger_message.hpp" + +namespace thinger{ + + + class thinger_resource { + + public: + enum io_type { + none = 0, + run = 1, + pson_in = 2, + pson_out = 3, + pson_in_pson_out = 4 + }; + + enum access_type{ + PRIVATE = 0, + PROTECTED = 1, + PUBLIC = 2, + NONE = 3 + }; + + static int get_streaming_counter(){ + return streaming_count_; + } + + private: + + // calback for function, input, output, or input/output + union callback{ + void (*run)(); + void (*pson_in)(protoson::pson& in); + void (*pson_out)(protoson::pson& out); + void (*pson_in_pson_out)(protoson::pson& in, protoson::pson& out); + }; + + // used for defining the resource + io_type io_type_; + access_type access_type_; + callback callback_; + + // used for allowing resource streaming (both periodically or by events) + uint16_t stream_id_; + + // used for periodic stream events + unsigned long streaming_freq_; + unsigned long last_streaming_; + + // used to know the total number of streams + static unsigned int streaming_count_; + + // TODO change to pointer so it is not using more than a pointer size if not used? + thinger_map<thinger_resource> sub_resources_; + + void enable_streaming(uint16_t stream_id, unsigned long streaming_freq){ + stream_id_ = stream_id; + if(streaming_freq_==0 && streaming_freq>0){ + streaming_count_++; + }else if(streaming_freq_>0 && streaming_freq==0){ + streaming_count_--; + } + streaming_freq_ = streaming_freq; + last_streaming_ = 0; + } + + public: + thinger_resource() : io_type_(none), access_type_(PRIVATE), stream_id_(0), streaming_freq_(0), last_streaming_(0) + {} + + void disable_streaming(){ + stream_id_ = 0; + if(streaming_freq_>0){ + streaming_count_--; + } + streaming_freq_ = 0; + } + + bool stream_enabled(){ + return stream_id_ > 0; + } + + uint32_t get_stream_id(){ + return stream_id_; + } + + bool stream_required(unsigned long timestamp){ + // sample interval is activated + if(streaming_freq_>0){ + if(timestamp-last_streaming_>=streaming_freq_){ + last_streaming_ = timestamp; + return true; + } + } + return false; + } + + thinger_resource * find(const char* res) + { + return sub_resources_.find(res); + } + + thinger_resource & operator[](const char* res){ + return sub_resources_[res]; + } + + thinger_resource & operator()(access_type type){ + access_type_ = type; + return *this; + } + + io_type get_io_type(){ + return io_type_; + } + + access_type get_access_type(){ + return access_type_; + } + + void fill_api(protoson::pson_object& content){ + if(io_type_!=none){ + content["al"] = access_type_; + content["fn"] = io_type_; + } + thinger_map<thinger_resource>::entry* current = sub_resources_.begin(); + if(current!=NULL){ + protoson::pson_object& actions = content["/"]; + do{ + current->value_.fill_api(actions[current->key_]); + current = current->next_; + }while(current!=NULL); + } + } + + void fill_api_io(protoson::pson_object& content){ + if(io_type_ == pson_in){ + callback_.pson_in(content["in"]); + }else if(io_type_ == pson_out){ + callback_.pson_out(content["out"]); + }else if(io_type_ == pson_in_pson_out){ + callback_.pson_in_pson_out(content["in"], content["out"]); + } + } + + public: + + /** + * Establish a function without input or output parameters + */ + void operator=(void (*run_function)()){ + io_type_ = run; + callback_.run = run_function; + } + + /** + * Establish a function without input or output parameters + */ + void set_function(void (*run_function)()){ + io_type_ = run; + callback_.run = run_function; + } + + /** + * Establish a function with input parameters + */ + void operator<<(void (*in_function)(protoson::pson& in)){ + io_type_ = pson_in; + callback_.pson_in = in_function; + } + + /** + * Establish a function with input parameters + */ + void set_input(void (*in_function)(protoson::pson& in)){ + io_type_ = pson_in; + callback_.pson_in = in_function; + } + + /** + * Establish a function that only generates an output + */ + void operator>>(void (*out_function)(protoson::pson& out)){ + io_type_ = pson_out; + callback_.pson_out = out_function; + } + + /** + * Establish a function that only generates an output + */ + void set_output(void (*out_function)(protoson::pson& out)){ + io_type_ = pson_out; + callback_.pson_out = out_function; + } + + /** + * Establish a function that can receive input parameters and generate an output + */ + void operator=(void (*pson_in_pson_out_function)(protoson::pson& in, protoson::pson& out)){ + io_type_ = pson_in_pson_out; + callback_.pson_in_pson_out = pson_in_pson_out_function; + } + + /** + * Establish a function that can receive input parameters and generate an output + */ + void set_input_output(void (*pson_in_pson_out_function)(protoson::pson& in, protoson::pson& out)){ + io_type_ = pson_in_pson_out; + callback_.pson_in_pson_out = pson_in_pson_out_function; + } + + /** + * Handle a request and fill a possible response + */ + void handle_request(thinger_message& request, thinger_message& response){ + switch(request.get_signal_flag()){ + // default action over the stream (run the resource) + case thinger_message::NONE: + switch (io_type_){ + case run: + callback_.run(); + break; + case pson_in: + callback_.pson_in(request); + break; + case pson_out: + callback_.pson_out(response); + break; + case pson_in_pson_out: + callback_.pson_in_pson_out(request, response); + break; + case none: + break; + } + break; + // flag for starting a resource stream + case thinger_message::START_STREAM: + enable_streaming(request.get_stream_id(), request.get_data()); + break; + // flat for stopping a resource stream + case thinger_message::STOP_STREAM: + disable_streaming(); + break; + default: + break; + } + } + }; + + unsigned int thinger_resource::streaming_count_ = 0; + +} + +#endif \ No newline at end of file