Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 21 additions & 24 deletions gems/smithy-cbor/lib/smithy-cbor/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,20 @@ def initialize(options = {})
end

def build(shape, data)
ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape)
return if ref.shape == Prelude::Unit
return if shape.target == Prelude::Unit

Cbor.encode(shape(ref, data))
Cbor.encode(build_shape(shape, data))
end

private

def shape(ref, value)
case ref.shape
def build_shape(shape, value)
case shape.target
when BlobShape then blob(value)
when ListShape then list(ref, value)
when MapShape then map(ref, value)
when StructureShape then structure(ref, value)
when UnionShape then union(ref, value)
when ListShape then list(shape, value)
when MapShape then map(shape, value)
when StructureShape then structure(shape, value)
when UnionShape then union(shape, value)
else value
end
end
Expand All @@ -36,47 +35,45 @@ def blob(value)
value.respond_to?(:read) ? value.read : value
end

def list(ref, values)
def list(shape, values)
return if values.nil?

shape = ref.shape
values.collect do |value|
shape(shape.member, value)
build_shape(shape.target.member, value)
end
end

def map(ref, values)
def map(shape, values)
return if values.nil?

shape = ref.shape
values.each.with_object({}) do |(key, value), data|
data[key] = shape(shape.value, value)
data[key] = build_shape(shape.target.value, value)
end
end

def structure(ref, values)
def structure(shape, values)
return if values.nil?

ref.shape.members.each_with_object({}) do |(member_name, member_ref), data|
shape.target.members.each_with_object({}) do |(member_name, member_shape), data|
value = values[member_name]
next if value.nil?

data[member_ref.location_name] = shape(member_ref, value)
data[member_shape.location_name] = build_shape(member_shape, value)
end
end

def union(ref, values) # rubocop:disable Metrics/AbcSize
def union(shape, values) # rubocop:disable Metrics/AbcSize
return if values.nil?

data = {}
if values.is_a?(Schema::Union)
_name, member_ref = ref.shape.member_by_type(values.class)
data[member_ref.location_name] = shape(member_ref, values.value)
_name, member_shape = shape.target.member_by_type(values.class)
data[member_shape.location_name] = build_shape(member_shape, values.value)
else
key, value = values.first
if ref.shape.member?(key)
member_ref = ref.shape.member(key)
data[member_ref.location_name] = shape(member_ref, value)
if shape.target.member?(key)
member_shape = shape.target.member(key)
data[member_shape.location_name] = build_shape(member_shape, value)
end
end
data
Expand Down
10 changes: 5 additions & 5 deletions gems/smithy-cbor/lib/smithy-cbor/codec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ def initialize(options = {})
@options = options
end

# @param [ShapeRef, Shape] shape
# @param [Shape] shape
# @param [Object] data
# @return [String, nil]
def build(shape, data)
Builder.new(@options).build(shape, data)
end

# @param [ShapeRef, Shape] shape
# @param [Shape] shape
# @param [String] bytes
# @param [Object, nil] target (nil)
# @param [Object, nil] result (nil)
# @return [Object, nil]
def parse(shape, bytes, target = nil)
Parser.new(@options).parse(shape, bytes, target)
def parse(shape, bytes, result = nil)
Parser.new(@options).parse(shape, bytes, result)
end
end
end
Expand Down
61 changes: 30 additions & 31 deletions gems/smithy-cbor/lib/smithy-cbor/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,68 +12,67 @@ def initialize(options = {})
@options = options
end

def parse(shape, bytes, target = nil)
def parse(shape, bytes, result = nil)
return {} if bytes.empty?

ref = shape.is_a?(ShapeRef) ? shape : ShapeRef.new(shape: shape)
shape(ref, Cbor.decode(bytes), target)
parse_shape(shape, Cbor.decode(bytes), result)
end

private

def shape(ref, value, target = nil)
def parse_shape(shape, value, result = nil)
return nil if value.nil?

case ref.shape
when ListShape then list(ref, value, target)
when MapShape then map(ref, value, target)
when StructureShape then structure(ref, value, target)
when UnionShape then union(ref, value, target)
case shape.target
when ListShape then list(shape, value, result)
when MapShape then map(shape, value, result)
when StructureShape then structure(shape, value, result)
when UnionShape then union(shape, value, result)
else value
end
end

def list(ref, values, target = nil)
target = [] if target.nil?
def list(shape, values, result = nil)
result = [] if result.nil?
values.each do |value|
next if value.nil? && !sparse?(ref.shape)
next if value.nil? && !sparse?(shape.target)

target << shape(ref.shape.member, value)
result << parse_shape(shape.target.member, value)
end
target
result
end

def map(ref, values, target = nil)
target = {} if target.nil?
def map(shape, values, result = nil)
result = {} if result.nil?
values.each do |key, value|
next if value.nil? && !sparse?(ref.shape)
next if value.nil? && !sparse?(shape.target)

target[key] = shape(ref.shape.value, value)
result[key] = parse_shape(shape.target.value, value)
end
target
result
end

def structure(ref, values, target = nil)
target = ref.shape.type.new if target.nil?
ref.shape.members.each do |member_name, member_ref|
value = values[member_ref.location_name]
target[member_name] = shape(member_ref, value) unless value.nil?
def structure(shape, values, result = nil)
result = shape.target.type.new if result.nil?
shape.target.members.each do |member_name, member_shape|
value = values[member_shape.location_name]
result[member_name] = parse_shape(member_shape, value) unless value.nil?
end
target
result
end

def union(ref, values, target = nil) # rubocop:disable Metrics/AbcSize
ref.shape.members.each do |member_name, member_ref|
value = values[member_ref.location_name]
def union(shape, values, result = nil) # rubocop:disable Metrics/AbcSize
shape.target.members.each do |member_name, member_shape|
value = values[member_shape.location_name]
next if value.nil?

target = ref.shape.member_type(member_name) if target.nil?
return target.new(member_name => shape(member_ref, value))
result = shape.target.member_type(member_name) if result.nil?
return result.new(member_name => parse_shape(member_shape, value))
end

values.delete('__type')
key, value = values.first
ref.shape.member_type(:unknown).new(unknown: { key => value })
shape.target.member_type(:unknown).new(unknown: { key => value })
end

def sparse?(shape)
Expand Down
4 changes: 2 additions & 2 deletions gems/smithy-cbor/sig/smithy-cbor/codec.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ module Smithy
module Cbor
module Codec
def initialize: (?Hash[Symbol, untyped] options) -> void
def build: (Schema::Shapes::Shape | Schema::Shapes::ShapeRef shape, Object data) -> (nil | String)
def parse: (Schema::Shapes::Shape | Schema::Shapes::ShapeRef shape, String bytes, ?Object ?target) -> Object?
def build: (Schema::Shapes::Shape shape, Object data) -> (nil | String)
def parse: (Schema::Shapes::Shape shape, String bytes, ?Object ?result) -> Object?
end
end
end
4 changes: 2 additions & 2 deletions gems/smithy-cbor/spec/smithy-cbor/builder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ module Cbor

context 'unions' do
it 'builds unions as a type' do
union = structure_shape.member(:union).shape.member_type(:string).new(string: 'string')
union = structure_shape.member(:union).target.member_type(:string).new(string: 'string')
type = structure_shape.type.new(union: union)
bytes = subject.build(structure_shape, type)
expect(Cbor.decode(bytes)).to eq({ 'union' => { 'string' => 'string' } })
Expand All @@ -90,7 +90,7 @@ module Cbor
end

it 'builds union unit members as a type' do
union = structure_shape.member(:union).shape.member_type(:unit).new(unit: Schema::EmptyStructure.new)
union = structure_shape.member(:union).target.member_type(:unit).new(unit: Schema::EmptyStructure.new)
type = structure_shape.type.new(union: union)
bytes = subject.build(structure_shape, type)
expect(Cbor.decode(bytes)).to eq('union' => { 'unit' => {} })
Expand Down
48 changes: 24 additions & 24 deletions gems/smithy-client/lib/smithy-client/default_params.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,70 +9,70 @@ module Client
class DefaultParams
include Schema::Shapes

def initialize(ref)
@ref = ref
def initialize(shape)
@shape = shape
end

# @param [Hash] params
# @return [Hash]
def apply(params)
structure(@ref, params)
structure(@shape, params)
end

private

def shape(ref, value)
case ref.shape
when ListShape then list(ref, value)
when MapShape then map(ref, value)
when StructureShape then structure(ref, value)
def apply_shape(shape, value)
case shape.target
when ListShape then list(shape, value)
when MapShape then map(shape, value)
when StructureShape then structure(shape, value)
else value
end
end

def list(ref, values)
def list(shape, values)
return if values.nil?

shape = ref.shape
member = shape.target.member
values.each do |value|
shape(shape.member, value)
apply_shape(member, value)
end
values
end

def map(ref, values)
def map(shape, values)
return if values.nil?

shape = ref.shape
value_shape = shape.target.value
values.each_pair do |_key, value|
shape(shape.value, value)
apply_shape(value_shape, value)
end
values
end

def structure(ref, values)
def structure(shape, values)
return if values.nil?

ref.shape.members.each do |member_name, member_ref|
shape.target.members.each do |member_name, member_shape|
value = values[member_name]
value ||= default(member_ref) if default?(ref, member_ref.traits)
next if value.nil? && !default?(ref, member_ref.traits) # default can have nil values
value ||= default(member_shape) if default?(shape, member_shape.traits)
next if value.nil? && !default?(shape, member_shape.traits) # default can have nil values

values[member_name] = shape(member_ref, value)
values[member_name] = apply_shape(member_shape, value)
end
values
end

def default?(ref, traits)
def default?(shape, traits)
# skip defaults for top level members
return false if ref == @ref
return false if shape == @shape

traits.include?('smithy.api#default') && !traits.include?('smithy.api#clientOptional')
end

def default(ref)
default = ref.traits['smithy.api#default']
case ref.shape
def default(member_shape)
default = member_shape.traits['smithy.api#default']
case member_shape.target
when BlobShape then Base64.strict_decode64(default)
when TimestampShape then timestamp_default(default)
else default
Expand Down
Loading
Loading