Exception handling

We support exception handling by catching thrown exception objects in the source language and rethrowing them in the target language. The user must mention the possible thrown exception classes for each method. For this purpose, we have a throws variable, which must contain throwable exceptions. The definition of that list variable looks like this:

    /**
     * __API__
     * action: gen_constructor
     * throws:
     *   - std::invalid_argument
     */
     ThrowExc(bool do_throw=false) {
        if (do_throw) throw std::invalid_argument("inv_arg");
     }

    /**
     * __API__
     * action: gen_method
     * throws:
     *   - std::out_of_range
     *   - cppbind::example::SystemError
     */
    static int getByKey(const std::map<int, int>& m, int key) {
        return m.at(key);
    }

    /**
     * Throws exception with return value of type string.
     * __API__
     * action: gen_method
     * throws: std::invalid_argument
     */
    static std::string throwsWithReturnValueString() {
        throw std::invalid_argument("return value error");
    }

    /**
     * Throws exception with return value of cppbind type.
     * __API__
     * action: gen_method
     * throws: std::invalid_argument
     */
    static cppbind::example::Task* throwsWithReturnValuePtr() {
        throw std::invalid_argument("return value error");
    }

throws variable is mandatory for methods, constructors, and functions (also for getters and setters). If a method doesn’t throw an exception, the user must set the parameter value to a special no_throw value. It is made as a requirement to ensure the user hasn’t forgotten about the throw ability of the method. An example of an empty exception list looks like this:

    /**
    * __API__
    * action: gen_method
    * throws: no_throw
    */
    virtual int errNum() {
        return err_num;
    }

Note

The order of listed exception classes in the throws variable is important. We preserve user-defined orders when catching/rethrowing exceptions.

Note

Swift language doesn’t support exception throwing from getter/setter, so the user should set the value of the throws variable to no_throw. CppBind complains about the wrong usage of throws.

The exception list can contain standard exception classes and user-defined exception classes with API annotations. On the target language side, we keep correspondence between those classes, and for this purpose, we also generate standard exceptions binding to the target language. We define binding rules for std::exception and its descendant classes, and the CppBind tool generates bindings for us. We define rules in the yaml config file, which looks like this:

# Copyright (c) 2022 PicsArt, Inc.
# All rights reserved. Use of this source code is governed by a
# MIT-style license that can be found in the LICENSE file.

- type: "std::exception"
  vars:
    action: gen_class
    python.action:
    name: StdException
    package_prefix: "{{helpers_package_prefix}}"
    package: "{{exception_helpers_package}}"
    file: "{{exception_file_name}}"
    is_exception: True
    include_cxx:
      - <stdexcept>
      - <new>
      - <typeinfo>

- type: "std::exception::what()"
  vars:
    action: gen_method
    python.action:
    throws: no_throw

- type: "std::runtime_error"
  vars:
    action: gen_class
    python.action:
    name: StdRuntimeError
    package_prefix: "{{helpers_package_prefix}}"
    package: "{{exception_helpers_package}}"
    file: "{{exception_file_name}}"

Note

Since we generate try/catch blocks in C bindings for catching an exception, we use C++ std exception classes, and therefore we need to include the header files where std exceptions are defined. Those header files are included via the include_cxx variable (which you can see in the example above). Here are the required includes:

#include <stdexcept>
#include <new>
#include <typeinfo>

If a user-defined exception is derived from std::exception, it is automatically throwable in the target language. If the user wants a class not to be derived from std::exception but to be throwable in the target language, the is_exception variable must be set to True (default value is False).

Note

User-defined exception classes must have a copy constructor since we copy the exception object before rethrowing it in the target language. We need this since the original exception object is deleted after its lifetime is ended.

If we catch an exception, not from the user-defined list, we report an unexpected exception and call an uncaught exception handler callback. We define an exception utility package that includes ExceptionHandler class to handle uncaught exception cases. The default handler aborts program execution immediately, but the user can set a custom callback, which will be called after an unhandled exception is detected. The mentioned package looks like this:

/**
 *   ______ .______   .______   .______    __  .__   __.  _______  
 *  /      ||   _  \  |   _  \  |   _  \  |  | |  \ |  | |       \ 
 * |  ,----'|  |_)  | |  |_)  | |  |_)  | |  | |   \|  | |  .--.  |
 * |  |     |   ___/  |   ___/  |   _  <  |  | |  . `  | |  |  |  |
 * |  `----.|  |      |  |      |  |_)  | |  | |  |\   | |  '--'  |
 *  \______|| _|      | _|      |______/  |__| |__| \__| |_______/ 
 * 
 * This file is generated by cppbind on 06/23/2021-14:46.
 * Please do not change it manually.
 */

package com.examples.cppbind.exceptionUtils

import kotlin.system.exitProcess

public class ExceptionHandler {
    companion object {
        private var uncaughtExceptionHandler = {errMsg: String -> defaultHandler(errMsg)}

        fun defaultHandler(errMsg: String) {
            println("Uncaught exception is found: ${errMsg}")
            exitProcess(1)
        }

        @JvmStatic
        fun handleUncaughtException(errMsg: String) {
            uncaughtExceptionHandler(errMsg)
        }

        fun setUncaughtExceptionHandler(handler: (String) -> Unit) {
            uncaughtExceptionHandler = {errMsg: String -> handler(errMsg)}
        }

        fun unsetUncaughtExceptionHandler() {
            uncaughtExceptionHandler = {errMsg: String -> defaultHandler(errMsg)}
        }
    }
}
/**
 *   ______ .______   .______   .______    __  .__   __.  _______
 *  /      ||   _  \  |   _  \  |   _  \  |  | |  \ |  | |       \
 * |  ,----'|  |_)  | |  |_)  | |  |_)  | |  | |   \|  | |  .--.  |
 * |  |     |   ___/  |   ___/  |   _  <  |  | |  . `  | |  |  |  |
 * |  `----.|  |      |  |      |  |_)  | |  | |  |\   | |  '--'  |
 *  \______|| _|      | _|      |______/  |__| |__| \__| |_______/
 * 
 * This file is generated by cppbind on 07/21/2021-07:17.
 * Please do not change it manually.
 */

public class ExceptionHandler {

    static var uncaughtExceptionHandler = defaultHandler

    static func defaultHandler(_ err_msg: String) -> Never {
        print("Uncaught exception is found: \(err_msg)")
        fatalError("Unexpected Exception")
    }

    static func handleUncaughtException(_ err_msg : String) -> Never {
        uncaughtExceptionHandler(err_msg)
    }

    public static func setUncaughtExceptionHandler(_ handler: @escaping (String) -> Never) {
        uncaughtExceptionHandler = handler
    }

    public static func unsetUncaughtExceptionHandler() {
        uncaughtExceptionHandler = defaultHandler
    }
}

Also, we always catch std::exception before catching all exceptions to have a more informative error message when the exception class is derived from std::exception.

Note

We use the pybind tool to generate Python bindings, which already has support for exception handling. Pybind translates C++ standard exceptions to their Python analogs using an exception correspondence map. Pybind translates all user-defined exceptions to RuntimeError in Python. This support also sets some constraints on us, so currently, we don’t support Python exceptions as it’s done for other languages. The user-defined exceptions list is not relevant here, but the user still must define the throws variable to the no_throw value. This requirement keeps API annotations style convenient between all target languages.

After generating bindings for the target language, we can call methods that can throw an exception and test results with catch blocks:

try {
    ThrowExc.getByKey(mapOf(1 to 1), 0)
} catch (e: StdOutOfRange) {
    assert(e.what().contains("map::at"))
} catch (e: Exception) {
    assert(false)
}

// assert everything is ok for returned pointer value when an exception is raised
try {
  ThrowExc.throwsWithReturnValuePtr()
} catch (e: StdInvalidArgument) {
    assert(e.what() == "return value error")
} catch (e: Exception) {
  assert(false)
}

// assert everything is ok for returned string value when an exception is raised
try {
    ThrowExc.throwsWithReturnValueString()
} catch (e: StdInvalidArgument) {
    assert(e.what() == "return value error")
} catch (e: Exception) {
    assert(false)
}

// checking throwing constructor
try {
    ThrowExc(true)
    assert(false)
} catch (e: StdInvalidArgument) {
    assert(e.what() == "inv_arg")
} catch (e: Exception) {
    assert(false)
}

try {
    MiscExc.returnInteger(true)
    assert(false)
} catch (e: StdOutOfRange) {
    assert(e.what() == "error")
} catch (e: Exception) {
    assert(false)
}

try {
    MiscExc.raiseErrorByType("simple_child")
} catch (e: SimpleChildException) {
    assert(e.errNum() == 100)
} catch (e: Exception) {
    assert(false)
}
let result = try? ThrowExc.getByKey(m: [1 : 1], key: 0)
assert(result == nil)

do {
    let _ = try ThrowExc.getByKey(m: [1 : 1], key: 0)
} catch is StdOutOfRange {
} catch {
    assert(false)
}

// assert everything is ok for returned pointer value when an exception is raised
do {
  let _ = try ThrowExc.throwsWithReturnValuePtr()
} catch let err as StdInvalidArgument {
  assert(err.what() == "return value error")
} catch {
  assert(false)
}

// assert everything is ok for returned string value when an exception is raised
do {
    let _ = try ThrowExc.throwsWithReturnValueString()
} catch let err as StdInvalidArgument {
    assert(err.what() == "return value error")
} catch {
    assert(false)
}

// checking throwing constructor
do {
    let _ = try ThrowExc(doThrow: true)
} catch let err as StdInvalidArgument {
    assert(err.what() == "inv_arg")
} catch {
    assert(false)
}

do {
    let _ = try MiscExc.returnInteger(doThrow: true)
    assert(false)
} catch is StdOutOfRange {
} catch {
    assert(false)
}

do {
    try MiscExc.raiseErrorByType(errType: "simple_child")
} catch let err as SimpleChildException {
    assert(err.errNum() == 100)
} catch {
    assert(false)
}

Note

In the last usage example, you can notice that we called the custom exception class method when an exception was caught. When a custom exception class and its methods have API annotations, we have corresponding bindings, and thus we can use class methods.

Binding codes when "throws" exception list is not empty

/**
 *   ______ .______   .______   .______    __  .__   __.  _______  
 *  /      ||   _  \  |   _  \  |   _  \  |  | |  \ |  | |       \ 
 * |  ,----'|  |_)  | |  |_)  | |  |_)  | |  | |   \|  | |  .--.  |
 * |  |     |   ___/  |   ___/  |   _  <  |  | |  . `  | |  |  |  |
 * |  `----.|  |      |  |      |  |_)  | |  | |  |\   | |  '--'  |
 *  \______|| _|      | _|      |______/  |__| |__| \__| |_______/ 
 * 
 * This file is generated by cppbind on 05/12/2022-10:29.
 * Please do not change it manually.
 */

package com.examples.exceptions

import com.examples.cppbind.alias.*
import com.examples.cppbind.exceptionUtils.*
import com.examples.cppbind.exception_helpers.*
import com.examples.simple.Task

private val INIT = run {
    System.loadLibrary("wrapper_jni");
}

/**
 * An example of a global function throwing an exception.
 */
fun throwExc(do_throw: Boolean = false): Unit {
    val result = jThrowexc(do_throw)
    
    return result
}

open class ThrowExc
internal constructor(obj: CppBindObject) : AutoCloseable {
    companion object {
        init {
            System.loadLibrary("wrapper_jni")
        }
        
        protected fun construct_helper(do_throw: Boolean): Long {
            val id = jConstructor(do_throw)
            return id
        }

        @JvmStatic
        private external fun jConstructor(do_throw: Boolean): Long

        fun getByKey(m: Map<Int, Int>, key: Int): Int {
            
            val tmp_key_kotlintojdkm = IntArray(m.size) 
            val tmp_val_kotlintojdkm = IntArray(m.size) 
            val kotlintojdkm = Pair<IntArray, IntArray>(tmp_key_kotlintojdkm, tmp_val_kotlintojdkm)
            var index_m = 0
            for ((key_m, value_m) in m) {
                
                
                tmp_key_kotlintojdkm[index_m] = key_m
                tmp_val_kotlintojdkm[index_m] = value_m
                ++index_m
            }
            val result = jGetbykey(kotlintojdkm, key)
            
            return result
        }
        @JvmStatic
        private external fun jGetbykey(m: Pair<IntArray, IntArray>, key: Int): Int

        /**
         * Throws exception with return value of type string.
         */
        fun throwsWithReturnValueString(): String {
            val result = jThrowswithreturnvaluestring()
            
            return result
        }
        @JvmStatic
        private external fun jThrowswithreturnvaluestring(): String

        /**
         * Throws exception with return value of cppbind type.
         */
        fun throwsWithReturnValuePtr(): Task {
            val result = jThrowswithreturnvalueptr()
            val jdktokotlinresult = Task(CppBindObject(result, true))
            return jdktokotlinresult
        }
        @JvmStatic
        private external fun jThrowswithreturnvalueptr(): Long
        const val cppbindCxxTypeName: String = "cppbind::exceptions::ThrowExc"
    }
    
    protected var cppbindObj = obj
    private var refs: MutableList<Any> = mutableListOf()

    fun keepCppBindReference(ref: Any) {
        refs.add(ref)
    }
    
    open val id: Long
        get() {
            if (cppbindObj.id == 0L) {
                throw RuntimeException("Object is not allocated")
            }
            return cppbindObj.id
        }
    
    constructor(do_throw: Boolean = false): this(CppBindObject(construct_helper(do_throw), true)) {
    }
    
    var prop: String
        get() {
            val result = jProp(id)
            
            return result
        }
        set(value) {
            
            jSetprop(id, value)
        }

    override fun close() {
        if (cppbindObj.owner && cppbindObj.id != 0L) {
            jFinalize(cppbindObj.id)
            cppbindObj.id = 0L
        }
    }

    /**
     * Finalize and deletes the object
     */
    protected fun finalize() {
        close()
    }

    ///// External wrapper functions ////////////
    private external fun jProp(id: Long): String
    private external fun jSetprop(id: Long, value: String): Unit
    private external fun jFinalize(id: Long): Unit
}

private external fun jThrowexc(do_throw: Boolean): Unit

private external fun jGettypebyid(id: Long): String
/**
 *   ______ .______   .______   .______    __  .__   __.  _______  
 *  /      ||   _  \  |   _  \  |   _  \  |  | |  \ |  | |       \ 
 * |  ,----'|  |_)  | |  |_)  | |  |_)  | |  | |   \|  | |  .--.  |
 * |  |     |   ___/  |   ___/  |   _  <  |  | |  . `  | |  |  |  |
 * |  `----.|  |      |  |      |  |_)  | |  | |  |\   | |  '--'  |
 *  \______|| _|      | _|      |______/  |__| |__| \__| |_______/ 
 * 
 * This file is generated by cppbind on 05/12/2022-10:26.
 * Please do not change it manually.
 */

import CWrapper
import Foundation

/**
 * An example of a global function throwing an exception.
 */
public func throwExc(doThrow: Bool = false) throws -> Void {
  var cppbindErr = CppBindCObject()
  _func_CppbindExceptions_throwExc(doThrow, &cppbindErr)
  if cppbindErr.type != nil {
    let errorType = String(cString: cppbindErr.type!)
    switch errorType {
    case ("std::invalid_argument"):
      throw StdInvalidArgument(cppbindErr, true)
    case ("std::exception"):
      let excObj = StdException(cppbindErr, true)
      ExceptionHandler.handleUncaughtException(excObj.what())
    default:
      cppbindErr.type.deallocate()
      ExceptionHandler.handleUncaughtException("Uncaught Exception")
    }
  }
}

public class ThrowExc {

  public let cself: CppBindCObject
  public let owner: Bool
  private var refs: [Any]

  /// internal main initializer
  internal required init(_ _cself: CppBindCObject, _ _owner: Bool = false) {
    self.cself = _cself
    self.owner = _owner
    self.refs = []
  }

  deinit {
    release_CppbindExceptions_ThrowExc(cself, owner)
  }

  public func keepCppBindReference(_ object: Any) {
    self.refs.append(object)
  }

  public convenience init(doThrow: Bool = false) throws {
    var cppbindErr = CppBindCObject()
    self.init(create_CppbindExceptions_ThrowExc(doThrow, &cppbindErr), true)
    if cppbindErr.type != nil {
      let errorType = String(cString: cppbindErr.type!)
      switch errorType {
      case ("std::invalid_argument"):
        throw StdInvalidArgument(cppbindErr, true)
      case ("std::exception"):
        let excObj = StdException(cppbindErr, true)
        ExceptionHandler.handleUncaughtException(excObj.what())
      default:
        cppbindErr.type.deallocate()
        ExceptionHandler.handleUncaughtException("Uncaught Exception")
      }
    }
  }

  /**
   * An example to check swift throwing property getter
   */
  public var prop1: String {
    get {
      var cppbindErr = CppBindCObject()
      let result = _prop_get_CppbindExceptions_ThrowExc_prop1(cself, &cppbindErr)
      if cppbindErr.type != nil {
        let errorType = String(cString: cppbindErr.type!)
        switch errorType {
        case ("std::exception"):
          let excObj = StdException(cppbindErr, true)
          ExceptionHandler.handleUncaughtException(excObj.what())
        default:
          cppbindErr.type.deallocate()
          ExceptionHandler.handleUncaughtException("Uncaught Exception")
        }
      }
      let sctoswiftresult = String(cString: result)
      defer {
        result.deallocate()
      }
      return sctoswiftresult
    }

    set(value) {
      let swifttoscvalue = strdup(value)!
      var cppbindErr = CppBindCObject()
      _prop_set_CppbindExceptions_ThrowExc_prop1(cself, swifttoscvalue, &cppbindErr)
      if cppbindErr.type != nil {
        let errorType = String(cString: cppbindErr.type!)
        switch errorType {
        case ("std::exception"):
          let excObj = StdException(cppbindErr, true)
          ExceptionHandler.handleUncaughtException(excObj.what())
        default:
          cppbindErr.type.deallocate()
          ExceptionHandler.handleUncaughtException("Uncaught Exception")
        }
      }
    }
  }

  public static func getByKey(m: Dictionary<Int, Int>, key: Int) throws -> Int {

    let _swifttoscmKey = UnsafeMutablePointer<CInt>.allocate(
      capacity: m.count)
    let _swifttoscmVal = UnsafeMutablePointer<CInt>.allocate(
      capacity: m.count)
    var swifttoscm = CppBindCDataMap()
    swifttoscm.keys = UnsafeMutableRawPointer(_swifttoscmKey)
    swifttoscm.values = UnsafeMutableRawPointer(_swifttoscmVal)
    swifttoscm.size = Int64(m.count)
    var mIdx = 0
    for (mKey, mVal) in m {
      let swifttoscmKey = CInt(mKey)
      let swifttoscmVal = CInt(mVal)
      _swifttoscmKey[mIdx] = swifttoscmKey
      _swifttoscmVal[mIdx] = swifttoscmVal
      mIdx += 1
    }
    let swifttosckey = CInt(key)
    var cppbindErr = CppBindCObject()
    let result = _func_CppbindExceptions_ThrowExc_getByKey(swifttoscm, swifttosckey, &cppbindErr)
    
    swifttoscm.keys.deallocate()
    swifttoscm.values.deallocate()
    if cppbindErr.type != nil {
      let errorType = String(cString: cppbindErr.type!)
      switch errorType {
      case ("std::out_of_range"):
        throw StdOutOfRange(cppbindErr, true)
      case ("cppbind::example::SystemError"):
        throw SystemError(cppbindErr, true)
      case ("std::exception"):
        let excObj = StdException(cppbindErr, true)
        ExceptionHandler.handleUncaughtException(excObj.what())
      default:
        cppbindErr.type.deallocate()
        ExceptionHandler.handleUncaughtException("Uncaught Exception")
      }
    }
    let sctoswiftresult = Int(result)
    return sctoswiftresult
  }

  /**
   * Throws exception with return value of type string.
   */
  public static func throwsWithReturnValueString() throws -> String {

    var cppbindErr = CppBindCObject()
    let result = _func_CppbindExceptions_ThrowExc_throwsWithReturnValueString(&cppbindErr)
    if cppbindErr.type != nil {
      let errorType = String(cString: cppbindErr.type!)
      switch errorType {
      case ("std::invalid_argument"):
        throw StdInvalidArgument(cppbindErr, true)
      case ("std::exception"):
        let excObj = StdException(cppbindErr, true)
        ExceptionHandler.handleUncaughtException(excObj.what())
      default:
        cppbindErr.type.deallocate()
        ExceptionHandler.handleUncaughtException("Uncaught Exception")
      }
    }
    let sctoswiftresult = String(cString: result)
    defer {
      result.deallocate()
    }
    return sctoswiftresult
  }

  /**
   * Throws exception with return value of cppbind type.
   */
  public static func throwsWithReturnValuePtr() throws -> Task {

    var cppbindErr = CppBindCObject()
    let result = _func_CppbindExceptions_ThrowExc_throwsWithReturnValuePtr(&cppbindErr)
    if cppbindErr.type != nil {
      let errorType = String(cString: cppbindErr.type!)
      switch errorType {
      case ("std::invalid_argument"):
        throw StdInvalidArgument(cppbindErr, true)
      case ("std::exception"):
        let excObj = StdException(cppbindErr, true)
        ExceptionHandler.handleUncaughtException(excObj.what())
      default:
        cppbindErr.type.deallocate()
        ExceptionHandler.handleUncaughtException("Uncaught Exception")
      }
    }
    var sctoswiftresult: Task
    sctoswiftresult = Task(result, true)
    return sctoswiftresult
  }

  class var cppbindCxxTypeName : String { return "cppbind::exceptions::ThrowExc" }
}

Binding codes when the exception list is empty (throws=True)

/**
 *   ______ .______   .______   .______    __  .__   __.  _______  
 *  /      ||   _  \  |   _  \  |   _  \  |  | |  \ |  | |       \ 
 * |  ,----'|  |_)  | |  |_)  | |  |_)  | |  | |   \|  | |  .--.  |
 * |  |     |   ___/  |   ___/  |   _  <  |  | |  . `  | |  |  |  |
 * |  `----.|  |      |  |      |  |_)  | |  | |  |\   | |  '--'  |
 *  \______|| _|      | _|      |______/  |__| |__| \__| |_______/ 
 * 
 * This file is generated by cppbind on 05/12/2022-10:29.
 * Please do not change it manually.
 */

package com.examples.exceptions

import com.examples.cppbind.alias.*
import com.examples.cppbind.exceptionUtils.*
import com.examples.cppbind.exception_helpers.*

open class NoThrowExc
internal constructor(obj: CppBindObject) : AutoCloseable {
    companion object {
        init {
            System.loadLibrary("wrapper_jni")
        }
        
        protected fun construct_helper(do_throw: Boolean): Long {
            val id = jConstructor(do_throw)
            return id
        }

        @JvmStatic
        private external fun jConstructor(do_throw: Boolean): Long

        fun noop(): Unit {
            val result = jNoop()
            
            return result
        }
        @JvmStatic
        private external fun jNoop(): Unit
        const val cppbindCxxTypeName: String = "cppbind::exceptions::NoThrowExc"
    }
    
    protected var cppbindObj = obj
    private var refs: MutableList<Any> = mutableListOf()

    fun keepCppBindReference(ref: Any) {
        refs.add(ref)
    }
    
    open val id: Long
        get() {
            if (cppbindObj.id == 0L) {
                throw RuntimeException("Object is not allocated")
            }
            return cppbindObj.id
        }
    
    constructor(do_throw: Boolean = false): this(CppBindObject(construct_helper(do_throw), true)) {
    }
    
    var prop: String
        get() {
            val result = jProp(id)
            
            return result
        }
        set(value) {
            
            jSetprop(id, value)
        }

    override fun close() {
        if (cppbindObj.owner && cppbindObj.id != 0L) {
            jFinalize(cppbindObj.id)
            cppbindObj.id = 0L
        }
    }

    /**
     * Finalize and deletes the object
     */
    protected fun finalize() {
        close()
    }

    ///// External wrapper functions ////////////
    private external fun jProp(id: Long): String
    private external fun jSetprop(id: Long, value: String): Unit
    private external fun jFinalize(id: Long): Unit
}

private external fun jGettypebyid(id: Long): String

Note

For Kotlin we rethrow caught exception from C binding via JNI special functions. It means that exception handling section of code is written in C binding file. Here is an example of C binding file.

/**
 *   ______ .______   .______   .______    __  .__   __.  _______  
 *  /      ||   _  \  |   _  \  |   _  \  |  | |  \ |  | |       \ 
 * |  ,----'|  |_)  | |  |_)  | |  |_)  | |  | |   \|  | |  .--.  |
 * |  |     |   ___/  |   ___/  |   _  <  |  | |  . `  | |  |  |  |
 * |  `----.|  |      |  |      |  |_)  | |  | |  |\   | |  '--'  |
 *  \______|| _|      | _|      |______/  |__| |__| \__| |_______/ 
 * 
 * This file is generated by cppbind on 05/12/2022-10:26.
 * Please do not change it manually.
 */

import CWrapper
import Foundation

public class NoThrowExc {

  public let cself: CppBindCObject
  public let owner: Bool
  private var refs: [Any]

  /// internal main initializer
  internal required init(_ _cself: CppBindCObject, _ _owner: Bool = false) {
    self.cself = _cself
    self.owner = _owner
    self.refs = []
  }

  deinit {
    release_CppbindExceptions_NoThrowExc(cself, owner)
  }

  public func keepCppBindReference(_ object: Any) {
    self.refs.append(object)
  }

  public convenience init(doThrow: Bool = false) {
    var cppbindErr = CppBindCObject()
    self.init(create_CppbindExceptions_NoThrowExc(doThrow, &cppbindErr), true)
    if cppbindErr.type != nil {
      let errorType = String(cString: cppbindErr.type!)
      switch errorType {
      case ("std::exception"):
        let excObj = StdException(cppbindErr, true)
        ExceptionHandler.handleUncaughtException(excObj.what())
      default:
        cppbindErr.type.deallocate()
        ExceptionHandler.handleUncaughtException("Uncaught Exception")
      }
    }
  }

  public var prop: String {
    get {
      var cppbindErr = CppBindCObject()
      let result = _prop_get_CppbindExceptions_NoThrowExc_prop(cself, &cppbindErr)
      if cppbindErr.type != nil {
        let errorType = String(cString: cppbindErr.type!)
        switch errorType {
        case ("std::exception"):
          let excObj = StdException(cppbindErr, true)
          ExceptionHandler.handleUncaughtException(excObj.what())
        default:
          cppbindErr.type.deallocate()
          ExceptionHandler.handleUncaughtException("Uncaught Exception")
        }
      }
      let sctoswiftresult = String(cString: result)
      defer {
        result.deallocate()
      }
      return sctoswiftresult
    }

    set(value) {
      let swifttoscvalue = strdup(value)!
      var cppbindErr = CppBindCObject()
      _prop_set_CppbindExceptions_NoThrowExc_prop(cself, swifttoscvalue, &cppbindErr)
      if cppbindErr.type != nil {
        let errorType = String(cString: cppbindErr.type!)
        switch errorType {
        case ("std::exception"):
          let excObj = StdException(cppbindErr, true)
          ExceptionHandler.handleUncaughtException(excObj.what())
        default:
          cppbindErr.type.deallocate()
          ExceptionHandler.handleUncaughtException("Uncaught Exception")
        }
      }
    }
  }

  public static func noop() -> Void {

    var cppbindErr = CppBindCObject()
    _func_CppbindExceptions_NoThrowExc_noop(&cppbindErr)
    if cppbindErr.type != nil {
      let errorType = String(cString: cppbindErr.type!)
      switch errorType {
      case ("std::exception"):
        let excObj = StdException(cppbindErr, true)
        ExceptionHandler.handleUncaughtException(excObj.what())
      default:
        cppbindErr.type.deallocate()
        ExceptionHandler.handleUncaughtException("Uncaught Exception")
      }
    }
  }

  class var cppbindCxxTypeName : String { return "cppbind::exceptions::NoThrowExc" }
}