Skip to content

Commit

Permalink
Merge pull request #119 from JuliaIO/kf/setproperty
Browse files Browse the repository at this point in the history
Use setproperty! rather than set_field!
  • Loading branch information
tanmaykm authored Oct 27, 2018
2 parents 06a932a + 1132a4d commit 5d267b7
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 37 deletions.
14 changes: 6 additions & 8 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,9 @@ meta(t::Type{MyType}) = meta(t, [], [8,10], Dict())
````

## Setting and Getting Fields
Types used as protocol buffer structures are regular Julia types and the Julia syntax to set and get fields can be used on them. But with fields that are set as optional, it is quite likely that some of them may not have been present in the instance that was read. Similarly, fields that need to be sent need to be explicitly marked as being set. The following methods are exported to assist doing this:
Types used as protocol buffer structures are regular Julia types and the Julia syntax to set and get fields can be used on them. But with fields that are set as optional, it is quite likely that some of them may not have been present in the instance that was read. The following methods are exported to assist doing this:

- `get_field(obj::Any, fld::Symbol)` : Gets `obj.fld` if it has been set. Throws an error otherwise.
- `set_field!(obj::Any, fld::Symbol, val)` : Sets `obj.fld = val` and marks the field as being set. The value would be written on the wire when `obj` is serialized. Fields can also be set the regular way, but then they must be marked as being set using the `fillset` method.
- `add_field!(obj::Any, fld::Symbol, val)` : Adds an element with value `val` to a repeated field `fld`. Essentially appends `val` to the array `obj.fld`.
- `has_field(obj::Any, fld::Symbol)` : Checks whether field `fld` has been set in `obj`.
- `clear(obj::Any, fld::Symbol)` : Marks field `fld` of `obj` as unset.
- `clear(obj::Any)` : Marks all fields of `obj` as unset.
Expand All @@ -63,14 +61,14 @@ Types generated through the Julia protoc plugin generates constructors that use
````
julia> using ProtoBuf
julia> mutable struct MyType # a Julia composite type
julia> mutable struct MyType <: ProtoType # a Julia composite type
intval::Int
# fillunset (documented below is similar to clear)
# ProtoBuf._protobuild is an internal method similar to protobuild
MyType(; kwargs...) = (o=new(); fillunset(o); isempty(kwargs) || ProtoBuf._protobuild(o, kwargs); o)
end
julia> mutable struct OptType # and another one to contain it
julia> mutable struct OptType <: ProtoType # and another one to contain it
opt::MyType
OptType(; kwargs...) = (o=new(); fillunset(o); isempty(kwargs) || ProtoBuf._protobuild(o, kwargs); o)
end
Expand Down Expand Up @@ -102,11 +100,11 @@ julia> using ProtoBuf
julia> import ProtoBuf.meta
julia> mutable struct TestType
julia> mutable struct TestType <: ProtoType
val::Any
end
julia> mutable struct TestFilled
julia> mutable struct TestFilled <: ProtoType
fld1::TestType
fld2::TestType
TestFilled(; kwargs...) = (o=new(); fillunset(o); isempty(kwargs) || ProtoBuf._protobuild(o, kwargs); o)
Expand All @@ -120,7 +118,7 @@ TestFilled(#undef,#undef)
julia> isinitialized(tf) # false, since fld1 is not set
false
julia> set_field!(tf, :fld1, TestType(""))
julia> tf.fld1 = TestType("");
julia> isinitialized(tf) # true, even though fld2 is not set yet
true
Expand Down
8 changes: 4 additions & 4 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

isinitialized(obj::Any) = isfilled(obj)

set_field!(obj::Any, fld::Symbol, val) = (setfield!(obj, fld, val); fillset(obj, fld); nothing)
@deprecate set_field(obj::Any, fld::Symbol, val) set_field!(obj, fld, val)
Base.setproperty!(obj::ProtoType, fld::Symbol, val) = (Core.setfield!(obj, fld, val); fillset(obj, fld); val)
@deprecate set_field!(obj::Any, fld::Symbol, val) setproperty!(obj, fld, val)

get_field(obj::Any, fld::Symbol) = isfilled(obj, fld) ? getfield(obj, fld) : error("uninitialized field $fld")

Expand All @@ -18,7 +18,7 @@ function copy!(to::T, from::T) where T <: ProtoType
for idx in 1:length(fnames)
if fill[1, idx]
name = fnames[idx]
set_field!(to, name, getfield(from, name))
setproperty!(to, name, getfield(from, name))
end
end
nothing
Expand All @@ -44,7 +44,7 @@ protobuild(::Type{T}, nv::Dict{Symbol}=Dict{Symbol,Any}()) where {T} = _protobui
function _protobuild(obj::T, nv) where T
for (n,v) in nv
fldtyp = fld_type(obj, n)
set_field!(obj, n, isa(v, fldtyp) ? v : convert(fldtyp, v))
setproperty!(obj, n, isa(v, fldtyp) ? v : convert(fldtyp, v))
end
obj
end
Expand Down
16 changes: 8 additions & 8 deletions test/services/testsvc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ mutable struct TestRpcChannel <: ProtoRpcChannel
end
close(channel::TestRpcChannel) = close(channel.sock)

mutable struct SvcHeader
mutable struct SvcHeader <: ProtoType
method::String
SvcHeader() = (o=new(); fillunset(o); o)
end

function write_request(channel::TestRpcChannel, controller::TestRpcController, service::ServiceDescriptor, method::MethodDescriptor, request)
io = channel.sock
hdr = SvcHeader()
set_field!(hdr, :method, method.name)
hdr.method = method.name

iob = IOBuffer()

Expand Down Expand Up @@ -119,13 +119,13 @@ end
# implementations of our test services
function Add(req::BinaryOpReq)
resp = BinaryOpResp()
set_field!(resp, :result, req.i1 + req.i2)
resp.result = req.i1 + req.i2
resp
end

function Mul(req::BinaryOpReq)
resp = BinaryOpResp()
set_field!(resp, :result, req.i1 * req.i2)
resp.result = req.i1 * req.i2
resp
end

Expand Down Expand Up @@ -164,8 +164,8 @@ function run_client(debug::Bool)
let channel=TestRpcChannel(connect(9999)), stub=TestMathBlockingStub(channel)
for i in 1:10
inp = BinaryOpReq()
set_field!(inp, :i1, Int64(rand(Int8)))
set_field!(inp, :i2, Int64(rand(Int8)))
inp.i1 = Int64(rand(Int8))
inp.i2 = Int64(rand(Int8))

out = Add(stub, controller, inp)
chk_results(out, inp.i1+inp.i2)
Expand All @@ -179,8 +179,8 @@ function run_client(debug::Bool)
debug_log(controller, "testing non blocking stub...")
for i in 1:10
inp = BinaryOpReq()
set_field!(inp, :i1, Int64(rand(Int8)))
set_field!(inp, :i2, Int64(rand(Int8)))
inp.i1 = Int64(rand(Int8))
inp.i2 = Int64(rand(Int8))

nresults -= 1
let channel=TestRpcChannel(connect(9999)), stub=TestMathStub(channel), expected=inp.i1+inp.i2
Expand Down
4 changes: 2 additions & 2 deletions test/services/testsvc_pb.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ using ProtoBuf
import ProtoBuf.meta
import Base: hash, isequal, ==

mutable struct BinaryOpReq
mutable struct BinaryOpReq <: ProtoType
i1::Int64
i2::Int64
BinaryOpReq(; kwargs...) = (o=new(); fillunset(o); isempty(kwargs) || ProtoBuf._protobuild(o, kwargs); o)
Expand All @@ -12,7 +12,7 @@ hash(v::BinaryOpReq) = ProtoBuf.protohash(v)
isequal(v1::BinaryOpReq, v2::BinaryOpReq) = ProtoBuf.protoisequal(v1, v2)
==(v1::BinaryOpReq, v2::BinaryOpReq) = ProtoBuf.protoeq(v1, v2)

mutable struct BinaryOpResp
mutable struct BinaryOpResp <: ProtoType
result::Int64
BinaryOpResp(; kwargs...) = (o=new(); fillunset(o); isempty(kwargs) || ProtoBuf._protobuild(o, kwargs); o)
end #type BinaryOpResp
Expand Down
20 changes: 10 additions & 10 deletions test/testcodec.jl
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ function test_nested()

writeproto(pb, testval, meta)
readfld2.iVal2 = Int64[]
readval.fld3 = TestType[]
readval.fld3 = TestStr[]
readproto(pb, readval, meta)

assert_equal(testval, readval)
Expand Down Expand Up @@ -363,19 +363,19 @@ function test_oneofs()
@test isfilled(testval, :iVal3)
@test which_oneof(testval, :optval) === :iVal3

set_field!(testval, :iVal2, 10)
testval.iVal2 = 10
@test isfilled(testval, :iVal1)
@test isfilled(testval, :iVal2)
@test !isfilled(testval, :iVal3)
@test which_oneof(testval, :optval) === :iVal2

set_field!(testval, :iVal1, 10)
testval.iVal1 = 10
@test isfilled(testval, :iVal1)
@test isfilled(testval, :iVal2)
@test !isfilled(testval, :iVal3)
@test which_oneof(testval, :optval) === :iVal2

set_field!(testval, :iVal3, 10)
testval.iVal3 = 10
@test isfilled(testval, :iVal1)
@test !isfilled(testval, :iVal2)
@test isfilled(testval, :iVal3)
Expand All @@ -394,28 +394,28 @@ function test_maps()

testval = TestMaps()
readval = TestMaps()
set_field!(testval, :d1, Dict{Int,Int}())
testval.d1 = Dict{Int,Int}()
writeproto(pb, testval)
readproto(pb, readval)
@test !isfilled(readval, :d1)

testval = TestMaps()
readval = TestMaps()
set_field!(testval, :d2, Dict{Int32,String}())
testval.d2 = Dict{Int32,String}()
writeproto(pb, testval)
readproto(pb, readval)
@test !isfilled(readval, :d2)

testval = TestMaps()
readval = TestMaps()
set_field!(testval, :d3, Dict{String,String}())
testval.d3 = Dict{String,String}()
writeproto(pb, testval)
readproto(pb, readval)
@test !isfilled(readval, :d3)

testval = TestMaps()
readval = TestMaps()
set_field!(testval, :d1, Dict{Int,Int}())
testval.d1 = Dict{Int,Int}()
testval.d1[1] = 1
testval.d1[2] = 2
writeproto(pb, testval)
Expand All @@ -425,7 +425,7 @@ function test_maps()

testval = TestMaps()
readval = TestMaps()
set_field!(testval, :d2, Dict{Int32,String}())
testval.d2 = Dict{Int32,String}()
testval.d2[Int32(1)] = convert(String, "One")
testval.d2[Int32(2)] = convert(String, "Two")
writeproto(pb, testval)
Expand All @@ -435,7 +435,7 @@ function test_maps()

testval = TestMaps()
readval = TestMaps()
set_field!(testval, :d3, Dict{String,String}())
testval.d3 = Dict{String,String}()
testval.d3["1"] = "One"
testval.d3["2"] = "Two"
writeproto(pb, testval)
Expand Down
8 changes: 3 additions & 5 deletions test/testutilapi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import ProtoBuf.meta

print_hdr(tname) = println("testing $tname...")

mutable struct TestType
mutable struct TestType <: ProtoType
a::AbstractString
b::Bool
TestType() = (o=new(); fillunset(o); o)
Expand All @@ -20,14 +20,12 @@ function test_apis()

@test false == try get_field(t, :a); true; catch; false; end

set_field!(t, :b, true)
t.b = true
@test has_field(t, :b)
@test (get_field(t, :b) == true)

@test !isinitialized(t)
t.a = "hello"
@test !isinitialized(t)
set_field!(t, :a, "hello world")
t.a = "hello world"
@test isinitialized(t)
@test (get_field(t, :a) == "hello world")

Expand Down

0 comments on commit 5d267b7

Please sign in to comment.