diff --git a/docs/src/api.md b/docs/src/api.md
index 6331983141aafa297596a060d5dca08f32d5a640..442f880cc0a2e0dfe736bbbc4d9374b7a0b9d65c 100644
--- a/docs/src/api.md
+++ b/docs/src/api.md
@@ -150,6 +150,8 @@ getevent
 categorize
 nthbitset
 most_frequent
+packedsize
+writestruct
 ```
 
 ### DAQ
diff --git a/src/daq.jl b/src/daq.jl
index d2f9981fd1340b50c7fa8a2a1f81525cd45d449e..de1802a18350ba80766525a1c502da6109204436 100644
--- a/src/daq.jl
+++ b/src/daq.jl
@@ -52,3 +52,9 @@ function Base.read(s::IO, ::Type{T}; legacy=false) where T<:DAQEvent
 
     T(header, snapshot_hits, triggered_hits)
 end
+
+function Base.write(io::IO, s::Summaryslice)
+    # write(io, Int32(size?))
+    # write(io, Int32(DAQDATATYPES.DAQSUMMARYSLICE))
+    writestruct(io, s.header)
+end
diff --git a/src/exports.jl b/src/exports.jl
index d531fdf6e0152b0c85b66e1bfff6ef14d39fd382..31b22e097b276a3d35cf9ce932618cdbdb49ac81 100644
--- a/src/exports.jl
+++ b/src/exports.jl
@@ -130,6 +130,10 @@ MCEventMatcher,
 SummarysliceIntervalIterator,
 getevent,
 
+# I/O
+packedsize,
+writestruct,
+
 # Utils
 categorize,
 is3dmuon,
diff --git a/src/tools/general.jl b/src/tools/general.jl
index 06ada871d38eb4986d07a3fe54cfd831406ab697..e646579191744bbd576428b49dbf94068516198e 100644
--- a/src/tools/general.jl
+++ b/src/tools/general.jl
@@ -109,3 +109,42 @@ function tonumifpossible(v::AbstractString)
     end
     v
 end
+
+
+"""
+Calculates the packed size in bytes of an immutable struct containing only
+primitives and other isbitstypes.
+"""
+function packedsize(dt::DataType)
+    isbitstype(dt) || error("Only isbits types are supported")
+    n = 0
+    for ftype in fieldtypes(dt)
+        if isprimitivetype(ftype)
+            n += sizeof(ftype)
+        else
+            n += packedsize(ftype)
+        end
+    end
+    n
+end
+packedsize(::T) where T = packedsize(T)
+
+
+"""
+Serialises an immutable struct containing only primitives and
+other isbitstypes. Returns the number of bytes written.
+"""
+function writestruct(io::IO, s::T) where T
+    isbitstype(T) || error("Only isbits types are supported")
+    n = 0
+    for fname in fieldnames(T)
+        v = getfield(s, fname)
+        if isprimitivetype(fieldtype(T, fname))
+            write(io, v)
+            n += sizeof(v)
+        else
+            n += writestruct(io, v)
+        end
+    end
+    n
+end