Gloss certainly handles variable-size frames: the wiki even has a number of examples of the different built-in ways you can encode the size, and you can write a custom size-detector if none of those suit you. As for streams vs channels, my understanding is that the java.nio package Gloss uses was introduced as a higher-performance option compared to java.io. Like most people, I don't think I've ever really understood nio, but I suspect that Zack does and chose it for a reason.
My point is that Gloss is a fantastic library focused at exactly your problem domain, and you should probably do some more investigating before dismissing it as unsuitable (I infer you haven't done much research because you think it isn't focused and that it's not possible/ easy to handle variable-length arrays). For example, here's how to do your example with Gloss: (def codec (compile-frame {:type :uint32 :data (repeated :uint32 :prefix :uint32)})) (encode codec {:type 3 :data [1 2 3]}) ;=> (#<HeapByteBuffer java.nio.HeapByteBuffer[pos=0 lim=16 cap=16]> #<HeapByteBuffer java.nio.HeapByteBuffer[pos=0 lim=4 cap=4]>) (decode codec *1) ;=> {:type 3, :data [1 2 3]} If you really-really want the :size to be present in the Clojure data structures (rather than just ignoring it as an artifact of the protocol), you can do that by messing with a header in the codec. You can also make type an enum instead of just an int32, so that Gloss converts it into a meaningful keyword for you instead of having to deal with the number yourself. I ignored both of these issues for simplicity and due to my ignorance of your actual protocol. Perhaps more importantly than any of this, I suspect you're relying on the maps you use to retain their order - that is, you assume because you specify type, then size, then data, they will be encoded in that order. But maps are not sorted; it's only a coincidence that for small maps, on the current version of Clojure, they happen to be in the order you specified them. If you encoded a structure with ten or more fields, your library would suddenly break because the fields would be ordered wrong. For regular maps, Gloss sorts the maps alphabetically by key - in my example it encoded data before type. This is consistent across versions of Clojure and all map sizes (great!) but not what you actually want when you interoperate with C. So instead, Gloss allows you to give it a vector of pairs (or something like that), or a special map that promises to retain the order you specify. This is an example of the sort of tricky edge-case (or scalability issue) that would surely slip by me when implementing my own binary- encoding library, but which has already been addressed by Gloss. By choosing a mature and well-known library instead of making your own, you get more features and fewer bugs. On Feb 5, 4:09 pm, Russell Christopher <russell.christop...@gmail.com> wrote: > I did look at Gloss before writing Marshal and decided against using it in > our application suite, I wanted something more focused utilizing > InputStream/OutputStream interface and able to handle variable sized > arrays/strings (size of array or string specified in packet). > > On Sun, Feb 5, 2012 at 6:10 PM, Alan Malloy <a...@malloys.org> wrote: > > Zack Tellman's library Gloss is excellent for this, if a bit confusing > > to understand at first. > > > On Feb 5, 2:50 pm, russellc <russell.christop...@gmail.com> wrote: > > > I needed a library to handle marshaling application defined (C > > > struct) binary TCP/IP protocol packets in a Clojure client app > > > replacing a legacy C++ client and there didn't seem to be an existing > > > library that performed as I needed. So, I've written a Marshal library > > > that marshals from the network to/from Clojure. > > > > Github:http://github.com/russellc/Marshal > > > Clojars:https://clojars.org/marshal > > > > //C header file definition > > > struct packet { > > > unsigned long type; > > > unsigned long size; > > > long data[1]; > > > > }; > > > > (require '[marshal.core :as m]) > > > (def packet (m/struct :type m/uint32 :size m/uint32 :data (m/array m/ > > > sint32 :size))) > > > (m/write output-stream packet {:type 1 :size 2 :data [1 -1]}) > > > (m/read input-stream packet) > > > => {:type 1 :size 2 :data [1 -1]} > > > -- > > You received this message because you are subscribed to the Google > > Groups "Clojure" group. > > To post to this group, send email to clojure@googlegroups.com > > Note that posts from new members are moderated - please be patient with > > your first post. > > To unsubscribe from this group, send email to > > clojure+unsubscr...@googlegroups.com > > For more options, visit this group at > >http://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en