First Rust Thrift Server crashing on returning i32?

So I've dove in an setup a small rust project (Implement one of my thrift services in rust.. via this example : Rust Thrift Example (server.rs) · GitHub

I took it and slightly modified it.. even checked the docs in apache thrift .. seemed no different there..

BUT when I start it up and call the ping RPC function..

...
// server implementation
#[derive(Default)]
struct IbrokersHandlerImpl;
impl IbrokersSyncHandler for IbrokersHandlerImpl {

    fn handle_ping(&self) -> thrift::Result<i32> {
        let ping_val: thrift::Result<i32> = Ok(0);
        ping_val
    }

    fn handle_ib_status(&self) -> thrift::Result<Vec<String>> {
        todo!()
    }

    fn handle_request_news(&self, request_contracts: Vec<IBContract>, news_type: String) -> thrift::Result<Vec<NewsResponse>> {
        todo!()
    }

    fn handle_request_historical(&self, request_contracts: Vec<IBContract>, trade_type: String) -> thrift::Result<Vec<HistoricalResponse>> {
        todo!()
    }

    fn handle_request_matching_symbols(&self, queries_list: Vec<String>) -> thrift::Result<Vec<MatchingSymbolResponse>> {
        todo!()
    }
}
client.connect("127.0.0.1")   # this works
client.ping()                          # crashes here

I get this

binding to 127.0.0.1:9090
memory allocation of 18446744071562133505 bytes failed
Aborted (core dumped)

I will double back and check if my thirft versions are mismatched .. but this seems to be the correct way to return a simple integer.. should I check the generated .rs file definition?

What crate are you using?

You may need to share more code related to how your IbrokersSyncHandler trait is interacting with the types in that crate as well.

That error message seems to be saying something requested an allocation of more than 18 million terabytes which uhhhh yeah I'm not surprised that crashed.

1 Like

That example is 6 years old and uses an old version (0.0.2) of thrift (and of the other depedencies, surely). I don't know anything about thrift, but that version is clearly no longer maintained.

So have you tried a newer version? There's a link to a Tutorial in the docs.

1 Like

thank you @semicoleon and @quinedot .. I am going to pare back my current thrift definition file to something smaller/simpler.. and will try again.. I am utilizing thrift via this external crate

[package]
name = "test_thrift" # the name of the package
version = "0.1.0"    # the current version, obeying semver
authors = ["Alice <a@example.com>", "Bob <b@example.com>"]


[dependencies]
thrift = "0.16.0"

Regarding the new tutorial.. I just now realized that the README only talked about the client.. so I sort of glanced and moved on .. but in fact the server example is indeed in there. I will look at it now again with the smaller .thrift file and try again

That error message seems to be saying something requested an allocation of more than 18 million terabytes which uhhhh yeah I'm not surprised that crashed.

Hahaha yeah I saw that and thought... hmmmmm I need a new SSD now

my test.thrift

namespace java com.jrgemcp.twsapithrift
namespace cpp twsapithrift

exception IBSAPIException {
  1: i32 error_code,
  2: string message
}


service ibrokers {

    i32 ping() throws (1:IBSAPIException error),

    list<string> ib_status() throws (1:IBSAPIException error)
}

I am using crate 0.16.0

even with a very simple simple .thrift definition .. this crash message occurs even with the latest tutorial code and this super simple .thrift file I think there is some issue

service.rs

// Autogenerated by Thrift Compiler (0.16.0)
// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING

#![allow(unused_imports)]
#![allow(unused_extern_crates)]
#![allow(clippy::too_many_arguments, clippy::type_complexity, clippy::vec_box)]
#![cfg_attr(rustfmt, rustfmt_skip)]

use std::cell::RefCell;
use std::collections::{BTreeMap, BTreeSet};
use std::convert::{From, TryFrom};
use std::default::Default;
use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::rc::Rc;

use thrift::OrderedFloat;
use thrift::{ApplicationError, ApplicationErrorKind, ProtocolError, ProtocolErrorKind, TThriftClient};
use thrift::protocol::{TFieldIdentifier, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType, TInputProtocol, TOutputProtocol, TSetIdentifier, TStructIdentifier, TType};
use thrift::protocol::field_id;
use thrift::protocol::verify_expected_message_type;
use thrift::protocol::verify_expected_sequence_number;
use thrift::protocol::verify_expected_service_call;
use thrift::protocol::verify_required_field_exists;
use thrift::server::TProcessor;

//
// IBSAPIException
//

#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct IBSAPIException {
  pub error_code: Option<i32>,
  pub message: Option<String>,
}

impl IBSAPIException {
  pub fn new<F1, F2>(error_code: F1, message: F2) -> IBSAPIException where F1: Into<Option<i32>>, F2: Into<Option<String>> {
    IBSAPIException {
      error_code: error_code.into(),
      message: message.into(),
    }
  }
  pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<IBSAPIException> {
    i_prot.read_struct_begin()?;
    let mut f_1: Option<i32> = Some(0);
    let mut f_2: Option<String> = Some("".to_owned());
    loop {
      let field_ident = i_prot.read_field_begin()?;
      if field_ident.field_type == TType::Stop {
        break;
      }
      let field_id = field_id(&field_ident)?;
      match field_id {
        1 => {
          let val = i_prot.read_i32()?;
          f_1 = Some(val);
        },
        2 => {
          let val = i_prot.read_string()?;
          f_2 = Some(val);
        },
        _ => {
          i_prot.skip(field_ident.field_type)?;
        },
      };
      i_prot.read_field_end()?;
    }
    i_prot.read_struct_end()?;
    let ret = IBSAPIException {
      error_code: f_1,
      message: f_2,
    };
    Ok(ret)
  }
  pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
    let struct_ident = TStructIdentifier::new("IBSAPIException");
    o_prot.write_struct_begin(&struct_ident)?;
    if let Some(fld_var) = self.error_code {
      o_prot.write_field_begin(&TFieldIdentifier::new("error_code", TType::I32, 1))?;
      o_prot.write_i32(fld_var)?;
      o_prot.write_field_end()?
    }
    if let Some(ref fld_var) = self.message {
      o_prot.write_field_begin(&TFieldIdentifier::new("message", TType::String, 2))?;
      o_prot.write_string(fld_var)?;
      o_prot.write_field_end()?
    }
    o_prot.write_field_stop()?;
    o_prot.write_struct_end()
  }
}

impl Default for IBSAPIException {
  fn default() -> Self {
    IBSAPIException{
      error_code: Some(0),
      message: Some("".to_owned()),
    }
  }
}

impl Error for IBSAPIException {}

impl From<IBSAPIException> for thrift::Error {
  fn from(e: IBSAPIException) -> Self {
    thrift::Error::User(Box::new(e))
  }
}

impl Display for IBSAPIException {
  fn fmt(&self, f: &mut Formatter) -> fmt::Result {
    write!(f, "remote service threw IBSAPIException")
  }
}

//
// ibrokers service client
//

pub trait TIbrokersSyncClient {
  fn ping(&mut self) -> thrift::Result<i32>;
  fn ib_status(&mut self) -> thrift::Result<Vec<String>>;
}

pub trait TIbrokersSyncClientMarker {}

pub struct IbrokersSyncClient<IP, OP> where IP: TInputProtocol, OP: TOutputProtocol {
  _i_prot: IP,
  _o_prot: OP,
  _sequence_number: i32,
}

impl <IP, OP> IbrokersSyncClient<IP, OP> where IP: TInputProtocol, OP: TOutputProtocol {
  pub fn new(input_protocol: IP, output_protocol: OP) -> IbrokersSyncClient<IP, OP> {
    IbrokersSyncClient { _i_prot: input_protocol, _o_prot: output_protocol, _sequence_number: 0 }
  }
}

impl <IP, OP> TThriftClient for IbrokersSyncClient<IP, OP> where IP: TInputProtocol, OP: TOutputProtocol {
  fn i_prot_mut(&mut self) -> &mut dyn TInputProtocol { &mut self._i_prot }
  fn o_prot_mut(&mut self) -> &mut dyn TOutputProtocol { &mut self._o_prot }
  fn sequence_number(&self) -> i32 { self._sequence_number }
  fn increment_sequence_number(&mut self) -> i32 { self._sequence_number += 1; self._sequence_number }
}

impl <IP, OP> TIbrokersSyncClientMarker for IbrokersSyncClient<IP, OP> where IP: TInputProtocol, OP: TOutputProtocol {}

impl <C: TThriftClient + TIbrokersSyncClientMarker> TIbrokersSyncClient for C {
  fn ping(&mut self) -> thrift::Result<i32> {
    (
      {
        self.increment_sequence_number();
        let message_ident = TMessageIdentifier::new("ping", TMessageType::Call, self.sequence_number());
        let call_args = IbrokersPingArgs {  };
        self.o_prot_mut().write_message_begin(&message_ident)?;
        call_args.write_to_out_protocol(self.o_prot_mut())?;
        self.o_prot_mut().write_message_end()?;
        self.o_prot_mut().flush()
      }
    )?;
    {
      let message_ident = self.i_prot_mut().read_message_begin()?;
      verify_expected_sequence_number(self.sequence_number(), message_ident.sequence_number)?;
      verify_expected_service_call("ping", &message_ident.name)?;
      if message_ident.message_type == TMessageType::Exception {
        let remote_error = thrift::Error::read_application_error_from_in_protocol(self.i_prot_mut())?;
        self.i_prot_mut().read_message_end()?;
        return Err(thrift::Error::Application(remote_error))
      }
      verify_expected_message_type(TMessageType::Reply, message_ident.message_type)?;
      let result = IbrokersPingResult::read_from_in_protocol(self.i_prot_mut())?;
      self.i_prot_mut().read_message_end()?;
      result.ok_or()
    }
  }
  fn ib_status(&mut self) -> thrift::Result<Vec<String>> {
    (
      {
        self.increment_sequence_number();
        let message_ident = TMessageIdentifier::new("ib_status", TMessageType::Call, self.sequence_number());
        let call_args = IbrokersIbStatusArgs {  };
        self.o_prot_mut().write_message_begin(&message_ident)?;
        call_args.write_to_out_protocol(self.o_prot_mut())?;
        self.o_prot_mut().write_message_end()?;
        self.o_prot_mut().flush()
      }
    )?;
    {
      let message_ident = self.i_prot_mut().read_message_begin()?;
      verify_expected_sequence_number(self.sequence_number(), message_ident.sequence_number)?;
      verify_expected_service_call("ib_status", &message_ident.name)?;
      if message_ident.message_type == TMessageType::Exception {
        let remote_error = thrift::Error::read_application_error_from_in_protocol(self.i_prot_mut())?;
        self.i_prot_mut().read_message_end()?;
        return Err(thrift::Error::Application(remote_error))
      }
      verify_expected_message_type(TMessageType::Reply, message_ident.message_type)?;
      let result = IbrokersIbStatusResult::read_from_in_protocol(self.i_prot_mut())?;
      self.i_prot_mut().read_message_end()?;
      result.ok_or()
    }
  }
}

//
// ibrokers service processor
//

pub trait IbrokersSyncHandler {
  fn handle_ping(&self) -> thrift::Result<i32>;
  fn handle_ib_status(&self) -> thrift::Result<Vec<String>>;
}

pub struct IbrokersSyncProcessor<H: IbrokersSyncHandler> {
  handler: H,
}

impl <H: IbrokersSyncHandler> IbrokersSyncProcessor<H> {
  pub fn new(handler: H) -> IbrokersSyncProcessor<H> {
    IbrokersSyncProcessor {
      handler,
    }
  }
  fn process_ping(&self, incoming_sequence_number: i32, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
    TIbrokersProcessFunctions::process_ping(&self.handler, incoming_sequence_number, i_prot, o_prot)
  }
  fn process_ib_status(&self, incoming_sequence_number: i32, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
    TIbrokersProcessFunctions::process_ib_status(&self.handler, incoming_sequence_number, i_prot, o_prot)
  }
}

pub struct TIbrokersProcessFunctions;

impl TIbrokersProcessFunctions {
  pub fn process_ping<H: IbrokersSyncHandler>(handler: &H, incoming_sequence_number: i32, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
    let _ = IbrokersPingArgs::read_from_in_protocol(i_prot)?;
    match handler.handle_ping() {
      Ok(handler_return) => {
        let message_ident = TMessageIdentifier::new("ping", TMessageType::Reply, incoming_sequence_number);
        o_prot.write_message_begin(&message_ident)?;
        let ret = IbrokersPingResult { result_value: Some(handler_return), error: None };
        ret.write_to_out_protocol(o_prot)?;
        o_prot.write_message_end()?;
        o_prot.flush()
      },
      Err(e) => {
        match e {
          thrift::Error::User(usr_err) => {
            if usr_err.downcast_ref::<IBSAPIException>().is_some() {
              let err = usr_err.downcast::<IBSAPIException>().expect("downcast already checked");
              let ret_err = IbrokersPingResult{ result_value: None, error: Some(*err) };
              let message_ident = TMessageIdentifier::new("ping", TMessageType::Reply, incoming_sequence_number);
              o_prot.write_message_begin(&message_ident)?;
              ret_err.write_to_out_protocol(o_prot)?;
              o_prot.write_message_end()?;
              o_prot.flush()
            } else {
              let ret_err = {
                ApplicationError::new(
                  ApplicationErrorKind::Unknown,
                  usr_err.to_string()
                )
              };
              let message_ident = TMessageIdentifier::new("ping", TMessageType::Exception, incoming_sequence_number);
              o_prot.write_message_begin(&message_ident)?;
              thrift::Error::write_application_error_to_out_protocol(&ret_err, o_prot)?;
              o_prot.write_message_end()?;
              o_prot.flush()
            }
          },
          thrift::Error::Application(app_err) => {
            let message_ident = TMessageIdentifier::new("ping", TMessageType::Exception, incoming_sequence_number);
            o_prot.write_message_begin(&message_ident)?;
            thrift::Error::write_application_error_to_out_protocol(&app_err, o_prot)?;
            o_prot.write_message_end()?;
            o_prot.flush()
          },
          _ => {
            let ret_err = {
              ApplicationError::new(
                ApplicationErrorKind::Unknown,
                e.to_string()
              )
            };
            let message_ident = TMessageIdentifier::new("ping", TMessageType::Exception, incoming_sequence_number);
            o_prot.write_message_begin(&message_ident)?;
            thrift::Error::write_application_error_to_out_protocol(&ret_err, o_prot)?;
            o_prot.write_message_end()?;
            o_prot.flush()
          },
        }
      },
    }
  }
  pub fn process_ib_status<H: IbrokersSyncHandler>(handler: &H, incoming_sequence_number: i32, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
    let _ = IbrokersIbStatusArgs::read_from_in_protocol(i_prot)?;
    match handler.handle_ib_status() {
      Ok(handler_return) => {
        let message_ident = TMessageIdentifier::new("ib_status", TMessageType::Reply, incoming_sequence_number);
        o_prot.write_message_begin(&message_ident)?;
        let ret = IbrokersIbStatusResult { result_value: Some(handler_return), error: None };
        ret.write_to_out_protocol(o_prot)?;
        o_prot.write_message_end()?;
        o_prot.flush()
      },
      Err(e) => {
        match e {
          thrift::Error::User(usr_err) => {
            if usr_err.downcast_ref::<IBSAPIException>().is_some() {
              let err = usr_err.downcast::<IBSAPIException>().expect("downcast already checked");
              let ret_err = IbrokersIbStatusResult{ result_value: None, error: Some(*err) };
              let message_ident = TMessageIdentifier::new("ib_status", TMessageType::Reply, incoming_sequence_number);
              o_prot.write_message_begin(&message_ident)?;
              ret_err.write_to_out_protocol(o_prot)?;
              o_prot.write_message_end()?;
              o_prot.flush()
            } else {
              let ret_err = {
                ApplicationError::new(
                  ApplicationErrorKind::Unknown,
                  usr_err.to_string()
                )
              };
              let message_ident = TMessageIdentifier::new("ib_status", TMessageType::Exception, incoming_sequence_number);
              o_prot.write_message_begin(&message_ident)?;
              thrift::Error::write_application_error_to_out_protocol(&ret_err, o_prot)?;
              o_prot.write_message_end()?;
              o_prot.flush()
            }
          },
          thrift::Error::Application(app_err) => {
            let message_ident = TMessageIdentifier::new("ib_status", TMessageType::Exception, incoming_sequence_number);
            o_prot.write_message_begin(&message_ident)?;
            thrift::Error::write_application_error_to_out_protocol(&app_err, o_prot)?;
            o_prot.write_message_end()?;
            o_prot.flush()
          },
          _ => {
            let ret_err = {
              ApplicationError::new(
                ApplicationErrorKind::Unknown,
                e.to_string()
              )
            };
            let message_ident = TMessageIdentifier::new("ib_status", TMessageType::Exception, incoming_sequence_number);
            o_prot.write_message_begin(&message_ident)?;
            thrift::Error::write_application_error_to_out_protocol(&ret_err, o_prot)?;
            o_prot.write_message_end()?;
            o_prot.flush()
          },
        }
      },
    }
  }
}

impl <H: IbrokersSyncHandler> TProcessor for IbrokersSyncProcessor<H> {
  fn process(&self, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
    let message_ident = i_prot.read_message_begin()?;
    let res = match &*message_ident.name {
      "ping" => {
        self.process_ping(message_ident.sequence_number, i_prot, o_prot)
      },
      "ib_status" => {
        self.process_ib_status(message_ident.sequence_number, i_prot, o_prot)
      },
      method => {
        Err(
          thrift::Error::Application(
            ApplicationError::new(
              ApplicationErrorKind::UnknownMethod,
              format!("unknown method {}", method)
            )
          )
        )
      },
    };
    thrift::server::handle_process_result(&message_ident, res, o_prot)
  }
}

//
// IbrokersPingArgs
//

#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
struct IbrokersPingArgs {
}

impl IbrokersPingArgs {
  fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<IbrokersPingArgs> {
    i_prot.read_struct_begin()?;
    loop {
      let field_ident = i_prot.read_field_begin()?;
      if field_ident.field_type == TType::Stop {
        break;
      }
      let field_id = field_id(&field_ident)?;
      match field_id {
        _ => {
          i_prot.skip(field_ident.field_type)?;
        },
      };
      i_prot.read_field_end()?;
    }
    i_prot.read_struct_end()?;
    let ret = IbrokersPingArgs {};
    Ok(ret)
  }
  fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
    let struct_ident = TStructIdentifier::new("ping_args");
    o_prot.write_struct_begin(&struct_ident)?;
    o_prot.write_field_stop()?;
    o_prot.write_struct_end()
  }
}

//
// IbrokersPingResult
//

#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
struct IbrokersPingResult {
  result_value: Option<i32>,
  error: Option<IBSAPIException>,
}

impl IbrokersPingResult {
  fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<IbrokersPingResult> {
    i_prot.read_struct_begin()?;
    let mut f_0: Option<i32> = None;
    let mut f_1: Option<IBSAPIException> = None;
    loop {
      let field_ident = i_prot.read_field_begin()?;
      if field_ident.field_type == TType::Stop {
        break;
      }
      let field_id = field_id(&field_ident)?;
      match field_id {
        0 => {
          let val = i_prot.read_i32()?;
          f_0 = Some(val);
        },
        1 => {
          let val = IBSAPIException::read_from_in_protocol(i_prot)?;
          f_1 = Some(val);
        },
        _ => {
          i_prot.skip(field_ident.field_type)?;
        },
      };
      i_prot.read_field_end()?;
    }
    i_prot.read_struct_end()?;
    let ret = IbrokersPingResult {
      result_value: f_0,
      error: f_1,
    };
    Ok(ret)
  }
  fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
    let struct_ident = TStructIdentifier::new("IbrokersPingResult");
    o_prot.write_struct_begin(&struct_ident)?;
    if let Some(fld_var) = self.result_value {
      o_prot.write_field_begin(&TFieldIdentifier::new("result_value", TType::I32, 0))?;
      o_prot.write_i32(fld_var)?;
      o_prot.write_field_end()?
    }
    if let Some(ref fld_var) = self.error {
      o_prot.write_field_begin(&TFieldIdentifier::new("error", TType::Struct, 1))?;
      fld_var.write_to_out_protocol(o_prot)?;
      o_prot.write_field_end()?
    }
    o_prot.write_field_stop()?;
    o_prot.write_struct_end()
  }
  fn ok_or(self) -> thrift::Result<i32> {
    if self.error.is_some() {
      Err(thrift::Error::User(Box::new(self.error.unwrap())))
    } else if self.result_value.is_some() {
      Ok(self.result_value.unwrap())
    } else {
      Err(
        thrift::Error::Application(
          ApplicationError::new(
            ApplicationErrorKind::MissingResult,
            "no result received for IbrokersPing"
          )
        )
      )
    }
  }
}

//
// IbrokersIbStatusArgs
//

#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
struct IbrokersIbStatusArgs {
}

impl IbrokersIbStatusArgs {
  fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<IbrokersIbStatusArgs> {
    i_prot.read_struct_begin()?;
    loop {
      let field_ident = i_prot.read_field_begin()?;
      if field_ident.field_type == TType::Stop {
        break;
      }
      let field_id = field_id(&field_ident)?;
      match field_id {
        _ => {
          i_prot.skip(field_ident.field_type)?;
        },
      };
      i_prot.read_field_end()?;
    }
    i_prot.read_struct_end()?;
    let ret = IbrokersIbStatusArgs {};
    Ok(ret)
  }
  fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
    let struct_ident = TStructIdentifier::new("ib_status_args");
    o_prot.write_struct_begin(&struct_ident)?;
    o_prot.write_field_stop()?;
    o_prot.write_struct_end()
  }
}

//
// IbrokersIbStatusResult
//

#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
struct IbrokersIbStatusResult {
  result_value: Option<Vec<String>>,
  error: Option<IBSAPIException>,
}

impl IbrokersIbStatusResult {
  fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<IbrokersIbStatusResult> {
    i_prot.read_struct_begin()?;
    let mut f_0: Option<Vec<String>> = None;
    let mut f_1: Option<IBSAPIException> = None;
    loop {
      let field_ident = i_prot.read_field_begin()?;
      if field_ident.field_type == TType::Stop {
        break;
      }
      let field_id = field_id(&field_ident)?;
      match field_id {
        0 => {
          let list_ident = i_prot.read_list_begin()?;
          let mut val: Vec<String> = Vec::with_capacity(list_ident.size as usize);
          for _ in 0..list_ident.size {
            let list_elem_0 = i_prot.read_string()?;
            val.push(list_elem_0);
          }
          i_prot.read_list_end()?;
          f_0 = Some(val);
        },
        1 => {
          let val = IBSAPIException::read_from_in_protocol(i_prot)?;
          f_1 = Some(val);
        },
        _ => {
          i_prot.skip(field_ident.field_type)?;
        },
      };
      i_prot.read_field_end()?;
    }
    i_prot.read_struct_end()?;
    let ret = IbrokersIbStatusResult {
      result_value: f_0,
      error: f_1,
    };
    Ok(ret)
  }
  fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
    let struct_ident = TStructIdentifier::new("IbrokersIbStatusResult");
    o_prot.write_struct_begin(&struct_ident)?;
    if let Some(ref fld_var) = self.result_value {
      o_prot.write_field_begin(&TFieldIdentifier::new("result_value", TType::List, 0))?;
      o_prot.write_list_begin(&TListIdentifier::new(TType::String, fld_var.len() as i32))?;
      for e in fld_var {
        o_prot.write_string(e)?;
      }
      o_prot.write_list_end()?;
      o_prot.write_field_end()?
    }
    if let Some(ref fld_var) = self.error {
      o_prot.write_field_begin(&TFieldIdentifier::new("error", TType::Struct, 1))?;
      fld_var.write_to_out_protocol(o_prot)?;
      o_prot.write_field_end()?
    }
    o_prot.write_field_stop()?;
    o_prot.write_struct_end()
  }
  fn ok_or(self) -> thrift::Result<Vec<String>> {
    if self.error.is_some() {
      Err(thrift::Error::User(Box::new(self.error.unwrap())))
    } else if self.result_value.is_some() {
      Ok(self.result_value.unwrap())
    } else {
      Err(
        thrift::Error::Application(
          ApplicationError::new(
            ApplicationErrorKind::MissingResult,
            "no result received for IbrokersIbStatus"
          )
        )
      )
    }
  }
}


edit: went ahead and opened a ticket in Thrift [THRIFT-5664] fairly simple .thrift service call in rust , attempts to allocate too much memory and crashes - ASF JIRA

I got a stack trace.. with the most minimal cost I can figure server-side.. if anyone can take a look who is better at rust.. that'd be appreciated. Seems to crash before it can decipher which API call occurs (ie read the message)

The Server Code

mod broken;

extern crate thrift;

use std::collections::HashMap;
use std::sync::Mutex;
use thrift::protocol::{TCompactInputProtocolFactory, TCompactOutputProtocolFactory};
use thrift::transport::{TFramedReadTransportFactory, TFramedWriteTransportFactory};
use thrift::server::TServer;

use broken::{ BrokenSyncHandler, BrokenSyncProcessor, IBSAPIException};

fn main() {
    match run() {
        Ok(()) => println!("server ran successfully"),
        Err(e) => {
            println!("server failed with error {:?}", e);
            std::process::exit(1);
        }
    }
}

fn run() -> thrift::Result<()> {
    // set listen address
    let listen_address = "127.0.0.1:9090";

    // create input protocol/transport factory
    let i_tran_fact = TFramedReadTransportFactory::new();
    let i_prot_fact = TCompactInputProtocolFactory::new();

    // create output  protocol/transport factory
    let o_tran_fact = TFramedWriteTransportFactory::new();
    let o_prot_fact = TCompactOutputProtocolFactory::new();

    // create the server and start listening
    let processor = BrokenSyncProcessor::new(BrokenServerImpl { });
    let mut server = TServer::new(
        i_tran_fact,
        i_prot_fact,
        o_tran_fact,
        o_prot_fact,
        processor,
        10,
    );

    println!("binding to {}", listen_address);
    server.listen(&listen_address)
}


#[derive(Default)]
struct BrokenServerImpl;
impl BrokenSyncHandler for BrokenServerImpl {

    fn handle_ping(&self) -> thrift::Result<i32> {
        println!("pong!");
        let ping_val: thrift::Result<i32> = Ok(0);
        ping_val
    }
}

Result when calling ping via python

import time
from gen_py.broken import broken
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol


class BrokenThriftClient:

    client_connection = None

    def connect_to_thrift_server(self, tws_thrift_host, ib_host_port=9090):

        if self.client_connection is None:
            # Make socket
            transport = TSocket.TSocket(tws_thrift_host, ib_host_port)
            # Buffering is critical. Raw sockets are very slow
            transport = TTransport.TBufferedTransport(transport)
            # Wrap in a protocol
            protocol = TBinaryProtocol.TBinaryProtocol(transport)
            # Create a ibrokers_client to use the protocol encoder
            client = broken.Client(protocol)
            # Connect!
            transport.open()

            self.client_connection = client

        return self.client_connection


if __name__ == "__main__":
    client = BrokenThriftClient()
    client.connect_to_thrift_server(tws_thrift_host="127.0.0.1")
    print(str(client.client_connection.ping()))


thread 'Thrift service processor' panicked at 'capacity overflow', library/alloc/src/raw_vec.rs:518:5
stack backtrace:
   0: rust_begin_unwind
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/panicking.rs:584:5
   1: core::panicking::panic_fmt
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/panicking.rs:142:14
   2: alloc::raw_vec::capacity_overflow
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/alloc/src/raw_vec.rs:518:5
   3: alloc::raw_vec::handle_reserve
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/alloc/src/raw_vec.rs:489:34
   4: alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/alloc/src/raw_vec.rs:285:13
   5: alloc::raw_vec::RawVec<T,A>::reserve
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/alloc/src/raw_vec.rs:289:13
   6: alloc::vec::Vec<T,A>::reserve
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/alloc/src/vec/mod.rs:841:9
   7: alloc::vec::Vec<T,A>::extend_with
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/alloc/src/vec/mod.rs:2400:9
   8: alloc::vec::Vec<T,A>::resize
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/alloc/src/vec/mod.rs:2256:13
   9: <thrift::transport::framed::TFramedReadTransport<C> as std::io::Read>::read
             at /home/emcp/.cargo/registry/src/github.com-1ecc6299db9ec823/thrift-0.16.0/src/transport/framed.rs:97:13
  10: std::io::default_read_exact
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/io/mod.rs:448:15
  11: std::io::Read::read_exact
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/io/mod.rs:805:9
  12: std::io::impls::<impl std::io::Read for alloc::boxed::Box<R>>::read_exact
             at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/io/impls.rs:154:9
  13: <thrift::protocol::compact::TCompactInputProtocol<T> as thrift::protocol::TInputProtocol>::read_byte
             at /home/emcp/.cargo/registry/src/github.com-1ecc6299db9ec823/thrift-0.16.0/src/protocol/compact.rs:300:9
  14: <thrift::protocol::compact::TCompactInputProtocol<T> as thrift::protocol::TInputProtocol>::read_message_begin
             at /home/emcp/.cargo/registry/src/github.com-1ecc6299db9ec823/thrift-0.16.0/src/protocol/compact.rs:105:26
  15: <tws_api_thrift::broken::BrokenSyncProcessor<H> as thrift::server::TProcessor>::process
             at ./src/broken.rs:361:25
  16: thrift::server::threaded::handle_incoming_connection
             at /home/emcp/.cargo/registry/src/github.com-1ecc6299db9ec823/thrift-0.16.0/src/server/threaded.rs:234:15
  17: thrift::server::threaded::TServer<PRC,RTF,IPF,WTF,OPF>::listen::{{closure}}
             at /home/emcp/.cargo/registry/src/github.com-1ecc6299db9ec823/thrift-0.16.0/src/server/threaded.rs:184:42
  18: <F as threadpool::FnBox>::call_box
             at /home/emcp/.cargo/registry/src/github.com-1ecc6299db9ec823/threadpool-1.8.1/src/lib.rs:95:9
  19: threadpool::spawn_in_pool::{{closure}}
             at /home/emcp/.cargo/registry/src/github.com-1ecc6299db9ec823/threadpool-1.8.1/src/lib.rs:769:17
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
^C