#pragma once #include #include #include "data.hpp" #include "stream_value.hpp" namespace saw { namespace encode { struct Csv {}; } namespace impl { struct csv_helper { static bool is_whitespace(int8_t ch){ /** * @TODO supply relevant control characters for checks. * Newlines are whitespace technically, but also control characters in CSV. * Contrary to JSON for example. */ return ch == '\t' || ch == ' '; } static void skip_whitespace(buffer_view& buff){ while(buff.read_composite_length() > 0 && csv_helper::is_whitespace(buff.read())){ buff.read_advance(1u); } } }; template struct csv_encode { static_assert(always_false, "Case not supported"); }; template struct csv_encode, FromDecode> { static_assert(Dim == 1, "Only one dimension is allowed."); static_assert(!is_array::value, "Array of an array is not allowed."); static_assert(is_tuple::value || is_struct::value, "Only struct or tuples allowed inside a csv array"); using Schema = schema::Array; static error_or encode(const data& from, buffer& to){ if constexpr (is_struct::value){ auto eov = csv_encode::encode_header(to); if(eov.is_error()){ return eov; } } for(data i = 0; i < from.size(); ++i){ auto eov = csv_encode::encode(from.at(i), to); if(eov.is_error()){ return eov; } } return void_t{}; } }; template struct csv_encode...>, FromDecode> { using Schema = schema::Struct...>; template static error_or encode_header_i(buffer& to){ // Encode string // constexpr auto str_view = parameter_key_pack_type::literal; for(auto& iter : str_view.view()){ auto eov = stream_value::encode(iter, to); if(eov.is_error()){ return eov; } } // Go to next string if constexpr ( (i+1) < sizeof...(K)){ /** * Replace this with col separator */ constexpr std::string_view lit = ","; for(int8_t iter : lit){ auto eov = stream_value::encode(iter, to); if(eov.is_error()){ return eov; } } return encode_header_i(to); } { /** * Replace this with row separator */ constexpr std::string_view lit = "\n"; for(int8_t iter : lit){ auto eov = stream_value::encode(iter, to); if ( eov.is_error()){ return eov; } } } return make_void(); } static error_or encode_header(buffer& to){ if constexpr (sizeof...(V) > 0u){ return encode_header_i<0u>(to); } return make_void(); } template static error_or encode_i(const data& from, buffer& to){ constexpr auto str_view = parameter_key_pack_type::literal; { auto eov = csv_encode::type, FromDecode>::encode(from.template get(), to); if(eov.is_error()){ return eov; } } if constexpr ( (i+1) < sizeof...(K)){ /** * Replace this with col separator */ constexpr std::string_view lit = ","; for(int8_t iter : lit){ auto eov = stream_value::encode(iter, to); if(eov.is_error()){ return eov; } } return encode_i(from, to); } { /** * Replace this with row separator */ constexpr std::string_view lit = "\r\n"; for(int8_t iter : lit){ auto eov = stream_value::encode(iter, to); if ( eov.is_error()){ return eov; } } } return make_void(); } static error_or encode(const data& from, buffer& to){ return encode_i<0>(from, to); } }; template struct csv_encode { using Schema = schema::String; static error_or encode(const data& from, buffer& to){ for(data i = 0; i < from.size(); ++i){ auto eov = stream_value::encode(from.at(i.get()), to); if(eov.is_error()){ return eov; } } return make_void(); } }; template struct csv_encode, FromDecode> { using Schema = schema::Primitive; static error_or encode(const data& from, buffer& to){ std::string to_str; try { to_str = std::to_string(from.get()); }catch(const std::exception& ){ return make_error(); } for(auto iter : to_str){ auto eov = stream_value::encode(iter, to); if(eov.is_error()){ return eov; } } return make_void(); } }; template struct csv_decode { static_assert(always_false, "Case not supported"); }; template struct csv_decode, FromDecode> { static_assert(Dim == 1, "Only one dimension is allowed."); static_assert(!is_array::value, "Array of an array is not allowed."); static_assert(is_tuple::value || is_struct::value, "Only struct or tuples allowed inside a csv array"); using Schema = schema::Array; static error_or decode(data& from, data& to){ buffer_view view{from.get_buffer()}; if constexpr (is_struct::value) { auto eov = csv_decode::check_header(view); if(eov.is_error()){ return eov; } } uint64_t len{}; return make_error(); } }; } template class data { private: own buffer_; public: data(): buffer_{heap()} {} data(own buffer__): buffer_{std::move(buffer__)} {} buffer& get_buffer(){ return *buffer_; } }; template class codec { static_assert(is_array::value, "Only an Array is allowed as a base value"); public: template static error_or encode(const data& from, data& to){ buffer_view buff_v{to.get_buffer()}; auto eov = impl::csv_encode::encode(from, buff_v); if(eov.is_error()){ return eov; } to.get_buffer().write_advance(buff_v.write_offset()); return eov; } template static error_or decode(data& from, data& to){ auto& buff = from.get_buffer(); buffer_view buff_v{buff}; auto eov = impl::csv_decode::decode(buff_v, to); if(eov.is_error()){ return eov; } buff.write_advance(buff_v.write_offset()); return eov; } }; }