aboutsummaryrefslogtreecommitdiff
path: root/julia/CrystFEL/src/streams.jl
blob: d5c86464f60ec6a09b4037fd80f7cb07c7b5f4fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
module Streams

import ..CrystFEL: libcrystfel
import ..CrystFEL.DataTemplates: DataTemplate, InternalDataTemplate
import ..CrystFEL.Images: Image, InternalImage
export Stream, chunkwrite, chunkread

# Represents the real C-side (opaque) structure.
mutable struct InternalStream end

# The Julia-side structure, needed to house the pointer to the C structure
mutable struct Stream
    internalptr::Ptr{InternalStream}
end


"""
    Stream(filename, "w", dtempl)

Opens a CrystFEL stream for writing.  Note that you must provide a `DataTemplate`,
which is needed to translate "panel coordinates" to "file coordinates".

Corresponds to CrystFEL C API routine `stream_open_for_write`.
"""
function Stream(filename, mode::AbstractString, dtempl::DataTemplate)

    if mode == "w"
        out = @ccall libcrystfel.stream_open_for_write(filename::Cstring,
                               dtempl.internalptr::Ptr{InternalDataTemplate})::Ptr{InternalStream}
        if out == C_NULL
            throw(ErrorException("Failed to open stream for reading"))
        end

        @ccall libcrystfel.stream_write_data_template(out::Ptr{InternalStream},
                               dtempl.internalptr::Ptr{InternalDataTemplate})::Cvoid

        finalizer(close, Stream(out))

    elseif mode =="r"
        throw(ArgumentError("To open a stream for reading, don't provide the DataTemplate"))

    else
        throw(ArgumentError("Unrecognised CrystFEL stream mode"*mode))
    end
end


"""
    Stream(filename, "r")

Opens a CrystFEL stream for reading.

Close the stream with `close` when you've finished (this will happen
automatically when the `Stream` object is finalized).

Corresponds to CrystFEL C API routine `stream_open_for_read`.
"""
function Stream(filename, mode::AbstractString)

    if mode == "r"
        out = @ccall libcrystfel.stream_open_for_read(filename::Cstring)::Ptr{InternalStream}
        if out == C_NULL
            throw(ErrorException("Failed to open stream for reading"))
        end
        finalizer(close, Stream(out))

    elseif mode == "w"
        throw(ArgumentError("To open a stream for writing, you must provide "
                            *"a DataTemplate: use Stream(filename, \"w\", dtempl)"))

    else
        throw(ArgumentError("Unrecognised CrystFEL stream mode"*mode))
    end
end


function Base.close(st::Stream)
    if st.internalptr != C_NULL
        @ccall libcrystfel.stream_close(st.internalptr::Ptr{InternalStream})::Cvoid
        st.internalptr = C_NULL
    end
end


function streamflags(peaks, reflections, imagedata)
    flags = 0
    if reflections
        flags |= 2
    end
    if peaks
        flags |= 4
    end
    if imagedata
        flags |= 8
    end
    return flags
end


function chunkwrite(st::Stream, image::Image; peaks=true, reflections=true)
    st.internalptr == C_NULL && throw(ErrorException("Stream is closed"))
    flags = streamflags(peaks, reflections, false)
    @ccall libcrystfel.stream_write_chunk(st.internalptr::Ptr{InternalStream},
                                          image.internalptr::Ptr{InternalImage},
                                          flags::Cint)::Cvoid
end


function chunkread(st::Stream; peaks=true, reflections=true)

    st.internalptr == C_NULL && throw(ErrorException("Stream is closed"))

    flags = streamflags(peaks, reflections, true)
    out = @ccall libcrystfel.stream_read_chunk(st.internalptr::Ptr{InternalStream},
                                               flags::Cint)::Ptr{InternalImage}
    out == C_NULL && return nothing

    finalizer(Image(out, nothing, [], [])) do x
        ccall((:image_free, libcrystfel), Cvoid, (Ptr{InternalImage},), x.internalptr)
    end

end


end  # of module