Thinger.io Client Library for ARM mbed platform. This is a generic library that provides a base class that can be used to other develop hardware specific libraries.
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