package Thrift::Parser::FieldSet;
=head1 NAME
Thrift::Parser::FieldSet - A set of fields in a structure
=cut
use strict;
use warnings;
use Params::Validate qw(validate_with);
use Data::Dumper;
use Scalar::Util qw(blessed);
use base qw(Class::Accessor::Grouped);
__PACKAGE__->mk_group_accessors(simple => qw(fields));
=head1 USAGE
=head2 fields
Returns an array ref of all the fields in this set.
=cut
sub new {
my $class = shift;
my %self = validate_with(
params => shift,
spec => {
fields => 1,
},
);
return bless \%self, $class;
}
=head2 named
my $value = $field_set->named('id');
Searches the fields in the set for the field named $name. Returns the value of that field.
=cut
sub named {
my ($self, $name) = @_;
foreach my $field (@{ $self->{fields} }) {
if ($field->name eq $name) {
return $field->value;
}
}
return;
}
*field_named = \&named;
=head2 id
my $value = $field_set->id(2);
Searches the fields in the set for the field with id $id. Returns the value of that field.
=cut
sub id {
my ($self, $id) = @_;
foreach my $field (@{ $self->{fields} }) {
if ($field->id eq $id) {
return $field->value;
}
}
return;
}
=head2 ids
Returns an array ref of the ids of this field set.
=cut
sub ids {
my $self = shift;
my @ids = sort { $a <=> $b } map { $_->id } @{ $self->{fields} };
return \@ids;
}
=head2 field_values
Returns an array ref of the values of the fields in the set.
=cut
sub field_values {
my $self = shift;
my @values = map { $_->value } @{ $self->{fields} };
return \@values;
}
=head2 keyed_field_values
Returns a hashref where the keys are the names of the fields and the values are the values of the fields.
=cut
sub keyed_field_values {
my $self = shift;
my %hash = map { $_->name => $_->value } @{ $self->{fields} };
return \%hash;
}
=head2 keyed_field_values_plain
Returns a hashref where the keys are the names of the fields and the values are the plain values of the fields.
=cut
sub keyed_field_values_plain {
my $self = shift;
my %hash = map { $_->name => $_->value->value_plain } @{ $self->{fields} };
return \%hash;
}
=head2 compose
Used internally by L<Thrift::Parser::Method> and L<Thrift::Parser::Struct>. Given a list of key/value pairs, returns a FieldSet object informed by the IDL.
=cut
sub compose {
my ($self_class, $class, %args) = @_;
if (! $class->idl) {
die "Requires an IDL";
}
if (! $class->idl->can('field_id')) {
Thrift::Parser::InvalidArgument->throw(
key => 'class', value => $class, error => "Doesn't support field_id()",
);
}
# Check for missing non-optional fields
foreach my $field (@{ $class->idl->fields }) {
my $default_value = $field->default_value;
# User may pass '_:id' or the name of the field
my $key = defined $args{ '_' . $field->id } ? '_' . $field->id : $field->name;
if (defined $default_value && ! defined $args{$key}) {
$args{$key} = $default_value;
next;
}
if (! defined $default_value && ! defined $args{$key} && ! $field->optional && $class->isa('Thrift::Parser::Type::Struct')) {
Thrift::Parser::InvalidArgument->throw("Missing value for field '".$field->name."' in $class compose()");
}
}
my @fields;
foreach my $key (keys %args) {
# Determine the IDL type of the field
my $idl_field;
if (my ($id) = $key =~ m{^_(\d+)$}) {
$idl_field = $class->idl->field_id($id);
}
else {
$idl_field = $class->idl->field_named($key);
}
if (! $idl_field) {
Thrift::Parser::InvalidArgument->throw(
error => "Failed to find referenced field '$key' in the $class IDL spec",
key => $key, value => $args{value},
);
}
my $type = $idl_field->type;
# Cast into the new value
my $type_class;
if ($type->isa('Thrift::IDL::Type::Custom')) {
my $type_name = $type->full_name;
my $referenced_type = $class->idl_doc->object_full_named($type_name);
if (! $referenced_type) {
Thrift::Parser::InvalidSpec->throw("Couldn't find definition of custom type '".$type_name."'");
}
my $namespace = $referenced_type->{header}->namespace('perl');
$type_class = join '::', (defined $namespace ? ($namespace) : ()), $type->local_name;
}
else {
$type_class = 'Thrift::Parser::Type::' . $type->name;
}
my $value = $type_class->compose_with_idl($type, $args{$key});
my $field = Thrift::Parser::Field->new({
id => $idl_field->id,
value => $value,
name => $idl_field->name,
});
push @fields, $field;
}
return $self_class->new({ fields => \@fields });
}
sub write {
my ($self, $output) = @_;
$output->writeStructBegin();
foreach my $field (@{ $self->{fields} }) {
$field->write($output);
}
$output->writeFieldStop();
$output->writeStructEnd();
}
=head1 COPYRIGHT
Copyright (c) 2009 Eric Waters and XMission LLC (http://www.xmission.com/). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the LICENSE file included with this module.
=head1 AUTHOR
Eric Waters <ewaters@gmail.com>
=cut
1;