Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
304 lines (190 sloc) 6.98 KB
/*
* C Seaplus driver in charge of converting, for each function exposed by the
* foobar service API, the Erlang parameters received from the
* port into C variables that can be passed to the service functions, and to
* perform the reciprocal operation on their results, so that they can be sent
* back to the Erlang calling side.
*
*/
// Generated by the Seaplus parse transform, based on foobar.erl:
#include "foobar_seaplus_api_mapping.h"
// Generic helpers to facilitate the writing of this C part of the bridge:
#include "seaplus.h"
// To access to the actual C implementation of the service:
#include "foobar.h"
// For free:
#include <stdlib.h>
// For strcmp:
#include <string.h>
// Forward references to the introduced foobar-specific helpers:
enum foo_status get_foo_status_from_atom( const char * atom_name ) ;
void write_foo_data_record_from_struct( output_buffer * output_sm_buf,
struct foo_data * s ) ;
enum tur_status get_tur_status_enum_from_atom_name( const char * atom_name ) ;
int main()
{
// Provided by the Seaplus library:
byte * current_read_buf ;
input_buffer read_buf = &current_read_buf ;
start_seaplus_driver( read_buf ) ;
// For the mandatory result:
output_buffer output_sm_buf ;
LOG_TRACE( "Foobar Driver started." ) ;
/* Reads a full command from (receive) buffer, based on its initial length:
*
* (a single term is expected hence read)
*
*/
while ( read_command( read_buf ) > 0 )
{
LOG_TRACE( "New command received." ) ;
// Current index in the input buffer (for decoding purpose):
buffer_index index = 0 ;
/* Will be set to the corresponding Seaplus-defined function identifier (ex:
* whose value is FOO_1_ID):
*
*/
fun_id current_fun_id ;
/* Will be set to the number of parameters obtained from Erlang for the
* function whose identifier has been transmitted:
*
*/
arity param_count ;
read_function_information( read_buf, &index, &current_fun_id, &param_count ) ;
LOG_DEBUG( "Function identifier is %u, arity is %u (new index is %u).",
current_fun_id, param_count, index ) ;
prepare_for_command( &output_sm_buf ) ;
// Now, taking care of the corresponding function call:
switch( current_fun_id )
{
case FOO_1_ID:
// -spec foo( integer() ) -> integer() vs int foo( int a )
LOG_DEBUG( "Executing foo/1." ) ;
check_arity_is( 1, param_count, FOO_1_ID ) ;
// So we expect the (single, hence first) parameter to be an integer:
long foo_a_param = read_int_parameter( read_buf, &index ) ;
LOG_DEBUG( "foo/1's integer parameter: %ld.", foo_a_param ) ;
// Actual call:
int foo_result = foo( (int) foo_a_param ) ;
LOG_DEBUG( "foo/1's integer result: %i.", foo_result ) ;
// Sending of the integer result:
write_int_result( &output_sm_buf, foo_result ) ;
break ;
case BAR_2_ID:
/* -spec bar( float(), foo_status() ) -> foo_data() vs
* struct foo * bar( double a, enum foo_status status )
*
*/
LOG_DEBUG( "Executing bar/2." ) ;
check_arity_is( 2, param_count, BAR_2_ID ) ;
// Getting first the Erlang float:
double bar_double_param = read_double_parameter( read_buf, &index ) ;
// Then the atom for foo_status():
char * atom_name = read_atom_parameter( read_buf, &index ) ;
// Converting said atom for the C API:
enum foo_status bar_status_param = get_foo_status_from_atom( atom_name ) ;
free( atom_name ) ;
// Actual call (ownership of struct_res transferred to this caller):
struct foo_data * struct_res = bar( bar_double_param, bar_status_param ) ;
// Defining a separated writing function is more convenient here:
write_foo_data_record_from_struct( &output_sm_buf, struct_res ) ;
free( struct_res ) ;
break ;
case BAZ_2_ID:
/* -spec baz( integer(), text_utils:ustring() ) -> tur_status() vs
* enum tur_status baz( unsigned int u, const char * m )
*
*/
LOG_DEBUG( "Executing baz/2." ) ;
check_arity_is( 2, param_count, BAZ_2_ID ) ;
// Getting first the (unsigned) integer:
int baz_int_param = read_int_parameter( read_buf, &index ) ;
// Then the string:
char * baz_string_param = read_string_parameter( read_buf, &index ) ;
// Actual call:
enum tur_status enum_res = baz( baz_int_param, baz_string_param ) ;
free( baz_string_param ) ;
if ( enum_res == tur_value )
write_atom_result( &output_sm_buf, "tur_value" ) ;
else if ( enum_res == non_tur_value )
write_atom_result( &output_sm_buf, "non_tur_value" ) ;
else
raise_error( "Unexpected tur_status enum: %i", enum_res ) ;
break ;
case TUR_0_ID:
// -spec tur() -> bool() vs bool tur()
LOG_DEBUG( "Executing tur/0." ) ;
check_arity_is( 0, param_count, TUR_0_ID ) ;
// Actual call:
bool res = tur() ;
// Sending of the result atom:
write_bool_result( &output_sm_buf, res ) ;
break ;
case FROB_1_ID:
/* frob( tur_status() ) -> text_utils:ustring() vs
* char * frob( enum tur_status )
*
*/
LOG_DEBUG( "Executing frob/1." ) ;
check_arity_is( 1, param_count, FROB_1_ID ) ;
char * tur_atom_name = read_atom_parameter( read_buf, &index ) ;
enum tur_status s = get_tur_status_enum_from_atom_name( tur_atom_name ) ;
free( tur_atom_name ) ;
char * string_res = frob( s ) ;
write_string_result( &output_sm_buf, string_res ) ;
break ;
default:
raise_error( "Unknown function identifier: %u", current_fun_id ) ;
}
finalize_command_after_writing( &output_sm_buf ) ;
}
// output_sm_buf internally already freed appropriately.
stop_seaplus_driver( read_buf ) ;
}
// Service-specific helpers:
// Converts the name of an atom into a foo_status enum.
enum foo_status get_foo_status_from_atom( const char * atom_name )
{
if ( strcmp( atom_name, "low_speed" ) == 0 )
return low_speed ;
if ( strcmp( atom_name, "moderate_speed" ) == 0 )
return moderate_speed ;
if ( strcmp( atom_name, "full_speed" ) == 0 )
return full_speed ;
raise_error( "Unable to convert atom name '%s' into a foo_status enum.",
atom_name ) ;
// To silence compiler:
return 0 ;
}
/* Returns a foo_data record from specified counterpart struct.
*
* We want to return a foo_data record, i.e. a { foo_data, Count:: integer(),
* Value:: float() } triplet.
*
* Note: ownership of the returned term transferred to the caller.
*
*/
void write_foo_data_record_from_struct( output_buffer * output_sm_buf,
struct foo_data * s )
{
write_tuple_header_result( output_sm_buf, 3 ) ;
write_atom_result( output_sm_buf, "foo_data" ) ;
write_int_result( output_sm_buf, s->count ) ;
write_double_result( output_sm_buf, s->value ) ;
}
/**
* Returns a tur_status enum from specified atom name (as a string).
*
* Note: not taking ownership of the input atom).
*
*/
enum tur_status get_tur_status_enum_from_atom_name( const char * atom_name )
{
if ( strcmp( atom_name, "tur_value" ) == 0 )
return tur_value ;
if ( strcmp( atom_name, "non_tur_value" ) == 0 )
return non_tur_value ;
raise_error( "Unexpected tur_status atom name: %s", atom_name ) ;
// To silence compiler:
return 0 ;
}
You can’t perform that action at this time.