Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streaming encoding #24

Open
letmaik opened this issue Jan 11, 2016 · 6 comments
Open

Streaming encoding #24

letmaik opened this issue Jan 11, 2016 · 6 comments
Assignees

Comments

@letmaik
Copy link

letmaik commented Jan 11, 2016

It would be nice if streaming encoding similar to Jackson is added. Important for me would be that I could stream the elements of a ByteString as well, since these form the major part of my payload.

@c-rack
Copy link
Owner

c-rack commented Jan 11, 2016

@neothemachine Basically, streaming encoding and decoding is already implemented. Could you please provide a small pseudo-code example what you want to achieve? Maybe I can help you to find the right direction; if not, I am sure we can find and implement a solution for your problem.

@letmaik
Copy link
Author

letmaik commented Jan 11, 2016

The README only has a "Streaming Decoding Example" and I checked the code of CborEncoder to see if it has some kind of streaming interface but couldn't find anything.

new CborEncoder(outputstream).stream()
    .add("text")                // add string
    .add(1234)                  // add integer
    .add(new byte[] { 0x10 })   // add byte array
    .addArray()                 // add array
        .add(1)
        .add("text")
        .end()
    .close();

Something like that.

@c-rack
Copy link
Owner

c-rack commented Jan 11, 2016

OK, it is already there but not with a nice DSL as described. You could transform the example above to (free coded, not checked with IDE):

CborEncoder encoder = new CborEncoder(outputstream);
encoder.encode(new UnicodeString("text"));
encoder.encode(new UnsignedInteger(1234));
encoder.encode(new ByteString(new byte[] { 0x10 }));
encoder.encode(new Array().setChunked()); // start array
encoder.encode(new UnsignedInteger(1));
encoder.encode(new UnicodeString("text"));
encoder.encode(Special.BREAK); // close array
outputstream.close();

A more developer-friendly DSL would be much better, of course.

@letmaik
Copy link
Author

letmaik commented Jan 11, 2016

I see. It seems natural to me to want to use the CborBuilder as such a DSL. So CborBuilder could be made into an interface where one implementation is the current builder class and the other directly writes to a CborEncoder instance (where the relations could be set up by my proposed .stream() call).

@c-rack
Copy link
Owner

c-rack commented Jan 11, 2016

Good idea! Allow me some time to implement this.

@c-rack c-rack self-assigned this Jan 11, 2016
@letmaik
Copy link
Author

letmaik commented Jan 11, 2016

In parallel I am implementing a generic streaming interface that I can use both with Jackson and cbor-java and which is supposed to be compatible to both, meaning which I can easily write adapters for. I think some things in CborBuilder are actually too much for a streaming interface, so maybe this has to be split in two interfaces or so.

For reference, this is what I currently got (targeted to my use case):

/**
 * A streaming encoder interface for JSON-compatible object structures
 * with additional hints for more advanced formats like CBOR encoders.
 * 
 * This interface is a mix of cbor-java's CborBuilder and Jackson's Streaming API,
 * with the goal of being compatible to both and being able to write
 * simple adapters for them.
 *  
 * @author Maik Riechert
 */
public interface StreamingEncoder {
    class ArrayHints {
        private final Long size;
        private final Class<Number> type;
        /**
         * 
         * @param size can be null
         * @param type can be null
         */
        public ArrayHints(Long size, Class<Number> type) {
            this.size = size;
            this.type = type;
        }
        boolean hasSize() {
            return size != null;
        }
        long getSize() {
            return size;
        }
        boolean hasType() {
            return type != null;
        }
        Class<Number> getType() {
            return type;
        }
    }

    interface ArrayEncoder <T> {
        ArrayEncoder<T> add(String value) throws IOException;
        ArrayEncoder<T> add(boolean value) throws IOException;
        ArrayEncoder<T> add(int value) throws IOException;
        ArrayEncoder<T> add(long value) throws IOException;
        ArrayEncoder<T> add(float value) throws IOException;
        ArrayEncoder<T> add(double value) throws IOException;
        ArrayEncoder<ArrayEncoder<T>> startArray() throws IOException;
        ArrayEncoder<ArrayEncoder<T>> startArray(ArrayHints hints) throws IOException;
        MapEncoder<ArrayEncoder<T>> startMap() throws IOException;
        T end() throws IOException;
    }

    interface MapEncoder <T> {
        MapEncoder<T> put(String key, String value) throws IOException;
        MapEncoder<T> put(String key, boolean value) throws IOException;
        MapEncoder<T> put(String key, int value) throws IOException;
        MapEncoder<T> put(String key, long value) throws IOException;
        MapEncoder<T> put(String key, float value) throws IOException;
        MapEncoder<T> put(String key, double value) throws IOException;
        ArrayEncoder<MapEncoder<T>> startArray(String key) throws IOException;
        ArrayEncoder<MapEncoder<T>> startArray(String key, ArrayHints hints) throws IOException;
        MapEncoder<MapEncoder<T>> startMap(String key) throws IOException;
        T end() throws IOException;
    }

    MapEncoder<StreamingEncoder> startMap() throws IOException;

    void end() throws IOException;

    // at the root level we only support Maps for now.  
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants