meta/rpc/SAI/Function.pm (156 lines of code) (raw):
# Copyright 2021-present Intel Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
package SAI::Function;
use Moose::Util::TypeConstraints;
use Term::ANSIColor;
use Carp;
use namespace::autoclean;
use Moose;
################
# Helper types #
################
subtype 'SAI::Types::ReturnValue' => as 'SAI::Function::Argument' =>
where { $_->name eq 'retval' };
# Accept also Str (TypeName) as ReturnValue
coerce 'SAI::Types::ReturnValue' => from 'SAI::Types::TypeName' => via {
SAI::Function::Argument->new(
name => 'retval',
type => $_,
is_retval => 1
)
};
##########
# Fields #
##########
has 'name' => ( is => 'ro', isa => 'Str', required => 1 );
has 'return' => (
is => 'rw',
isa => 'SAI::Types::ReturnValue',
coerce => 1,
trigger => \&_return_set,
);
has 'args' => (
traits => ['Array'],
is => 'rw',
isa => 'ArrayRef[SAI::Function::Argument]',
handles =>
{ filter_args => 'grep', get_arg => 'get', all_args => 'elements' },
trigger => \&_args_set,
);
has 'api' => ( is => 'rw', isa => 'Str' );
has 'dbg_info' => ( is => 'ro', isa => 'Str' );
with 'SAI::RPC::ThriftName', 'SAI::Utils::XMLLoader', 'SAI::RPC::Function';
##################
# Public methods #
##################
# Get the operation name, e.g. 'set', 'get', 'create', etc.
sub operation {
my $self = shift;
return ( $self->_get_info_from_name )[0];
}
# Get the object name, the function operates on
sub object {
my $self = shift;
my $object = ( $self->_get_info_from_name )[1];
# For attr arguments, the object information is required
if ( not defined $object and $self->filter_args( sub { $_->is_attr } ) ) {
carp colored( 'Could not obtain object name (' . $self->name . "())\n",
'red' );
}
return $object;
}
###################
# Private methods #
###################
# return field trigger
sub _return_set {
my $self = shift;
my $return = shift;
# just set the parent object (this 'Function' object)
$return->_set_parent($self);
return;
}
# args field trigger
sub _args_set {
my $self = shift;
my $args = shift;
# set the parent object (this 'Function' object) for all args
$_->_set_parent($self) for ( @{$args} );
return;
}
# Get (from function name) an object name and operation performed on it
sub _get_info_from_name {
my $self = shift;
if (
$self->name =~
m{(create|remove|set|get|clear)_ # we expect attribute only for those functions
(\w+)(?<!_attribute)(?<!_stats)(?<!_ext) # attribute should not be matched
(_attribute|_stats)? # attribute is optional (for set or get only)
(_ext)? # ext is optional
$}x
)
{
my $operation = $1;
$operation = 'stats'
if $operation eq 'get'
and defined $3
and $3 eq '_stats';
return $operation, $2;
}
# Special cases
return ( 'other', 'fdb_flush' )
if ( $self->name =~ 'flush_fdb_entries' );
return ( q{}, 'hostif_packet' )
if ( $self->name =~ 'hostif_packet$' );
return ( q{}, q{} );
}
# Find the count argument for the specified potential list argument
sub _find_count_arg {
my $self = shift;
my $arg = shift;
my $direct_predecessor = 1;
my $arg_pos = $arg->pos;
my $prev_arg;
# Check previous arguments
while ( $prev_arg = $self->get_arg( --$arg_pos ) ) {
# Previous variable has its uint32 (is a list)
if ( $prev_arg->count ) {
# Get count argument from the prevous one, e.g.:
# get_stats(uint32_t number_of_elements,
# sai_stat_id_t *counter_ids,
# uint64_t *counters)
return $prev_arg->count;
}
elsif (
# Previous variable is uint32
$prev_arg->type->thrift_name =~ /uint32_t/
# or list of uint32 (and we have pointer to pointer)
or ( $arg->type->ptr == 2
and $prev_arg->is_list
and $prev_arg->type->subtype->thrift_name =~ /uint32_t/ )
)
{
# Note, that counter must be directly previous argument.
return $prev_arg if $direct_predecessor;
}
else { $direct_predecessor = 0 }
}
return;
}
################
# TT coditions #
################
################
# Construction #
################
# Function arguments play another roles, depending on their neighbours
# e.g. uint32 argument before pointer argument, means that pointer
# argument is a list, and uint32 one is its counter
sub resolve_arg_dependencies {
my $self = shift;
# If we have pointer args, then mark some of them as arrays
for my $arg ( $self->filter_args( sub { $_->type->ptr } ) ) {
my $count_arg = $self->_find_count_arg($arg);
if ($count_arg) {
# Arg is a list:
$arg->count($count_arg);
$count_arg->is_count(1);
$arg->convert_to_list;
}
}
return;
}
# Moose builder, called right after construction
sub BUILD {
my $self = shift;
# Assign argument positions
my $pos = 0;
$_->_set_pos( $pos++ ) for ( $self->all_args );
# Finish function creation
$self->resolve_arg_dependencies;
return;
}
# Get function definition from XML typedef (SAI::Utils::XMLLoader role)
sub parse_xml_typedef {
my $class = shift;
my $xml_typedef = shift;
my $ret_type;
my @args;
my $fn;
# Get function name
$fn = $1 if $xml_typedef->{name}[0] =~ /^(\w+)_fn$/;
# Get return value
$ret_type = $1 if $xml_typedef->{type}[0] =~ /^(\w+_t)/;
# Get parameter list
my $args_string = $xml_typedef->{argsstring}[0];
$args_string =~ s/[()]//g;
my @sai_args = split /, /, $args_string;
push @args, SAI::Function::Argument->new($_) for (@sai_args);
return (
name => $fn,
return => $ret_type,
args => \@args,
dbg_info => $xml_typedef->{type}[0]
. $xml_typedef->{name}[0]
. $xml_typedef->{argsstring}[0],
);
}
# Validate function definition in XML typedef (SAI::Utils::XMLLoader role)
sub validate_xml_typedef {
my $class = shift;
my $xml_typedef = shift;
return 0
unless $xml_typedef->{name}[0] =~ /^\w+_fn$/;
return 0
unless $xml_typedef->{type}[0] =~ /^\w+_t/;
return 1;
}
__PACKAGE__->meta->make_immutable;
1;