// Export visible API #include "cyson.h" #include #include #include #include #include #include #include #include #include #include #include namespace { template void safe_assign_string(TString& dest, T&& value) noexcept { try { dest = std::forward(value); } catch (...) { // Suppress exception } } } // anonymous namespace struct yson_reader { NYsonPull::NDetail::gen_reader_impl impl; TString error_message; yson_reader(NYsonPull::NInput::IStream* stream, NYsonPull::EStreamType mode) : impl(*stream, mode) { error_message.reserve(64); } yson_event_type safe_get_next_event() noexcept { try { auto& event = impl.next_event(); return static_cast(event.Type()); } catch (...) { safe_assign_string(error_message, CurrentExceptionMessage()); return YSON_EVENT_ERROR; } } }; struct yson_writer { THolder consumer; TString error_message; yson_writer(THolder consumer_) : consumer{std::move(consumer_)} { error_message.reserve(64); } template yson_writer_result safe_write(T&& func) noexcept { try { func(*consumer); return YSON_WRITER_RESULT_OK; } catch (const NYsonPull::NException::TBadOutput& err) { safe_assign_string(error_message, err.what()); return YSON_WRITER_RESULT_BAD_STREAM; } catch (...) { safe_assign_string(error_message, CurrentExceptionMessage()); return YSON_WRITER_RESULT_ERROR; } } }; namespace { class callback_error: public std::exception { public: const char* what() const noexcept override { return "User callback returned error result code"; } }; class c_yson_input_stream: public NYsonPull::NInput::IStream { void* ctx_; yson_input_stream_func callback_; public: c_yson_input_stream(void* ctx, yson_input_stream_func callback) : ctx_{ctx} , callback_{callback} { } protected: result do_fill_buffer() override { const char* ptr; size_t length; switch (callback_(ctx_, &ptr, &length)) { case YSON_INPUT_STREAM_RESULT_OK: buffer().reset( reinterpret_cast(ptr), reinterpret_cast(ptr) + length); return result::have_more_data; case YSON_INPUT_STREAM_RESULT_EOF: return result::at_end; default: case YSON_INPUT_STREAM_RESULT_ERROR: throw callback_error(); } } }; class c_yson_output_stream: public NYsonPull::NDetail::NOutput::TBuffered { using base_type = NYsonPull::NDetail::NOutput::TBuffered; void* ctx_; yson_output_stream_func callback_; public: c_yson_output_stream(void* ctx, yson_output_stream_func callback, size_t buffer_size) : base_type(buffer_size) , ctx_{ctx} , callback_{callback} { } void write(TStringBuf data) { switch (callback_(ctx_, data.data(), data.size())) { case YSON_OUTPUT_STREAM_RESULT_OK: return; default: case YSON_OUTPUT_STREAM_RESULT_ERROR: throw callback_error(); } } }; // Type marshalling const yson_string* to_yson_string(const NYsonPull::TScalar& value) { assert(value.Type() == NYsonPull::EScalarType::String); auto* result = &value.AsUnsafeValue().AsString; return reinterpret_cast(result); } yson_input_stream* to_yson_input_stream(NYsonPull::NInput::IStream* ptr) { return reinterpret_cast(ptr); } NYsonPull::NInput::IStream* from_yson_input_stream(yson_input_stream* ptr) { return reinterpret_cast(ptr); } yson_output_stream* to_yson_output_stream(NYsonPull::NOutput::IStream* ptr) { return reinterpret_cast(ptr); } NYsonPull::NOutput::IStream* from_yson_output_stream(yson_output_stream* ptr) { return reinterpret_cast(ptr); } // Exception-handling new/delete wrappers template T* safe_new(Args&&... args) noexcept { try { return new T(std::forward(args)...); } catch (...) { return nullptr; } } template void safe_delete(T* ptr) noexcept { assert(ptr != nullptr); try { delete ptr; } catch (...) { // Suppress destructor exceptions } } template yson_writer* safe_new_writer(yson_output_stream* stream, Args&&... args) noexcept { try { auto impl = MakeHolder( *from_yson_output_stream(stream), std::forward(args)...); return new yson_writer(std::move(impl)); } catch (...) { return nullptr; } } } // anonymous namespace extern "C" { // Input stream yson_input_stream* yson_input_stream_from_string(const char* ptr, size_t length) { auto buf = TStringBuf{ptr, length}; auto* result = safe_new>(buf); return to_yson_input_stream(result); } yson_input_stream* yson_input_stream_from_file(FILE* file, size_t buffer_size) { auto* result = safe_new(file, buffer_size); return to_yson_input_stream(result); } yson_input_stream* yson_input_stream_from_fd(int fd, size_t buffer_size) { auto* result = safe_new(fd, buffer_size); return to_yson_input_stream(result); } yson_input_stream* yson_input_stream_new(void* ctx, yson_input_stream_func callback) { auto* result = safe_new(ctx, callback); return to_yson_input_stream(result); } void yson_input_stream_delete(yson_input_stream* stream) { assert(stream != nullptr); safe_delete(from_yson_input_stream(stream)); } // Reader yson_reader* yson_reader_new(yson_input_stream* stream, yson_stream_type mode) { assert(stream != nullptr); return safe_new( from_yson_input_stream(stream), static_cast(mode)); } void yson_reader_delete(yson_reader* reader) { assert(reader != nullptr); safe_delete(reader); } yson_event_type yson_reader_get_next_event(yson_reader* reader) { assert(reader != nullptr); return reader->safe_get_next_event(); } const char* yson_reader_get_error_message(yson_reader* reader) { assert(reader != nullptr); return reader->error_message.c_str(); } yson_scalar_type yson_reader_get_scalar_type(yson_reader* reader) { assert(reader != nullptr); auto& event = reader->impl.last_event(); return static_cast(event.AsScalar().Type()); } int yson_reader_get_boolean(yson_reader* reader) { assert(reader != nullptr); auto& event = reader->impl.last_event(); return static_cast(event.AsScalar().AsBoolean()); } i64 yson_reader_get_int64(yson_reader* reader) { assert(reader != nullptr); auto& event = reader->impl.last_event(); return event.AsScalar().AsInt64(); } ui64 yson_reader_get_uint64(yson_reader* reader) { assert(reader != nullptr); auto& event = reader->impl.last_event(); return event.AsScalar().AsUInt64(); } double yson_reader_get_float64(yson_reader* reader) { assert(reader != nullptr); auto& event = reader->impl.last_event(); return event.AsScalar().AsFloat64(); } const yson_string* yson_reader_get_string(yson_reader* reader) { assert(reader != nullptr); return to_yson_string(reader->impl.last_event().AsScalar()); } // Output stream yson_output_stream* yson_output_stream_from_file(FILE* file, size_t buffer_size) { auto* result = safe_new(file, buffer_size); return to_yson_output_stream(result); } yson_output_stream* yson_output_stream_from_fd(int fd, size_t buffer_size) { auto* result = safe_new(fd, buffer_size); return to_yson_output_stream(result); } yson_output_stream* yson_output_stream_new(void* ctx, yson_output_stream_func callback, size_t buffer_size) { auto* result = safe_new(ctx, callback, buffer_size); return to_yson_output_stream(result); } void yson_output_stream_delete(yson_output_stream* stream) { assert(stream != nullptr); safe_delete(from_yson_output_stream(stream)); } // Writer yson_writer* yson_writer_new_binary(yson_output_stream* stream, yson_stream_type mode) { assert(stream != nullptr); return safe_new_writer( stream, static_cast(mode)); } yson_writer* yson_writer_new_text(yson_output_stream* stream, yson_stream_type mode) { assert(stream != nullptr); return safe_new_writer( stream, static_cast(mode)); } yson_writer* yson_writer_new_pretty_text(yson_output_stream* stream, yson_stream_type mode, size_t indent) { assert(stream != nullptr); return safe_new_writer( stream, static_cast(mode), indent); } void yson_writer_delete(yson_writer* writer) { assert(writer != nullptr); safe_delete(writer); } const char* yson_writer_get_error_message(yson_writer* writer) { assert(writer != nullptr); return writer->error_message.c_str(); } yson_writer_result yson_writer_write_begin_stream(yson_writer* writer) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnBeginStream(); }); } yson_writer_result yson_writer_write_end_stream(yson_writer* writer) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnEndStream(); }); } yson_writer_result yson_writer_write_begin_list(yson_writer* writer) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnBeginList(); }); } yson_writer_result yson_writer_write_end_list(yson_writer* writer) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnEndList(); }); } yson_writer_result yson_writer_write_begin_map(yson_writer* writer) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnBeginMap(); }); } yson_writer_result yson_writer_write_end_map(yson_writer* writer) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnEndMap(); }); } yson_writer_result yson_writer_write_begin_attributes(yson_writer* writer) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnBeginAttributes(); }); } yson_writer_result yson_writer_write_end_attributes(yson_writer* writer) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnEndAttributes(); }); } yson_writer_result yson_writer_write_entity(yson_writer* writer) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnEntity(); }); } yson_writer_result yson_writer_write_key(yson_writer* writer, const char* ptr, size_t length) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnKey({ptr, length}); }); } yson_writer_result yson_writer_write_string(yson_writer* writer, const char* ptr, size_t length) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnScalarString({ptr, length}); }); } yson_writer_result yson_writer_write_int64(yson_writer* writer, i64 value) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnScalarInt64(value); }); } yson_writer_result yson_writer_write_uint64(yson_writer* writer, ui64 value) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnScalarUInt64(value); }); } yson_writer_result yson_writer_write_boolean(yson_writer* writer, int value) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnScalarBoolean(static_cast(value)); }); } yson_writer_result yson_writer_write_float64(yson_writer* writer, double value) { assert(writer != nullptr); return writer->safe_write([=](NYsonPull::IConsumer& consumer) { consumer.OnScalarFloat64(value); }); } } // extern "C"