import logging
import os.path
import re
import sys
import textwrap
from pprint import pformat
from string import Template
if sys.version_info[0] >= 3:
from io import StringIO
else:
from cStringIO import StringIO
def template(text):
return Template(textwrap.dedent(text))
ManualFuncs = {
"core": (
["cv.Mat.size", "Size", ["/C"], []],
)
}
cross_modules_deps = {
"core": (
["class cv.Mat", "", ["/Ghost"], []],
["class cv.Algorithm", "", ["/Ghost"], []],
["class cv.DMatch", "", ["/Ghost", "/Simple"], []],
["class cv.KeyPoint", "", ["/Ghost", "/Simple"], []],
["class cv.RotatedRect", "", ["/Ghost"], []],
["class cv.TermCriteria", "", ["/Ghost"], []],
["class cv.Range", "", ["/Ghost"], []],
)
}
renamed_funcs = { "cv_findEssentialMat_Mat_points1_Mat_points2_Mat_cameraMatrix_int_method_double_prob_double_threshold_Mat_mask": "find_essential_map_matrix",
"cv_findHomography_Mat_srcPoints_Mat_dstPoints_int_method_double_ransacReprojThreshold_Mat_mask_int_maxIters_double_confidence": "find_homography_full",
"cv_fisheye_projectPoints_Mat_objectPoints_Mat_imagePoints_Mat_rvec_Mat_tvec_Mat_K_Mat_D_double_alpha_Mat_jacobian": "fisheye_project_points",
"cv_fisheye_undistortImage_Mat_distorted_Mat_undistorted_Mat_K_Mat_D_Mat_Knew_Size_new_size": "fisheye_undistort_image",
"cv_fisheye_undistortPoints_Mat_distorted_Mat_undistorted_Mat_K_Mat_D_Mat_R_Mat_P": "fisheye_undistort_points",
"cv_recoverPose_Mat_E_Mat_points1_Mat_points2_Mat_cameraMatrix_Mat_R_Mat_t_Mat_mask": "recover_pose_matrix",
"cv_MatExpr_type" : "typ",
"cv_Mat_Mat": "new",
"cv_Mat_Mat_Mat_m": "copy",
"cv_Mat_Mat_Mat_m_Range_ranges": "ranges",
"cv_Mat_Mat_Mat_m_Range_rowRange_Range_colRange": "rowscols",
"cv_Mat_Mat_Mat_m_Rect_roi": "roi",
"cv_Mat_Mat_Size_size_int_type": "new_size",
"cv_Mat_Mat_Size_size_int_type_Scalar_s": "new_size_with_default",
"cv_Mat_Mat_int_rows_int_cols_int_type": "new_rows_cols",
"cv_Mat_Mat_int_rows_int_cols_int_type_Scalar_s": "new_rows_cols_with_default",
"cv_Mat_colRange_Range_r": "colrange",
"cv_Mat_colRange_int_startcol_int_endcol": "colbounds",
"cv_Mat_copyTo_Mat_m_Mat_mask": "copy_to_masked",
"cv_Mat_create_Size_size_int_type": "-",
"cv_Mat_create_int_rows_int_cols_int_type": "-",
"cv_Mat_diag_Mat_d": "diag_new_mat",
"cv_Mat_diag_int_d": "diag",
"cv_Mat_ptr_int_i0": "ptr_row",
"cv_Mat_ptr_int_row_int_col": "ptr_2d",
"cv_Mat_ptr_int_i0_int_i1_int_i2": "ptr_3d",
"cv_Mat_resize_size_t_sz": "resize",
"cv_Mat_resize_size_t_sz_Scalar_s": "resize_with_default",
"cv_Mat_rowRange_Range_r": "rowRange",
"cv_Mat_rowRange_int_startrow_int_endrow": "rowbounds",
"cv_Mat_type": "typ",
"cv_PCA_PCA": "default",
"cv_PCA_PCA_Mat_data_Mat_mean_int_flags_double_retainedVariance": "new_mat_variance",
"cv_PCA_PCA_Mat_data_Mat_mean_int_flags_int_maxComponents": "new_mat_max",
"cv_PCA_backProject_Mat_vec_Mat_result": "back_project_to",
"cv_PCA_project_Mat_vec_Mat_result": "project_to",
"cv_PCACompute_Mat_data_Mat_mean_Mat_eigenvectors_double_retainedVariance": "pca_compute_variance",
"cv_PCACompute_Mat_data_Mat_mean_Mat_eigenvectors_int_maxComponents": "pca_compute",
"cv_Range_Range": "default",
"cv_Range_Range_int__start_int__end": "new",
"cv_RotatedRect_RotatedRect": "default",
"cv_RotatedRect_RotatedRect_Point2f_center_Size2f_size_float_angle": "new",
"cv_RotatedRect_RotatedRect_Point2f_point1_Point2f_point2_Point2f_point3": "for_points",
"cv_TermCriteria_TermCriteria": "default",
"cv_TermCriteria_TermCriteria_int_type_int_maxCount_double_epsilon": "new",
"cv_UMat_type": "typ",
"cv_UMat_copyTo_Mat_m": "copy_to",
"cv_UMat_copyTo_Mat_m_Mat_mask": "copy_to_masked",
"cv_calcCovarMatrix_Mat_samples_Mat_covar_Mat_mean_int_flags_int_ctype": "calc_covar_matrix_arrays",
"cv_calcCovarMatrix_Mat_samples_int_nsamples_Mat_covar_Mat_mean_int_flags_int_ctype": "calc_covar_matrix",
"cv_clipLine_Size_imgSize_Point_pt1_Point_pt2": "clip_line_size",
"cv_clipLine_Size2l_imgSize_Point2l_pt1_Point2l_pt2": "clip_line_size_i64",
"cv_clipLine_Rect_imgRect_Point_pt1_Point_pt2": "clip_line",
"cv_cv_abs_short_x": "-",
"cv_cv_abs_uchar_x": "-",
"cv_divide_double_scale_Mat_src2_Mat_dst_int_dtype": "divide",
"cv_divide_Mat_src1_Mat_src2_Mat_dst_double_scale_int_dtype": "divide_mat",
"cv_ellipse_Mat_img_Point_center_Size_axes_double_angle_double_startAngle_double_endAngle_Scalar_color_int_thickness_int_lineType_int_shift": "ellipse",
"cv_ellipse_Mat_img_RotatedRect_box_Scalar_color_int_thickness_int_lineType": "ellipse_new_rotated_rect",
"cv_ellipse2Poly_Point2d_center_Size2d_axes_int_angle_int_arcStart_int_arcEnd_int_delta_VectorOfPoint2d_pts": "ellipse2_poly_f64",
"cv_hconcat_Mat_src_size_t_nsrc_Mat_dst": "-",
"cv_max_Mat_src1_Mat_src2_Mat_dst": "max_mat_mat",
"cv_max_Mat_src1_double_src2_Mat_dst": "max_mat",
"cv_merge_Mat_mv_size_t_count_Mat_dst": "-",
"cv_min_Mat_src1_Mat_src2_Mat_dst": "min_mat_mat",
"cv_norm_Mat_src1_Mat_src2_int_normType_Mat_mask": "norm_with_type",
"cv_norm_Mat_src1_int_normType_Mat_mask": "norm",
"cv_rectangle_Mat_img_Point_pt1_Point_pt2_Scalar_color_int_thickness_int_lineType_int_shift": "rectangle_points",
"cv_rectangle_Mat_img_Rect_rec_Scalar_color_int_thickness_int_lineType_int_shift": "rectangle",
"cv_repeat_Mat_src_int_ny_int_nx_Mat_dst": "repeat_to",
"cv_repeat_Mat_src_int_ny_int_nx": "repeat",
"cv_split_Mat_m_VectorOfMat_mv": "split",
"cv_split_Mat_src_Mat_mvbegin": "split_at",
"cv_vconcat_Mat_src_size_t_nsrc_Mat_dst": "-",
"cv_AGAST_Mat_image_VectorOfKeyPoint_keypoints_int_threshold_bool_nonmaxSuppression": "AGAST",
"cv_AGAST_Mat_image_VectorOfKeyPoint_keypoints_int_threshold_bool_nonmaxSuppression_int_type": "AGAST_with_type",
"cv_BOWKMeansTrainer_cluster": "default",
"cv_BOWKMeansTrainer_cluster_Mat_descriptors": "new",
"cv_BOWKMeansTrainer_BOWKMeansTrainer_int_clusterCount_TermCriteria_termcrit_int_attempts_int_flags": "new_with_criteria",
"cv_BOWImgDescriptorExtractor_compute_Mat_keypointDescriptors_Mat_imgDescriptor_VectorOfVectorOfint_pointIdxsOfClusters": "compute",
"cv_BOWImgDescriptorExtractor_compute_Mat_image_VectorOfKeyPoint_keypoints_Mat_imgDescriptor_VectorOfVectorOfint_pointIdxsOfClusters_Mat_descriptors": "compute_desc",
"cv_DMatch_DMatch": "default",
"cv_DMatch_DMatch_int__queryIdx_int__trainIdx_float__distance": "new",
"cv_DMatch_DMatch_int__queryIdx_int__trainIdx_int__imgIdx_float__distance": "new_index",
"cv_DescriptorMatcher_knnMatch_Mat_queryDescriptors_Mat_trainDescriptors_VectorOfVectorOfDMatch_matches_int_k_Mat_mask_bool_compactResult": "knn_train_matches",
"cv_DescriptorMatcher_knnMatch_Mat_queryDescriptors_VectorOfVectorOfDMatch_matches_int_k_VectorOfMat_masks_bool_compactResult": "knn_matches",
"cv_DescriptorMatcher_match_Mat_queryDescriptors_VectorOfDMatch_matches_VectorOfMat_masks": "matches",
"cv_DescriptorMatcher_match_Mat_queryDescriptors_Mat_trainDescriptors_VectorOfDMatch_matches_Mat_mask": "train_matches",
"cv_DescriptorMatcher_radiusMatch_Mat_queryDescriptors_Mat_trainDescriptors_VectorOfVectorOfDMatch_matches_float_maxDistance_Mat_mask_bool_compactResult": "train_radius_matches",
"cv_DescriptorMatcher_radiusMatch_Mat_queryDescriptors_VectorOfVectorOfDMatch_matches_float_maxDistance_VectorOfMat_masks_bool_compactResult": "radius_matches",
"cv_FAST_Mat_image_VectorOfKeyPoint_keypoints_int_threshold_bool_nonmaxSuppression": "FAST",
"cv_FAST_Mat_image_VectorOfKeyPoint_keypoints_int_threshold_bool_nonmaxSuppression_int_type": "FAST_with_type",
"cv_Feature2D_detect_VectorOfMat_images_VectorOfVectorOfKeyPoint_keypoints_VectorOfMat_masks": "detect_n",
"cv_KeyPoint_KeyPoint": "default",
"cv_KeyPoint_KeyPoint_Point2f__pt_float__size_float__angle_float__response_int__octave_int__class_id": "new_point",
"cv_KeyPoint_KeyPoint_float_x_float_y_float__size_float__angle_float__response_int__octave_int__class_id": "new_coords",
"cv_KeyPoint_convert_VectorOfKeyPoint_keypoints_VectorOfPoint2f_points2f_VectorOfint_keypointIndexes": "convert_from",
"cv_KeyPoint_convert_VectorOfPoint2f_points2f_VectorOfKeyPoint_keypoints_float_size_float_response_int_octave_int_class_id": "convert_to",
"cv_MatStep_MatStep": "default",
"cv_MatStep_MatStep_size_t_s": "new",
"cv_drawMatches_Mat_img1_VectorOfKeyPoint_keypoints1_Mat_img2_VectorOfKeyPoint_keypoints2_VectorOfDMatch_matches1to2_Mat_outImg_Scalar_matchColor_Scalar_singlePointColor_VectorOfchar_matchesMask_int_flags": "draw_matches",
"cv_drawMatches_Mat_img1_VectorOfKeyPoint_keypoints1_Mat_img2_VectorOfKeyPoint_keypoints2_VectorOfVectorOfDMatch_matches1to2_Mat_outImg_Scalar_matchColor_Scalar_singlePointColor_VectorOfVectorOfchar_matchesMask_int_flags": "draw_vector_matches",
"cv_setImpl_int_flags": "-",
"cv_setUseCollection_bool_flag": "-",
"cv_useCollection": "-",
"cv_imdecode_Mat_buf_int_flags": "decode",
"cv_imdecode_Mat_buf_int_flags_Mat_dst": "decode_to",
"cv_Canny_Mat_dx_Mat_dy_Mat_edges_double_threshold1_double_threshold2_bool_L2gradient": "canny_derivative",
"cv_Moments_Moments": "default",
"cv_Moments_Moments_double_m00_double_m10_double_m01_double_m20_double_m11_double_m02_double_m30_double_m21_double_m12_double_m03": "new",
"cv_Subdiv2D_Subdiv2D": "default",
"cv_Subdiv2D_Subdiv2D_Rect_rect": "new",
"cv_Subdiv2D_insert_Point2f_pt": "insert",
"cv_Subdiv2D_insert_VectorOfPoint2f_ptvec": "insert_n",
"cv_findContours_Mat_image_VectorOfMat_contours_Mat_hierarchy_int_mode_int_method_Point_offset": "find_contours_with_hierarchy",
"cv_distanceTransform_Mat_src_Mat_dst_Mat_labels_int_distanceType_int_maskSize_int_labelType": "distance_transform_labels",
"cv_distanceTransform_Mat_src_Mat_dst_int_distanceType_int_maskSize": "distance_transform",
"cv_integral_Mat_src_Mat_sum_Mat_sqsum_Mat_tilted_int_sdepth_int_sqdepth": "integral_titled_sq",
"cv_integral_Mat_src_Mat_sum_Mat_sqsum_Mat_tilted_int_sdepth": "integral_tilted",
"cv_integral_Mat_src_Mat_sum_Mat_sqsum_int_sdepth_int_sqdepth": "integral_sq_depth",
"cv_integral_Mat_src_Mat_sum_Mat_sqsum_int_sdepth": "integral_sq",
"cv_integral_Mat_src_Mat_sum_int_sdepth": "integral",
"cv_ml_ParamGrid_ParamGrid_double__minVal_double__maxVal_double__logStep": "for_range",
"cv_CascadeClassifier_CascadeClassifier": "default",
"cv_CascadeClassifier_detectMultiScale_Mat_image_VectorOfRect_objects_VectorOfint_rejectLevels_VectorOfdouble_levelWeights_double_scaleFactor_int_minNeighbors_int_flags_Size_minSize_Size_maxSize_bool_outputRejectLevels": "detect_multi_scale_levels",
"cv_CascadeClassifier_detectMultiScale_Mat_image_VectorOfRect_objects_VectorOfint_numDetections_double_scaleFactor_int_minNeighbors_int_flags_Size_minSize_Size_maxSize": "detect_multi_scale_num",
"cv_CascadeClassifier_detectMultiScale_Mat_image_VectorOfRect_objects_double_scaleFactor_int_minNeighbors_int_flags_Size_minSize_Size_maxSize": "detect_multi_scale",
"cv_HOGDescriptor_HOGDescriptor_HOGDescriptor_d": "copy",
"cv_HOGDescriptor_detectMultiScale_Mat_img_VectorOfRect_foundLocations_VectorOfdouble_foundWeights_double_hitThreshold_Size_winStride_Size_padding_double_scale_double_finalThreshold_bool_useMeanshiftGrouping": "detect_multi_scale",
"cv_HOGDescriptor_detectMultiScale_Mat_img_VectorOfRect_foundLocations_double_hitThreshold_Size_winStride_Size_padding_double_scale_double_finalThreshold_bool_useMeanshiftGrouping": "detect_multi_scale_weights",
"cv_HOGDescriptor_detect_Mat_img_VectorOfPoint_foundLocations_VectorOfdouble_weights_double_hitThreshold_Size_winStride_Size_padding_VectorOfPoint_searchLocations": "detect_weights",
"cv_HOGDescriptor_detect_Mat_img_VectorOfPoint_foundLocations_double_hitThreshold_Size_winStride_Size_padding_VectorOfPoint_searchLocations": "detect",
"cv_groupRectangles_VectorOfRect_rectList_VectorOfint_rejectLevels_VectorOfdouble_levelWeights_int_groupThreshold_double_eps": "group_rectangles_weights_rejects",
"cv_groupRectangles_VectorOfRect_rectList_VectorOfint_weights_int_groupThreshold_double_eps": "group_rectangle_weights",
"cv_groupRectangles_VectorOfRect_rectList_int_groupThreshold_double_eps": "group_rectangle",
"cv_groupRectangles_VectorOfRect_rectList_int_groupThreshold_double_eps_VectorOfint_weights_VectorOfdouble_levelWeights": "group_rectangle_levelweights",
"cv_fastNlMeansDenoisingColored_Mat_src_Mat_dst_float_h_float_hColor_int_templateWindowSize_int_searchWindowSize": "fast_nl_means_denoising_color",
"cv_fastNlMeansDenoising_Mat_src_Mat_dst_VectorOffloat_h_int_templateWindowSize_int_searchWindowSize_int_normType": "fast_nl_means_denoising_vec",
"cv_fastNlMeansDenoising_Mat_src_Mat_dst_float_h_int_templateWindowSize_int_searchWindowSize": "fast_nl_means_denoising_window",
"cv_AlignMTB_process_VectorOfMat_src_VectorOfMat_dst_Mat_times_Mat_response": "process_with_response",
"cv_MergeDebevec_process_VectorOfMat_src_Mat_dst_Mat_times_Mat_response": "process_with_response",
"cv_MergeMertens_process_VectorOfMat_src_Mat_dst_Mat_times_Mat_response": "process_with_response",
"cv_MergeRobertson_process_VectorOfMat_src_Mat_dst_Mat_times_Mat_response": "process_with_response",
"cv_KalmanFilter_KalmanFilter": "default",
"cv_KalmanFilter_KalmanFilter_int_dynamParams_int_measureParams_int_controlParams_int_type": "new",
"cv_VideoCapture_VideoCapture": "default",
"cv_VideoCapture_VideoCapture_int_index": "index",
"cv_VideoCapture_VideoCapture_String_filename": "filename",
"cv_VideoCapture_VideoCapture_String_filename_int_apiPreference": "filename_api",
"cv_VideoCapture_open_int_index": "open_index",
"cv_VideoCapture_open_String_filename": "open_filename",
"cv_VideoCapture_open_String_filename_int_apiPreference": "open_filename_api",
"cv_VideoWriter_VideoWriter": "default",
"cv_line_descriptor_BinaryDescriptorMatcher_match_Mat_queryDescriptors_Mat_trainDescriptors_VectorOfDMatch_matches_Mat_mask": "train_matches",
"cv_line_descriptor_BinaryDescriptorMatcher_match_Mat_queryDescriptors_VectorOfDMatch_matches_VectorOfMat_masks": "matches",
"cv_getImpl_VectorOfint_impl_VectorOfString_funName": "-",
"cv_dnn_<unnamed>_is_neg_int_i": "-",
"cv_dnn_NMSBoxes_VectorOfRotatedRect_bboxes_VectorOffloat_scores_float_score_threshold_float_nms_threshold_VectorOfint_indices_float_eta_int_top_k": "nms_boxes_rotated",
"cv_dnn_NMSBoxes_VectorOfRect2d_bboxes_VectorOffloat_scores_float_score_threshold_float_nms_threshold_VectorOfint_indices_float_eta_int_top_k": "nms_boxes_rotated_f64",
}
class_ignore_list = (
"CvMat", "CvArr", "CvSeq", "CvPoint.*", "CvRect", "CvTermCriteria", "CvSize", "CvSlice", "CvScalar",
"Cv[A-Z].*",
"cv::Param",
"cv::Mat::MStep",
"cv::Mat::MSize",
"cv::Mutex",
"Ipl.*",
"BinaryFunc", "ConvertData", "ConvertScaleData",
"cv::FileNode", "cv::FileStorage", "cv::FileNodeIterator",
"cv::KDTree", "IndexParams", "Params", "CvAttrList",
"cv::Exception", "cv::ErrorCallback",
"cv::RNG.*", "cv::SVD",
"cv::hal",
"cv::TLSDataContainer",
"NAryMatIterator",
"cv::MatConstIterator",
"cv::CommandLineParser",
"cv::_InputArray", "cv::_OutputArray", "cv::_InputOutputArray",
"cv::MatAllocator",
"cv::SparseMat",
"cv::AlgorithmInfo",
"Vertex", "QuadEdge",
"GeneralizedHough",
"Subdiv2D", "DescriptorCollection", "cv::CylindricalWarperGpu", "cv::PlaneWarperGpu", "cv::SphericalWarperGpu",
"cv::videostab::DensePyrLkOptFlowEstimatorGpu",
"cv::videostab::KeypointBasedMotionEstimatorGpu",
"cv::videostab::MoreAccurateMotionWobbleSuppressorGpu",
"cv::videostab::SparsePyrLkOptFlowEstimatorGpu",
"cv::ml::SimulatedAnnealingSolverSystem", "cv::dnn::_Range",
)
aliases_types = {
"unsigned": "uint",
"InputArray": "cv::Mat",
"InputArrayOfArrays": "vector<cv::Mat>",
"OutputArray": "cv::Mat",
"OutputArrayOfArrays": "vector<cv::Mat>",
"InputOutputArrayOfArrays": "vector<cv::Mat>",
"InputOutputArray": "cv::Mat",
"_InputArray": "cv::Mat",
"_OutputArray": "cv::Mat",
"_InputOutputArray": "cv::Mat",
"_Range": "cv::Range",
}
func_ignore_list = (
"cv.glob", "cv.fastFree", "cv.fastMalloc",
"cv.getBuildInformation", "cv.scalarToRawData", "cv::noArray", "()", "cv.Mat.MSize.operator[]",
"const int*", "=", "==", "!=", "--", "++", "*", ">>", "<<", "<", ">", "operator==", "operator()",
"cv.Mat.MStep.operator[]",
"cv.abs", "cvCeil", "cvFloor", "cvIsInf", "cvIsNaN", "cvRound",
"cv.swap",
"cv.minMaxLoc", "cv.minMaxIdx", "cv.merge", "cv.split",
"cv.mixChannels", "cv.insertChannel",
"cv.hconcat", "cv.vconcat", "cv.repeat", "cv.min", "cv.max", "cv.exp", "cv.log", "cv.fastAtan2", "cv.magnitude", "cv.patchNaNs", "cv.setIdentity", "cv.completeSymm", "cv.calcCovarMatrix",
"cv.fillConvexPoly", "cv.fillPoly", "cv.polylines", "cv.getTextSize", "cv.SparseMat.Hdr.clear",
"cv.PCA.computeVar", "cvSetPreprocessFuncWin32_", "cvSetPostprocessFuncWin32_",
"cv.BOWImgDescriptorExtractor.getVocabulary",
)
func_ignore_filters = (
lambda func_info: func_info.fullname.endswith("cv::Mat::ptr") and func_info.const,
)
const_ignore_list = (
"^CV_EXPORTS_W", "CV_MAKE_TYPE",
"CV_IS_CONT_MAT", "CV_RNG_COEFF", "IPL_IMAGE_MAGIC_VAL",
"CV_SET_ELEM_FREE_FLAG", "CV_FOURCC_DEFAULT",
"CV_WHOLE_ARR", "CV_WHOLE_SEQ", "CV_PI", "CV_2PI", "CV_LOG2",
"CV_TYPE_NAME_IMAGE",
"CV_SUPPRESS_DEPRECATED_START",
"CV_SUPPRESS_DEPRECATED_END",
"__CV_BEGIN__", "__CV_END__", "__CV_EXIT__",
"CV_IMPL_IPP", "CV_IMPL_MT", "CV_IMPL_OCL", "CV_IMPL_PLAIN",
"CV_TRY", "CV_CATCH_ALL",
"^CV__DEBUG_NS_",
"UINT64_1",
"CV_STRUCT_INITIALIZER", "CV__ENABLE_C_API_CTORS",
"^VSX_IMPL_MULH_",
"^CV__DNN_EXPERIMENTAL_NS_",
"^CV_Sts",
)
primitives = {
u"void": {u"ctype": "void", "rust_local": "()"},
u"bool": {u"ctype": "char", u"rust_local": "bool"},
u"char": {u"ctype": "char", u"rust_local": "i8"},
u"schar": {u"ctype": "char", u"rust_local": "i8"},
u"uchar": {u"ctype": "unsigned char", u"rust_local": "u8"},
u"unsigned char": {u"ctype": "unsigned char", u"rust_local": "u8"},
u"uchar*": {u"ctype": "unsigned char*", u"rust_local": "*mut u8"},
u"short": {u"ctype": "short", u"rust_local": "i16"},
u"ushort": {u"ctype": "unsigned short", u"rust_local": "u16"},
u"int": {u"ctype": "int", u"rust_local": "i32"},
u"uint": {u"ctype": "unsigned int", u"rust_local": "u32"},
u"unsigned int": {u"ctype": "unsigned int", u"rust_local": "u32"},
u"uint32_t": {u"ctype": "uint32_t", u"rust_local": "u32"},
u"size_t": {u"ctype": "std::size_t", u"rust_local": "size_t"},
u"int64": {u"ctype": "int64", u"rust_local": "i64"},
u"uint64": {u"ctype": "uint64", u"rust_local": "u64"},
u"unsigned long long": {u"ctype": "unsigned long long", u"rust_local": "u64"},
u"int64_t": {u"ctype": "int64_t", u"rust_local": "i64"},
u"uint64_t": {u"ctype": "uint64_t", u"rust_local": "u64"},
u"float": {u"ctype": "float", u"rust_local": "f32"},
u"double": {u"ctype": "double", u"rust_local": "f64"},
}
forced_trait_classes = ("cv::Algorithm", "cv::BackgroundSubtractor", "cv::dnn::Layer")
value_struct_types = {
"Point2i": (("x", "int"), ("y", "int")),
"Point2l": (("x", "int64"), ("y", "int64")),
"Point2f": (("x", "float"), ("y", "float")),
"Point2d": (("x", "double"), ("y", "double")),
"Point": (("x", "int"), ("y", "int")),
"Size2i": (("width", "int"), ("height", "int")),
"Size2l": (("width", "int64"), ("height", "int64")),
"Size2f": (("width", "float"), ("height", "float")),
"Size2d": (("width", "double"), ("height", "double")),
"Size": (("width", "int"), ("height", "int")),
"Rect2i": (("x", "int"), ("y", "int"), ("width", "int"), ("height", "int")),
"Rect2f": (("x", "float"), ("y", "float"), ("width", "float"), ("height", "float")),
"Rect2d": (("x", "double"), ("y", "double"), ("width", "double"), ("height", "double")),
"Rect": (("x", "int"), ("y", "int"), ("width", "int"), ("height", "int")),
"Scalar": (("*", "double[4]"),),
"CvRNG": (("data", "int64"),)
}
for s in (2, 3, 4, 6):
for t in (("uchar", "b"), ("short", "s"), ("int", "i"), ("double", "d"), ("float", "f")):
value_struct_types["Vec%d%s" % (s,t[1])] = ("data", "%s[%d]" % (t[0],s)),
boxed_type_fields = {
"RotatedRect": {
"center": "Point2f",
"size": "Size2f",
"angle": "float",
}
}
reserved_rename = {
"type": "_type",
"box": "_box",
"ref": "_ref",
"in": "_in",
"use": "_use",
}
static_modules = ("core", "sys", "types")
T_CPP_MODULE = template("""
//
// This file is auto-generated, please don't edit!
//
#include "stdint.h"
#include "common.h"
typedef int64_t int64;
#include <iostream>
#include "opencv2/opencv_modules.hpp"
#include <string>
#include "common_opencv.h"
using namespace cv;
#include "types.h"
$includes
extern "C" {
#include "return_types.h"
$code
} // extern "C"
""")
const_private_list = (
"CV_MOP_.+",
"CV_INTER_.+",
"CV_THRESH_.+",
"CV_INPAINT_.+",
"CV_RETR_.+",
"CV_CHAIN_APPROX_.+",
"OPPONENTEXTRACTOR",
"GRIDDETECTOR",
"PYRAMIDDETECTOR",
"DYNAMICDETECTOR",
)
def camel_case_to_snake_case(name):
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
def bump_counter(name):
pos = len(name) - 1
for pos in xrange(len(name) - 1, 0, -1):
if not name[pos].isdigit():
break
base_name = name[:pos + 1]
try:
counter = int(name[pos + 1:])
except ValueError:
base_name += "_"
counter = 0
return "{}{}".format(base_name, counter + 1)
def split_known_namespace(name, namespaces):
if "::" in name:
for namespace in sorted(namespaces, key=len, reverse=True):
namespace_colon = namespace + "::"
if name.startswith(namespace_colon):
return namespace, name[len(namespace_colon):]
return "", name
else:
return "", name
class GeneralInfo():
def __init__(self, gen, name, namespaces):
self.gen = gen
self.fullname, self.namespace, self.classpath, self.classname, self.name = self.do_parse_name(name, namespaces)
logging.info(
"parse_name: %s with %s -> fullname:%s namespace:%s classpath:%s classname:%s name:%s" %
(name, namespaces, self.fullname, self.namespace, self.classpath, self.classname, self.name)
)
def do_parse_name(self, name, namespaces):
name = name.replace("const ", "").replace("struct ", "").replace("class ", "").replace(".", "::")
space_name, local_name = split_known_namespace(name, namespaces)
pieces = local_name.split("::")
if len(pieces) > 2: return name, space_name, "::".join(pieces[:-1]), pieces[-2], pieces[-1]
elif len(pieces) == 2: return name, space_name, pieces[0], pieces[0], pieces[1]
elif len(pieces) == 1: return name, space_name, "", "", pieces[0]
else:
return name, space_name, "", ""
class ArgInfo():
def __init__(self, gen, arg_tuple):
self.gen = gen
self.pointer = False
type = arg_tuple[0]
if type.endswith("*"):
type = type[:-1]
self.pointer = True
self.type = self.gen.get_type_info(type)
self.name = arg_tuple[1]
if not self.name:
self.name = "unnamed_arg"
self.rsname = camel_case_to_snake_case(reserved_rename.get(self.name, self.name))
self.defval = ""
self.typeinfo = None
if len(arg_tuple) > 2:
self.defval = arg_tuple[2]
self.out = ""
if arg_tuple[0] in ("OutputArray", "OutputArrayOfArrays") or len(arg_tuple) > 3 and "/O" in arg_tuple[3]:
self.out = "O"
if arg_tuple[0] in ("InputOutputArray", "InputOutputArrayOfArrays") or len(arg_tuple) > 3 and "/IO" in arg_tuple[3]:
self.out = "IO"
def __repr__(self):
return template("ARG $ctype$p $name=$defval").substitute(ctype=self.type,
p=" *" if self.pointer else "",
name=self.name,
defval="" )
class FuncInfo(GeneralInfo):
KIND_FUNCTION = "(function)"
KIND_METHOD = "(method)"
KIND_CONSTRUCTOR = "(constructor)"
def __init__(self, gen, decl, namespaces=frozenset()): GeneralInfo.__init__(self, gen, decl[0], namespaces)
self._r_name = None
if self.classname and not self.classname.startswith("operator"):
self.ci = gen.get_class(self.classname)
if not self.ci:
if self.classname == "std":
self.is_ignored = True
return
else:
raise NameError("class not found: " + self.classname)
if "/A" in decl[2]:
self.ci.is_trait = True
if self.classname == self.name:
self.kind = self.KIND_CONSTRUCTOR
self.name = "new"
self.type = gen.get_type_info(self.classname)
else:
self.kind = self.KIND_METHOD
self.type = gen.get_type_info(decl[1])
else:
self.kind = self.KIND_FUNCTION
self.ci = None
self.type = gen.get_type_info(decl[1])
self.identifier = self.fullname.replace("::", "_")
if len(decl) > 5:
self.comment = decl[5].encode("ascii", "ignore")
else:
self.comment = ""
self.args = []
for arg in decl[3]:
ai = ArgInfo(gen, arg)
while any(True for x in self.args if x.name == ai.name):
ai.name = bump_counter(ai.name)
ai.rsname = camel_case_to_snake_case(reserved_rename.get(ai.name, ai.name))
self.args.append(ai)
self.identifier += "_" + ai.type.rust_safe_id + "_" + ai.name
self.const = "/C" in decl[2]
self.static = ["", "static"]["/S" in decl[2]]
self.fake_attrgetter = "/ATTRGETTER" in decl[2]
self.struct_attrname = decl[6] if self.fake_attrgetter else None
self.cname = self.cppname = self.name
self.is_ignored = "/H" in decl[2] or "/I" in decl[2]
if self.name.startswith("~"):
logging.info("ignore destructor %s %s in %s"%(self.kind, self.name, self.ci))
self.is_ignored = True
if self.name.startswith("operator") or self.fullname.startswith("operator "):
logging.info("ignore %s %s in %s"%(self.kind, self.name, self.ci))
self.is_ignored = True
if self.is_ignored:
return
if self.kind == self.KIND_FUNCTION:
logging.info("register %s %s (%s)"%(self.kind, self.name, self.identifier))
gen.register_function(self)
else:
logging.info("register %s %s in %s (%s)"%(self.kind, self.name, self.ci, self.identifier))
self.ci.add_method(self)
def isconstructor(self):
return self.kind == self.KIND_CONSTRUCTOR
def rv_type(self):
if self.isconstructor():
if self.ci:
return self.gen.get_type_info(self.ci.fullname)
else:
return None
else:
return self.type
def reason_to_skip(self):
if self.identifier in self.gen.generated:
return "already there"
if self.name.startswith("operator"):
return "can not map %s yet"%(self.name)
for f in func_ignore_list:
if self.fullname.endswith(f):
return "manual ignore from list"
if any(filter_func(self) for filter_func in func_ignore_filters):
return "manual ignore from filter"
if renamed_funcs.get(self.identifier) == "-":
return "ignored by renamed table"
if not self.rv_type():
return "rv_header_type returns None. this is an error. (class not found ?)"
if self.type.is_ignored:
return "return type class %s is ignored"%(self.type)
if self.rv_type().is_ignored:
return "return value type is ignored"
if self.kind == self.KIND_CONSTRUCTOR and self.ci.is_trait:
return "skip constructor of abstract class"
for a in self.args:
if a.type.is_ignored:
return "can not map type %s yet"%(a.type)
if a.pointer and a.type.is_by_value:
return "returning primitive by pointer is not supported (FIXME ?)"
if a.pointer and a.type.typeid.endswith("*"):
return "** not supported yet"
if a.type.typeid.endswith("]"):
return "passing raw arrays will wait (FIXME ?)"
if a.type.typeid == "const char" and a.pointer:
return "const char* will wait"
if a.type.typeid == "...":
return "variadic will have to wait"
return None
def gen_cpp_prelude(self):
io = StringIO()
io.write("// %s\n"%(self.identifier))
io.write("// parsed: %s\n"%(self.fullname))
io.write("// as: %s\n"%(self))
for a in self.args:
ignored = ptr = ""
if a.type.is_ignored:
ignored = "(ignored)"
if a.pointer:
ptr = "(ptr)"
io.write("// Arg %s %s %s =%s %s\n"%(a, ptr, a.type, a.defval, ignored))
io.write("// Return value: %s\n"%(self.rv_type()))
return io.getvalue()
def c_name(self):
return "cv_%s_%s" % (self.gen.module, self.identifier.replace("::", "").replace(" ", "_"))
def r_name(self):
if self._r_name is not None:
return self._r_name
if renamed_funcs.get(self.identifier):
return renamed_funcs[self.identifier]
name = "new" if self.isconstructor() else self.name
return camel_case_to_snake_case(name)
def set_r_name(self, value):
self._r_name = value
def mutability(self):
if self.ci is not None and not self.isconstructor():
return "const" if self.const else "mut"
return ""
def gen_rust_extern(self):
rust_extern_rs = "cv_return_value_%s" % (self.rv_type().c_safe_id)
args = []
if not self.static and self.mutability():
if self.ci.type_info().is_by_value:
args.append("instance: %s" % (self.ci.type_info().rust_full))
else:
args.append("instance: *%s c_void" % (self.mutability()))
for a in self.args:
args.append(a.rsname + ": " + a.type.rust_extern)
return "#[doc(hidden)] pub fn %s(%s) -> %s;\n" % (self.c_name(), ", ".join(args), rust_extern_rs)
def gen_safe_rust(self):
args = []
call_args = []
cstring_args = []
if not self.static and self.mutability() == "const":
if self.ci.type_info().is_by_value:
args.append("self")
call_args.append("self")
else:
args.append("&self")
call_args.append("self.as_raw_%s()"%(self.ci.type_info().rust_local))
elif not self.static and self.mutability() == "mut":
if self.ci.type_info().is_by_value:
args.append("self")
call_args.append("self")
else:
args.append("&mut self")
call_args.append("self.as_raw_%s()"%(self.ci.type_info().rust_local))
for a in self.args:
if isinstance(a.type,StringTypeInfo):
args.append("%s:&str"%(a.rsname))
elif a.type.is_by_value:
args.append(a.rsname + ": " + a.type.rust_full)
elif a.out == "O" or a.out == "IO":
args.append(a.rsname + ": &mut " + a.type.rust_full)
else:
args.append(a.rsname + ": &" + a.type.rust_full)
if isinstance(a.type, BoxedClassTypeInfo) or a.type.is_by_ptr:
call_args.append("%s.as_raw_%s()"%(a.rsname, a.type.rust_local))
elif isinstance(a.type,StringTypeInfo):
cstring_args.append(" let %s = CString::new(%s).unwrap();\n" % (a.rsname, a.rsname))
call_args.append("%s.as_ptr() as _" % (a.rsname))
else:
call_args.append("%s"%(a.rsname))
pub = "" if self.ci and self.ci.type_info().is_trait and not self.static else "pub "
io = StringIO()
io.write(self.gen.reformat_doc(self.comment))
first = True
for a in self.args:
if a.defval != "":
if first:
io.write("///\n/// ## C++ default parameters:\n")
io.write("/// * %s: %s\n"%(a.rsname, a.defval))
first = False
io.write("%sfn %s(%s) -> Result<%s> {\n"%(pub, self.r_name(), ", ".join(args), self.rv_type().rust_full))
io.write("// identifier: %s\n"%(self.identifier))
io.write(" unsafe {\n")
io.writelines(cstring_args)
io.write(" let rv = sys::%s(%s);\n"%(self.c_name(), ", ".join(call_args)))
io.write(" if !rv.error_msg.is_null() {\n")
io.write(" let v = CStr::from_ptr(rv.error_msg as _).to_bytes().to_vec();\n")
io.write(" ::libc::free(rv.error_msg as _);\n")
io.write(" Err(Error { code: rv.error_code, message: String::from_utf8(v).unwrap() })\n")
io.write(" } else {\n")
if self.type.typeid == "void":
io.write(" Ok(())\n")
elif isinstance(self.rv_type(), StringTypeInfo):
io.write(" let v = CStr::from_ptr(rv.result as _).to_bytes().to_vec();\n")
io.write(" ::libc::free(rv.result as _);\n")
io.write(" Ok(String::from_utf8(v).unwrap())\n")
elif isinstance(self.rv_type(), SmartPtrTypeInfo):
io.write(" Ok(%s { ptr: rv.result })\n" % (self.rv_type().rust_full))
elif isinstance(self.rv_type(), VectorTypeInfo):
io.write(" Ok(%s { ptr: rv.result })\n" % (self.rv_type().rust_full))
elif isinstance(self.rv_type(), BoxedClassTypeInfo):
io.write(" Ok(%s { ptr: rv.result })\n" % (self.rv_type().rust_full))
else:
io.write(" Ok(rv.result)\n")
io.write(" }\n")
io.write(" }\n")
io.write("}\n\n")
block = io.getvalue()
if self.kind == self.KIND_FUNCTION:
return block
else:
return re.sub("^(.+)$", " \\1", block, flags=re.M)
def __repr__(self):
if self.kind == self.KIND_FUNCTION:
return "%s %s"%(self.fullname, self.kind)
else:
return "%s %s %s . %s"%(self.fullname, self.kind, self.ci, self.name)
class ClassPropInfo:
def __init__(self, decl): self.ctype = decl[0]
self.name = decl[1]
self.rw = "/RW" in decl[3]
def __repr__(self):
return template("PROP $ctype $name").substitute(ctype=self.ctype, name=self.name)
class ClassInfo(GeneralInfo):
def __init__(self, gen, decl, namespaces): GeneralInfo.__init__(self, gen, decl[0], namespaces)
self.methods = []
self.namespaces = namespaces
self.module = self.gen.module
self.is_simple = self.is_ignored = self.is_ghost = False
self.is_trait = self.fullname in forced_trait_classes
self.classname = self.name
self.comment = ""
if len(decl) > 5:
self.comment = decl[5].encode("ascii", "ignore")
for m in decl[2]:
if m == "/Simple" or m == "/Map":
self.is_simple = True
if m == "/Hidden":
self.is_ignored = True
if m == "/Ghost":
self.is_ghost = True
if self.classpath and gen.get_class(self.classpath).is_ignored:
self.is_ignored = True
self.nested_cname = self.fullname.replace("::", "_")
bases = decl[1][1:].strip()
if len(bases):
self.bases = [x for x in set(x.strip() for x in bases.split(",")) if x != self.fullname]
else:
self.bases = []
for base in self.bases:
typ = self.gen.get_class(base)
if typ:
self.gen.get_class(base).is_trait = True
self.props = []
for p in decl[3]:
self.props.append(ClassPropInfo(p))
self.is_ignored = self.is_ignored or self.gen.class_is_ignored(self.fullname)
logging.info("register class %s (%s)%s%s", self.fullname, decl,
" [ignored]" if self.is_ignored else "",
" impl:"+",".join(self.bases) if len(self.bases) else "")
gen.classes[self.fullname] = self
self.add_unpack_methods()
def __repr__(self):
attrs = []
if self.is_simple:
attrs.append("simple")
if self.is_ignored:
attrs.append("ignored")
if self.is_ghost:
attrs.append("ghost")
if self.is_trait:
attrs.append("trait")
if len(attrs) == 0:
return self.fullname
else:
return "{} ({})".format(self.fullname, ", ".join(attrs))
def add_unpack_methods(self):
for struct_field, field_type in boxed_type_fields.get(self.classname, {}).items():
field_decl = [
u'{classname}.get_{struct_field}'.format(
classname=self.classname,
struct_field=struct_field,
),
field_type,
['/ATTRGETTER'],
[],
None,
u'returns the {struct_field} attr of {field_type} type\n'.format(
struct_field=struct_field,
field_type=field_type,
),
struct_field,
]
self.add_method(FuncInfo(self.gen, field_decl, frozenset(self.namespaces)))
def add_method(self, fi):
self.methods.append(fi)
def type_info(self):
return self.gen.get_type_info(self.fullname)
class ConstInfo(GeneralInfo):
def __init__(self, gen, decl, namespaces, added_manually=False):
GeneralInfo.__init__(self, gen, decl[0], namespaces)
_, self.rustname = split_known_namespace(self.fullname, namespaces)
self.rustname = self.rustname.replace("::", "_")
self.cname = self.name.replace(".", "::")
self.value = decl[1]
self.added_manually = added_manually
self.templates = {
"rust_string": template("${doccomment}pub const ${name}: &'static str = ${value};\n"),
"rust_int": template("${doccomment}pub const ${name}: i32 = ${value};\n"),
"cpp_string": template(""" printf("pub static ${name}: &'static str = \\"%s\\";\\n", ${full_name});\n"""),
"cpp_double": template(""" printf("pub const ${name}: f64 = %f;\\n", ${full_name});\n"""),
"cpp_int": template(""" printf("pub const ${name}: i32 = 0x%x; // %i\\n", ${full_name}, ${full_name});\n"""),
}
if self.is_ignored():
logging.info('ignored: %s', self)
elif not gen.get_const(self.name):
gen.consts.append(self)
def __repr__(self):
return template("CONST $name=$value$manual").substitute(name=self.name,
value=self.value,
manual="(manual)" if self.added_manually else "")
def is_ignored(self):
for c in const_ignore_list:
if re.match(c, self.name):
return True
return False
def gen_rust(self):
name = self.rustname
value = self.value
while True:
doccomment = ""
m = re.match(r"^(.+?)\s*(?://\s*(.+)|/\*+\s*(.+?)\s*\*+/)$", value) if m:
value = m.group(1)
doccomment = "/// {}\n".format(m.group(3) if m.group(2) is None else m.group(2))
if value.startswith('"'):
return self.templates["rust_string"].substitute(doccomment=doccomment, name=name, value=value)
elif re.match(r"^(-?[0-9]+|0x[0-9A-Fa-f]+)$", value): return self.templates["rust_int"].substitute(doccomment=doccomment, name=name, value=value)
elif re.match(r"^\(?\s*(\d+\s*<<\s*\d+)\s*\)?$", value): return self.templates["rust_int"].substitute(doccomment=doccomment, name=name, value=value)
elif re.match(r"^\s*(\d+\s*\+\s*\d+)\s*$", value): return self.templates["rust_int"].substitute(doccomment=doccomment, name=name, value=value)
ref_const = self.gen.get_const(value)
if ref_const is not None:
value = ref_const.value
continue
return None
def gen_cpp_for_complex(self):
if len(self.fullname.split(".")) > 2:
return ""
elif self.fullname == "CV_VERSION":
return self.templates["cpp_string"].substitute(name=self.rustname, full_name=self.fullname)
elif self.fullname in ("MLN10", "RELATIVE_ERROR_FACTOR"):
return self.templates["cpp_double"].substitute(name=self.rustname, full_name=self.fullname)
else:
return self.templates["cpp_int"].substitute(name=self.rustname, full_name=self.fullname)
class TypeInfo:
def __init__(self, gen, typeid):
self.is_const = typeid.startswith("const ") self.typeid = typeid.replace("const ", "") self.gen = gen
self.is_ignored = False self.is_by_ptr = False self.is_by_value = False self.is_trait = False
self.ctype = ""
self.cpptype = self.typeid
self.c_safe_id = "XX"
_, self.rust_local = split_known_namespace(self.typeid, gen.namespaces)
self.rust_local = self.rust_local.replace("::", "_") self.rust_safe_id = self.rust_local self.rust_full = "" self.rust_extern = ""
self.inner = None
def gen_wrappers(self):
pass
class StringTypeInfo(TypeInfo):
def __init__(self, gen, typeid):
TypeInfo.__init__(self, gen, typeid)
self.ctype = "const char*"
self.cpptype = "String"
self.c_safe_id = "char_X"
self.rust_full = "String"
self.rust_local = "*const c_char"
self.rust_extern = "*const c_char"
self.rust_safe_id = "String"
def __str__(self):
return "string"
class IgnoredTypeInfo(TypeInfo):
def __init__(self, gen, typeid):
TypeInfo.__init__(self, gen, typeid)
self.is_ignored = True
def __str__(self):
return "Ignored(%s)"%(self.typeid)
class PrimitiveTypeInfo(TypeInfo):
def __init__(self, gen, typeid):
TypeInfo.__init__(self, gen, typeid)
self.is_by_value = True
primitive = primitives[self.typeid]
self.ctype = primitive["ctype"]
self.rust_extern = self.rust_full = self.rust_local = primitive["rust_local"]
self.rust_safe_id = self.typeid.replace(" ", "_")
self.c_safe_id = self.ctype.replace(" ", "_").replace("*", "X").replace("::", "_")
def __str__(self):
return "Primitive(%s)" % (self.cpptype)
class SimpleClassTypeInfo(TypeInfo):
def __init__(self, gen, typeid):
TypeInfo.__init__(self, gen, typeid)
self.is_by_value = True
self.ci = gen.get_class(self.typeid)
if self.ci and self.ci.is_ignored:
self.is_ignored = True
if self.ci:
self.rust_full = ("super::" if self.ci.module not in static_modules else "") + self.ci.module + "::" + self.rust_local
self.ctype = "c_" + self.rust_local
self.c_safe_id = self.ctype
self.rust_extern = self.rust_full
self.is_trait = False
def __str__(self):
return "%s (simple)"%(self.cpptype)
class ValueStructTypeInfo(TypeInfo):
def __init__(self, gen, typeid):
TypeInfo.__init__(self, gen, typeid)
self.is_by_value = True
self.ci = gen.get_class(self.typeid)
if self.ci and self.ci.is_ignored:
self.is_ignored = True
self.rust_full = "core::" + self.rust_local
self.ctype = "c_" + self.rust_local
self.c_safe_id = self.ctype
self.rust_extern = self.rust_full
self.is_trait = False
def __str__(self):
return "%s (struct)"%(self.cpptype)
class BoxedClassTypeInfo(TypeInfo):
def __init__(self, gen, typeid, alias):
TypeInfo.__init__(self, gen, typeid)
self.ci = gen.get_class(self.typeid)
self.cpptype = self.ci.fullname
self.rust_extern = "*mut c_void"
self.rust_full = ("super::" if self.ci.module not in static_modules else "") + self.ci.module + "::" + self.rust_local
self.is_by_ptr = True
self.is_trait = self.typeid in forced_trait_classes or self.ci.is_trait
self.ctype = "void*"
self.c_safe_id = "void_X"
self.is_ignored = self.ci.is_ignored
if alias:
self.rust_safe_id = alias
else:
self.rust_safe_id = self.ci.name
def __str__(self):
return "%s (boxed)"%(self.typeid)
class VectorTypeInfo(TypeInfo):
def __init__(self, gen, typeid, inner):
TypeInfo.__init__(self, gen, typeid)
self.is_by_ptr = True
self.inner = inner
self.is_ignored = inner.is_ignored
if not self.is_ignored:
self.ctype = "void*"
self.c_safe_id = "void_X"
self.inner_cpptype = inner.cpptype
if isinstance(self.inner, SmartPtrTypeInfo):
self.outer_cpptype = "std::vector<%s>" % (self.inner.outer_cpptype)
self.inner_outer_cpptype = self.inner.outer_cpptype
self.cpptype = "std::vector<%s>" % (inner.cpptype)
self.rust_safe_id = self.rust_local = "VectorOf"+inner.rust_safe_id
self.rust_full = "types::" + self.rust_local
self.rust_extern = "*mut c_void"
self.inner_rust_full = inner.rust_full
self.templates = {
"rust_common": template("""
extern "C" {
#[doc(hidden)] fn cv_new_${rust_safe_id}() -> ${rust_extern};
#[doc(hidden)] fn cv_delete_${rust_safe_id}(ptr: ${rust_extern});
#[doc(hidden)] fn cv_push_${rust_safe_id}(ptr: ${rust_extern}, ptr2: *const c_void);
#[doc(hidden)] fn cv_${rust_safe_id}_len(ptr: ${rust_extern}) -> i32;
#[doc(hidden)] fn cv_${rust_safe_id}_get(ptr: ${rust_extern}, index: i32) -> ${rust_extern};
}
#[allow(dead_code)]
pub struct ${rust_local} {
pub(crate) ptr: ${rust_extern}
}
impl ${rust_local} {
pub fn new() -> Self {
unsafe { Self { ptr: cv_new_${rust_safe_id}() } }
}
pub fn len(&self) -> i32 {
unsafe { cv_${rust_safe_id}_len(self.ptr) }
}
#[doc(hidden)]
pub unsafe fn as_raw_$rust_local(&self) -> ${rust_extern} {
self.ptr
}
}
impl Drop for $rust_local {
fn drop(&mut self) {
unsafe { cv_delete_${rust_safe_id}(self.ptr) };
}
}
"""),
"rust_boxed": template("""
// BoxedClassTypeInfo
impl ${rust_local} {
pub fn push(&mut self, val: ${inner_rust_full}) {
unsafe { cv_push_${rust_safe_id}(self.ptr, val.ptr) }
}
pub fn get(&self, index: i32) -> ${inner_rust_full} {
${inner_rust_full} { ptr: unsafe { cv_${rust_safe_id}_get(self.ptr, index) } }
}
pub fn to_vec(&self) -> Vec<$inner_rust_full> {
(0..self.len()).map(|x| self.get(x)).collect()
}
}
"""),
"rust_non_boxed": template("""
impl ${rust_local} {
pub fn push(&mut self, val: ${inner_rust_full}) {
unsafe { cv_push_${rust_safe_id}(self.ptr, &val as *const _ as _) }
}
pub fn get(&self, index: i32) -> &mut $inner_rust_full {
unsafe { (cv_${rust_safe_id}_get(self.ptr, index) as *mut ${inner_rust_full}).as_mut().unwrap() }
}
}
"""),
"rust_non_bool": template("""
extern "C" { #[doc(hidden)] fn cv_${rust_safe_id}_data(ptr: ${rust_extern}) -> ${rust_extern}; }
impl ::std::ops::Deref for ${rust_local} {
type Target = [${inner_rust_full}];
fn deref(&self) -> &Self::Target {
unsafe {
let length = cv_${rust_safe_id}_len(self.ptr) as usize;
let data = cv_${rust_safe_id}_data(self.ptr);
::std::slice::from_raw_parts(::std::mem::transmute(data), length)
}
}
}
"""),
"cpp_externs": template("""
void* cv_new_${rust_safe_id}() {
return new ${cpptype}();
}
void cv_delete_${rust_safe_id}(void* ptr) {
delete reinterpret_cast<${cpptype}*>(ptr);
}
void cv_push_${rust_safe_id}(void* ptr, void* ptr2) {
${inner_cpptype}* val = reinterpret_cast<${inner_cpptype}*>(ptr2);
reinterpret_cast<${cpptype}*>(ptr)->push_back(*val);
}
${inner_cpptype}* cv_${rust_safe_id}_front_item(void* ptr) {
${inner_cpptype} val = reinterpret_cast<${cpptype}*>(ptr)->front();
return new ${inner_cpptype}(val);
}
${inner_cpptype}* cv_${rust_safe_id}_back_item(void* ptr) {
${inner_cpptype} val = reinterpret_cast<${cpptype}*>(ptr)->back();
return new ${inner_cpptype}(val);
}
int cv_${rust_safe_id}_len(void* ptr) {
return reinterpret_cast<${cpptype}*>(ptr)->size();
}
"""),
"cpp_externs_bool": template("""
${inner_cpptype}* cv_${rust_safe_id}_get(void* ptr, int index) {
${inner_cpptype} val = (*reinterpret_cast<${cpptype}*>(ptr))[index];
return new ${inner_cpptype}(val);
}
"""),
"cpp_externs_non_bool": template("""
${inner_cpptype}* cv_${rust_safe_id}_get(void* ptr, int index) {
${inner_cpptype} val = reinterpret_cast<${cpptype}*>(ptr)->data()[index];
return new ${inner_cpptype}(val);
}
${ctype}* cv_${rust_safe_id}_data(void* ptr) {
return reinterpret_cast<${ctype}*>(reinterpret_cast<${cpptype}*>(ptr)->data());
}
"""),
}
def gen_wrappers(self):
with open("{}/{}.type.rs".format(self.gen.rust_dir, self.rust_safe_id), "w") as f:
f.write(self.templates["rust_common"].substitute(self.__dict__))
if isinstance(self.inner, BoxedClassTypeInfo) or self.inner.is_by_ptr:
f.write(self.templates["rust_boxed"].substitute(self.__dict__))
else:
f.write(self.templates["rust_non_boxed"].substitute(self.__dict__))
if self.inner.typeid != "bool":
f.write(self.templates["rust_non_bool"].substitute(self.__dict__))
if isinstance(self.inner, SmartPtrTypeInfo):
template_vars = self.__dict__.copy()
template_vars["cpptype"] = self.outer_cpptype
template_vars["inner_cpptype"] = self.inner_outer_cpptype
else:
template_vars = self.__dict__
externs = self.templates["cpp_externs"].substitute(template_vars)
if self.inner.typeid == "bool":
externs += self.templates["cpp_externs_bool"].substitute(template_vars)
else:
externs += self.templates["cpp_externs_non_bool"].substitute(template_vars)
with open("{}/{}.type.cpp".format(self.gen.cpp_dir, self.rust_safe_id), "w") as f:
f.write(T_CPP_MODULE.substitute(code=externs, includes=""))
def __str__(self):
return "Vector[%s]" % (self.inner)
class SmartPtrTypeInfo(TypeInfo):
def __init__(self, gen, typeid, inner):
TypeInfo.__init__(self, gen, typeid)
self.is_by_ptr = True
self.inner = inner
self.is_ignored = self.inner.is_ignored
if not self.is_ignored:
self.ctype = "void*"
self.c_safe_id = "void_X"
self.rust_extern = "*mut c_void"
self.cpptype = self.inner.cpptype
self.outer_cpptype = "Ptr<{}>".format(self.inner.cpptype)
self.rust_local = self.rust_safe_id = "PtrOf{}".format(inner.rust_safe_id)
self.rust_full = "types::{}".format(self.rust_local)
self.inner_rust_full = inner.rust_full
self.inner_local = inner.rust_local
self.templates = {
"rust": template("""
extern "C" {
#[doc(hidden)] fn cv_${rust_safe_id}_get(ptr: ${rust_extern}) -> ${rust_extern};
#[doc(hidden)] fn cv_delete_${rust_safe_id}(ptr: ${rust_extern});
}
#[allow(dead_code)]
pub struct ${rust_local} {
pub(crate) ptr: ${rust_extern}
}
impl ${rust_local} {
#[doc(hidden)] pub fn as_raw_${rust_safe_id}(&self) -> ${rust_extern} {
self.ptr
}
}
impl Drop for ${rust_local} {
fn drop(&mut self) {
unsafe { cv_delete_${rust_safe_id}(self.ptr) };
}
}
"""),
"rust_trait_cast": template("""
impl ${base_full} for ${rust_local} {
#[doc(hidden)]
fn as_raw_${base_local}(&self) -> ${rust_extern} {
unsafe { cv_${rust_safe_id}_get(self.ptr) }
}
}
"""),
"cpp_externs": template("""
void* cv_${rust_safe_id}_get(${ctype} ptr) {
return reinterpret_cast<${outer_cpptype}*>(ptr)->get();
}
void cv_delete_${rust_safe_id}(${ctype} ptr) {
delete reinterpret_cast<${outer_cpptype}*>(ptr);
}
"""),
}
def gen_wrappers(self):
with open("{}/{}.type.rs".format(self.gen.rust_dir, self.rust_safe_id), "w") as f:
f.write(self.templates["rust"].substitute(self.__dict__))
if not isinstance(self.inner, PrimitiveTypeInfo) and self.inner.ci.is_trait:
bases = self.gen.all_bases(self.inner.ci.name).union({self.inner.typeid})
for base in bases:
cibase = self.gen.get_type_info(base)
if not isinstance(cibase, UnknownTypeInfo):
f.write(self.templates["rust_trait_cast"].substitute(
rust_local=self.rust_local,
rust_safe_id=self.rust_safe_id,
rust_extern=self.rust_extern,
base_local=cibase.rust_local,
base_full=cibase.rust_full
))
with open("{}/{}.type.cpp".format(self.gen.cpp_dir, self.rust_safe_id), "w") as f:
code = self.templates["cpp_externs"].substitute(self.__dict__)
f.write(T_CPP_MODULE.substitute(code=code, includes=""))
def __str__(self):
return "SmartPtr[%s]" % (self.inner)
class RawPtrTypeInfo(TypeInfo):
def __init__(self, gen, typeid, inner):
TypeInfo.__init__(self, gen, typeid)
self.inner = inner
self.is_ignored = True
self.rust_safe_id = inner.rust_safe_id
def __str__(self):
return "RawPtr[%s]" % (self.inner)
class UnknownTypeInfo(TypeInfo):
def __init__(self, gen, typeid):
TypeInfo.__init__(self, gen, typeid)
self.is_ignored = True
logging.info("Registering an unknown type: %s", self.typeid)
def __str__(self):
return "Unknown[%s]" % (self.typeid)
def parse_type(gen, typeid):
full_typeid = typeid.strip().replace("..", ".")
if full_typeid.startswith("const "):
typeid = full_typeid[6:]
if typeid == "":
typeid = "void"
full_typeid = "void"
if typeid.endswith("&"):
typeid = typeid[:-1].strip()
full_typeid = full_typeid[:-1].strip()
if typeid in primitives:
return PrimitiveTypeInfo(gen, full_typeid)
elif typeid.endswith("*"):
return RawPtrTypeInfo(gen, full_typeid, gen.get_type_info(typeid[:-1].strip()))
elif typeid.endswith("[]"):
return RawPtrTypeInfo(gen, full_typeid, gen.get_type_info(typeid[:-2].strip()))
elif typeid == "string" or typeid == "String":
return StringTypeInfo(gen, full_typeid)
elif typeid == "":
raise NameError("empty type detected")
elif typeid.startswith("Ptr<"):
return SmartPtrTypeInfo(gen, full_typeid, gen.get_type_info(typeid[4:-1].strip()))
elif typeid.startswith("vector<"):
inner = gen.get_type_info(typeid[7:-1].strip())
if not inner:
raise NameError("inner type `%s' not found" % (typeid[7:-1].strip()))
return VectorTypeInfo(gen, full_typeid, inner)
elif typeid.startswith("std::vector<"):
inner = gen.get_type_info(typeid[12:-1].strip())
if not inner:
raise NameError("inner type `%s' not found" % (typeid[12:-1].strip()))
return VectorTypeInfo(gen, full_typeid, inner)
elif gen.get_value_struct(typeid):
return ValueStructTypeInfo(gen, gen.get_value_struct(typeid))
else:
ci = gen.get_class(typeid)
if ci and not ci.is_ignored:
if ci.is_simple:
return SimpleClassTypeInfo(gen, ci.fullname)
else:
return BoxedClassTypeInfo(gen, ci.fullname, None)
actual = aliases_types.get(typeid)
if actual:
ci = gen.get_class(actual)
if ci:
if ci.is_simple:
return SimpleClassTypeInfo(gen, ci.fullname)
else:
return BoxedClassTypeInfo(gen, ci.fullname, None)
return parse_type(gen, actual)
return UnknownTypeInfo(gen, full_typeid)
class RustWrapperGenerator(object):
def __init__(self):
self.cpp_dir = ""
self.rust_dir = ""
self.module = ""
self.classes = {}
self.functions = []
self.ported_func_list = []
self.skipped_func_list = []
self.consts = []
self.type_infos = {}
self.namespaces = set()
self.generated = set()
self.generated_functions = []
self.func_names = set()
def get_class(self, classname):
c = self.classes.get(classname)
if c:
return c
for c in self.classes.values():
if c.fullname.endswith("::"+classname):
return c
return None
def get_value_struct(self, classname):
c = value_struct_types.get(classname)
if c:
return classname
for c in value_struct_types.keys():
if c.endswith("::" + classname):
return c
return None
def get_type_info(self, typeid):
typeid = typeid.strip()
if typeid not in self.type_infos:
self.type_infos[typeid] = parse_type(self, typeid)
return self.type_infos[typeid]
def get_const(self, name):
for c in self.consts:
if c.cname == name:
return c
return None
def add_decl(self, decl):
if decl[0] == "cv.String.String" or decl[0] == 'cv.Exception.~Exception':
return
if decl[0] == "cv.Algorithm":
decl[0] = "cv.Algorithm.Algorithm"
name = decl[0]
if name.startswith("struct") or name.startswith("class"):
ClassInfo(self, decl, frozenset(self.namespaces))
elif name.startswith("const"):
ConstInfo(self, decl, frozenset(self.namespaces))
else:
FuncInfo(self, decl, frozenset(self.namespaces))
def register_function(self, f):
self.functions.append(f)
def gen(self, srcfiles, module, cpp_dir, rust_dir):
self.cpp_dir = cpp_dir
self.rust_dir = rust_dir
self.module = module
includes = []
parser = hdr_parser.CppHeaderParser()
self.namespaces = set(x for x in parser.namespaces)
self.namespaces.add("cv")
for m in cross_modules_deps:
self.module = m
for d in cross_modules_deps[m]:
self.add_decl(d)
self.module = module
for hdr in srcfiles:
decls = parser.parse(hdr, False)
self.namespaces = set(str(x.replace(".", "::")) for x in parser.namespaces)
logging.info("\n\n=============== Header: %s ================\n\n", hdr)
logging.info("Namespaces: %s", parser.namespaces)
logging.info("Comment: %s", parser.comment)
includes.append('#include "' + hdr + '"')
for decl in decls:
logging.info("\n--- Incoming ---\n%s", pformat(decl, 4))
self.add_decl(decl)
if module in ManualFuncs:
for decl in ManualFuncs[self.module]:
logging.info("\n--- Manual ---\n%s", pformat(decl, 4))
self.add_decl(decl)
logging.info("\n\n===== Generating... =====")
self.moduleCppTypes = StringIO()
self.moduleCppCode = StringIO()
self.moduleCppConsts = StringIO()
self.moduleSafeRust = StringIO()
self.moduleRustExterns = StringIO()
self.moduleSafeRust.write('//! <script type="text/javascript" src="http://latex.codecogs.com/latexit.js"></script>\n'.encode("utf-8"))
self.moduleSafeRust.write(self.reformat_doc(parser.comment).encode("utf-8").replace("///", "//!"))
self.moduleSafeRust.write(template("""
use libc::{c_void, c_char, size_t};
use std::ffi::{CStr, CString};
use crate::{Error, Result, """ + ", ".join(static_modules) + """};
""").substitute())
for co in sorted(self.consts, key=lambda c: c.rustname):
rust = co.gen_rust()
if rust:
self.moduleSafeRust.write(rust)
else:
self.moduleCppConsts.write(co.gen_cpp_for_complex())
self.moduleSafeRust.write("\n")
if module == "core":
for c in sorted(value_struct_types, key=lambda c: c[0]):
self.gen_value_struct(c)
for t in self.type_infos.values():
if not t.is_ignored:
t.gen_wrappers()
for c in self.classes.values():
if c.is_simple and not c.is_ignored and not c.is_ghost:
self.gen_simple_class(c)
for fi in sorted(self.functions, key=lambda fi: fi.identifier):
if not fi.is_ignored:
self.gen_func(fi)
for ci in sorted(self.classes.values(), key=lambda ci:ci.fullname):
if not ci.is_ignored and not ci.is_ghost:
self.gen_class(ci)
with open(cpp_dir + "/types.h", "a") as f:
f.write(self.moduleCppTypes.getvalue())
with open(cpp_dir + "/" + self.module + ".consts.cpp", "w") as f:
f.write("""#include <cstdio>\n""")
f.write("""#include "opencv2/opencv_modules.hpp"\n""")
f.write("""#include "opencv2/%s.hpp"\n"""%(module))
for include in includes:
f.write(include+"\n")
f.write("""using namespace cv;\n""")
f.write("int main(int, char**) {\n")
f.write(self.moduleCppConsts.getvalue())
f.write("}\n")
namespaces = ""
for namespace in self.namespaces:
if namespace != "":
namespaces += "using namespace %s;\n"%(namespace.replace(".", "::"))
with open(cpp_dir + "/" + module + ".cpp", "w") as f:
f.write(T_CPP_MODULE.substitute(m = module, M = module.upper(), code = self.moduleCppCode.getvalue(), includes = "\n".join(includes), namespaces=namespaces))
with open(rust_dir + "/%s.externs.rs" % (module), "w") as f:
f.write("extern \"C\" {\n")
f.write(self.moduleRustExterns.getvalue())
f.write("}\n")
with open(rust_dir + "/" + module + ".rs", "w") as f:
f.write(self.moduleSafeRust.getvalue())
with open(cpp_dir + "/" + module + ".txt", "w") as f:
f.write(self.makeReport())
def makeReport(self):
report = StringIO()
total_count = len(self.ported_func_list)+len(self.skipped_func_list)
report.write("FOUND FUNCs: %i\n\n" % (total_count))
report.write("PORTED FUNCs: %i\n\n" % (len(self.ported_func_list)))
for f in self.ported_func_list:
report.write("PORTED: " + f + "\n")
if len(self.skipped_func_list) > 0:
report.write("\n\nSKIPPED FUNCs: %i\n\n" % (len(self.skipped_func_list)))
for f in self.skipped_func_list:
report.write("SKIPPED: " + f + "\n")
return report.getvalue()
def class_is_ignored(self, type_name):
for c in class_ignore_list:
if re.match(c, type_name):
return True
return False
def gen_vector_struct_for(self, name):
struct_name = "cv_vector_of_"+name
self.defined_in_types_h.appand(struct_name)
self.moduleCppTypes.write
def gen_func(self, fi):
if fi.kind == fi.KIND_FUNCTION or fi.fake_attrgetter:
for item in self.generated_functions:
if item.name == fi.name and str(item.args) == str(fi.args):
return
else:
self.generated_functions.append(fi)
logging.info("Generating func %s"%(fi.identifier))
reason = fi.reason_to_skip()
if reason:
logging.info(" ignored: " + reason)
self.skipped_func_list.append("%s\n %s\n"%(fi,reason))
return
self.ported_func_list.append(fi.__repr__())
self.generated.add(fi.identifier)
self.moduleCppCode.write(fi.gen_cpp_prelude())
decl_c_args = "\n "
call_cpp_args = ""
if fi.ci is not None and not fi.isconstructor() and not fi.static:
decl_c_args += fi.ci.type_info().ctype + " instance"
for a in fi.args:
if not decl_c_args.strip() == "":
decl_c_args+=",\n "
if not call_cpp_args == "":
call_cpp_args += ", "
rw = a.out == "O" or a.out == "IO"
arg_decl_star = not isinstance(a.type, BoxedClassTypeInfo) and rw
if arg_decl_star:
decl_c_args += a.type.ctype + " *" + a.name
else:
decl_c_args += a.type.ctype + " " + a.name
if isinstance(a.type, SmartPtrTypeInfo):
call_cpp_args += "reinterpret_cast<" + a.type.cpptype + " *>(" + a.name + ")"
elif a.type.is_by_ptr:
if a.pointer:
call_cpp_args += "((%s*)%s)"%(a.type.cpptype.replace("&",""), a.name)
elif isinstance(a.type, VectorTypeInfo) and isinstance(a.type.inner, SmartPtrTypeInfo):
call_cpp_args += "*((%s*)%s)"%(a.type.outer_cpptype.replace("&",""), a.name)
else:
call_cpp_args += "*((%s*)%s)"%(a.type.cpptype.replace("&",""), a.name)
elif isinstance(a.type, StringTypeInfo):
call_cpp_args += "%s(%s)" % (a.type.cpptype, a.name)
elif a.type.is_by_value:
if arg_decl_star and a.pointer:
call_cpp_args += "reinterpret_cast<" + a.type.cpptype + "*>(" + a.name + ")"
elif arg_decl_star and not a.pointer:
call_cpp_args += "*reinterpret_cast<" + a.type.cpptype + "*>(" + a.name + ")"
elif a.pointer:
call_cpp_args += "reinterpret_cast<" + a.type.cpptype + "*>(&" + a.name + ")"
else:
call_cpp_args += "*reinterpret_cast<" + a.type.cpptype + "*>(&" + a.name + ")"
else:
if arg_decl_star and a.pointer:
call_cpp_args += a.name
elif not arg_decl_star and not a.pointer:
call_cpp_args += a.name
else:
call_cpp_args += "*" + a.name
self.moduleCppCode.write("cv_return_value_%s %s(%s) {\n" % (fi.rv_type().c_safe_id, fi.c_name(), decl_c_args))
self.moduleCppCode.write(" try {\n")
if fi.ci is None and (fi.cppname.startswith("cv") or fi.cppname.startswith("CV")):
call_name = fi.cppname
elif fi.ci is None or fi.static:
call_name = fi.fullname.replace(".", "::")
elif fi.isconstructor() and isinstance(fi.ci.type_info(), BoxedClassTypeInfo):
call_name = fi.ci.fullname
elif fi.cppname == "()":
call_name = "(*((%s*) instance))" % (fi.ci.fullname)
elif fi.fake_attrgetter:
if isinstance(fi.type, PrimitiveTypeInfo):
call_name = "(({typename}*) instance)->{attrname}".format(
typename=fi.classname,
attrname=fi.struct_attrname,
)
else:
call_name = "({typeid}) (({typename}*) instance)->{attrname}".format(
typeid=fi.type.typeid,
typename=fi.classname,
attrname=fi.struct_attrname,
)
elif isinstance(self.get_type_info(fi.ci.name), BoxedClassTypeInfo):
call_name = "((%s*) instance)->%s" % (fi.ci.fullname, fi.cppname)
else:
call_name = "((%s*) &instance)->%s" % (fi.ci.fullname, fi.cppname)
if fi.type.ctype == "void":
self.moduleCppCode.write(" %s(%s);\n"%(call_name, call_cpp_args))
elif fi.isconstructor() and (isinstance(fi.rv_type(), BoxedClassTypeInfo)):
self.moduleCppCode.write(" %s* cpp_return_value = new %s(%s);\n" % (fi.rv_type().cpptype, call_name, call_cpp_args))
elif isinstance(fi.rv_type(), SmartPtrTypeInfo):
if fi.fake_attrgetter:
self.moduleCppCode.write(" Ptr<%s> *cpp_return_value = new Ptr<%s>;\n" % (fi.rv_type().cpptype, call_name))
else:
self.moduleCppCode.write(
" Ptr<%s> *cpp_return_value = new Ptr<%s>(%s(%s));\n" % (fi.rv_type().cpptype, fi.rv_type().cpptype, call_name, call_cpp_args))
elif fi.isconstructor() and call_cpp_args != "":
self.moduleCppCode.write(" %s cpp_return_value(%s);\n" % (fi.rv_type().cpptype, call_cpp_args))
elif fi.isconstructor():
self.moduleCppCode.write(" %s cpp_return_value;\n" % (fi.rv_type().cpptype))
else:
if fi.fake_attrgetter:
self.moduleCppCode.write(" %s cpp_return_value = %s;\n" % (fi.rv_type().cpptype, call_name))
else:
self.moduleCppCode.write(" %s cpp_return_value = %s(%s);\n" % (fi.rv_type().cpptype, call_name, call_cpp_args))
self.gen_c_return_value_type(fi.rv_type())
if fi.type.ctype == "void":
self.moduleCppCode.write(" return { Error::Code::StsOk, NULL };\n")
elif isinstance(fi.rv_type(), StringTypeInfo):
self.moduleCppCode.write(" return { Error::Code::StsOk, NULL, strdup(cpp_return_value.c_str()) };\n")
elif isinstance(fi.rv_type(), BoxedClassTypeInfo) and not fi.isconstructor():
self.moduleCppCode.write(" return { Error::Code::StsOk, NULL, new %s(cpp_return_value) };\n" % (fi.rv_type().cpptype))
elif isinstance(fi.rv_type(), BoxedClassTypeInfo) and fi.isconstructor():
self.moduleCppCode.write(" return { Error::Code::StsOk, NULL, cpp_return_value };\n")
elif isinstance(fi.rv_type(), SmartPtrTypeInfo):
self.moduleCppCode.write(" return { Error::Code::StsOk, NULL, cpp_return_value };\n")
elif fi.rv_type().is_by_value:
self.moduleCppCode.write(" return { Error::Code::StsOk, NULL, *reinterpret_cast<%s*>(&cpp_return_value) };\n"%(fi.rv_type().ctype))
elif isinstance(fi.rv_type(), VectorTypeInfo):
self.moduleCppCode.write(" return { Error::Code::StsOk, NULL, (void *)new %s(cpp_return_value) };\n" % (fi.rv_type().cpptype))
else: self.moduleCppCode.write(" return { Error::Code::StsOk, NULL, cpp_return_value };\n")
self.moduleCppCode.write(" } catch (cv::Exception& e) {\n")
self.moduleCppCode.write(" char* msg = strdup(e.what());\n")
if fi.type.ctype == "void":
self.moduleCppCode.write(" return { e.code, msg };\n")
else:
self.moduleCppCode.write(" cv_return_value_%s ret;\n" % (fi.rv_type().c_safe_id))
self.moduleCppCode.write(" memset(&ret, 0x00, sizeof(ret));\n")
self.moduleCppCode.write(" ret.error_code = e.code;\n")
self.moduleCppCode.write(" ret.error_msg = msg;\n")
self.moduleCppCode.write(" return ret;\n")
self.moduleCppCode.write(" } catch (...) {\n")
self.moduleCppCode.write(" char* msg = strdup(\"unspecified error in OpenCV guts\");\n")
if fi.type.ctype == "void":
self.moduleCppCode.write(" return { -99999, msg };\n")
else:
self.moduleCppCode.write(" cv_return_value_%s ret;\n" % (fi.rv_type().c_safe_id))
self.moduleCppCode.write(" memset(&ret, 0x00, sizeof(ret));\n")
self.moduleCppCode.write(" ret.error_code = -99999;\n")
self.moduleCppCode.write(" ret.error_msg = msg;\n")
self.moduleCppCode.write(" return ret;\n")
self.moduleCppCode.write(" }\n")
self.moduleCppCode.write("}\n\n")
self.moduleRustExterns.write(fi.gen_rust_extern())
rust_func_name = fi.r_name()
classname = "" if fi.kind == fi.KIND_FUNCTION else fi.classname
while classname + '::' + rust_func_name in self.func_names:
rust_func_name = bump_counter(rust_func_name)
fi.set_r_name(rust_func_name)
self.moduleSafeRust.write(fi.gen_safe_rust())
self.func_names.add(classname + '::' + fi.r_name())
def gen_value_struct_field(self, name, typ, is_simple_struct=False):
if name == "*":
name = "data"
rsname = reserved_rename.get(name, name)
visibility = "" if rsname == "__rust_private" else "pub "
if "[" in typ:
bracket = typ.index("[")
cppt = typ[:bracket]
ct = self.get_type_info(cppt).ctype
size = typ[bracket+1:-1]
rst = self.get_type_info(cppt).rust_full
self.moduleCppTypes.write(" %s %s[%s];\n"%(ct, name, size))
if is_simple_struct:
self.moduleSafeRust.write("%s[%s; %s], " % (visibility, rst, size))
else:
self.moduleSafeRust.write(" %s%s: [%s; %s],\n" % (visibility, rsname, rst, size))
else:
typ = self.get_type_info(typ)
self.moduleCppTypes.write(" %s %s;\n"%(typ.ctype, name))
if is_simple_struct:
self.moduleSafeRust.write("%s %s, " % (visibility, typ.rust_full))
else:
self.moduleSafeRust.write(" %s%s: %s,\n"%(visibility, rsname, typ.rust_full))
def gen_value_struct(self, c):
self.moduleCppTypes.write("typedef struct c_%s {\n"%(c.replace("::","_")))
self.moduleSafeRust.write("// manually defined value struct %s\n" % (c.split("::")[-1]))
self.moduleSafeRust.write("#[repr(C)]\n#[derive(Copy,Clone,Debug,PartialEq)]\npub struct %s" % (c.split("::")[-1]))
is_simple_struct = len(value_struct_types[c]) == 1 and value_struct_types[c][0][0] == "*"
if is_simple_struct:
self.moduleSafeRust.write(" (")
else:
self.moduleSafeRust.write(" {\n")
for field in value_struct_types[c]:
self.gen_value_struct_field(field[0], field[1], is_simple_struct)
self.moduleCppTypes.write("} c_%s;\n\n" % (c.replace("::", "_")))
if is_simple_struct:
self.moduleSafeRust.write(");\n\n")
else:
self.moduleSafeRust.write("}\n\n")
def gen_simple_class(self,ci):
self.moduleSafeRust.write(self.reformat_doc(ci.comment))
self.moduleSafeRust.write("#[repr(C)]\n#[derive(Copy,Clone,Debug,PartialEq)]\npub struct %s {\n" % (ci.type_info().rust_local))
self.moduleCppTypes.write("typedef struct %s {\n" % (ci.type_info().c_safe_id))
if len(ci.props) > 0:
for p in ci.props:
self.gen_value_struct_field(p.name, p.ctype)
else:
self.gen_value_struct_field("__rust_private", "unsigned char[0]")
self.moduleSafeRust.write("}\n\n")
self.moduleCppTypes.write("} %s;\n\n" % (ci.type_info().c_safe_id))
def gen_c_return_value_type(self, typ):
with open(self.cpp_dir + "/cv_return_value_" + typ.c_safe_id + ".type.h", "w") as f:
if typ.ctype == "void":
f.write(template("""
// $typeid
struct cv_return_value_${c_safe_id} {
int error_code;
char* error_msg;
};
""").substitute(typ.__dict__))
else:
f.write(template("""
// $typeid
struct cv_return_value_${c_safe_id} {
int error_code;
char* error_msg;
$ctype result;
};
""").substitute(typ.__dict__))
with open(self.rust_dir + "/cv_return_value_" + typ.c_safe_id + ".rv.rs", "w") as f:
if typ.ctype == "void":
f.write(template("""
// $typeid
#[repr(C)]
pub struct cv_return_value_void {
pub error_code: i32,
pub error_msg: *const c_char,
}
""").substitute(typ.__dict__))
else:
f.write(template("""
// $typeid
#[repr(C)]
pub struct cv_return_value_${c_safe_id} {
pub error_code: i32,
pub error_msg: *const c_char,
pub result: $rust_extern
}
""").substitute(typ.__dict__))
def gen_boxed_class(self, name):
ci = self.get_class(name)
if not ci:
logging.info("type %s not found", name)
return
typ = ci.type_info()
logging.info("Generating box for %s", ci)
self.moduleCppCode.write(template("""
// boxed class: $typeid
void cv_delete_$rust_local(void* instance) {
delete ($cpptype*) instance;
}
""").substitute(typ.__dict__))
self.moduleRustExterns.write("pub fn cv_delete_%s(ptr : *mut c_void);\n" % (typ.rust_safe_id))
self.moduleSafeRust.write("// boxed class %s\n"%(typ.typeid))
self.moduleSafeRust.write(self.reformat_doc(ci.comment))
self.moduleSafeRust.write(template("""
#[allow(dead_code)]
pub struct $rust_local {
#[doc(hidden)] pub ptr: *mut c_void
}
impl Drop for $rust_full {
fn drop(&mut self) {
unsafe { sys::cv_delete_${rust_safe_id}(self.ptr) };
}
}
impl $rust_full {
#[doc(hidden)] pub fn as_raw_$rust_local(&self) -> *mut c_void { self.ptr }
}
""").substitute(typ.__dict__))
bases = self.all_bases(name)
for base in bases:
cibase = self.get_class(base)
if cibase is not None:
cibase = cibase.type_info()
self.moduleSafeRust.write(template("""
impl $base_full for ${rust_local} {
#[doc(hidden)] fn as_raw_$base_local(&self) -> *mut c_void { self.ptr }
}
""").substitute(rust_local=typ.rust_local, base_local=cibase.rust_local, base_full=cibase.rust_full))
def all_bases(self, name):
bases = set()
ci = self.get_class(name)
if ci is not None:
for b in ci.bases:
bases.add(b)
bases = bases.union(self.all_bases(b))
return bases
def gen_class(self, ci):
if ci.is_ignored:
logging.info("Manual ignore class %s", ci)
return
t = ci.type_info()
if not t:
logging.info("Ignore class %s (not found)", ci)
return
if ci.namespace == "":
logging.info("Not namespaced. Skipped %s", ci)
return
if t.is_trait:
if len(ci.bases):
bases = (x.rust_full for x in (self.get_type_info(x) for x in ci.bases) if not isinstance(x, UnknownTypeInfo))
bases = " : " + " + ".join(bases)
else:
bases = ""
logging.info("Generating impl for trait %s", ci)
self.moduleSafeRust.write("// Generating impl for trait %s\n" % (ci))
self.moduleSafeRust.write(self.reformat_doc(ci.comment.strip()))
self.moduleSafeRust.write("pub trait %s%s {\n" % (t.rust_local, bases))
self.moduleSafeRust.write(" #[doc(hidden)] fn as_raw_%s(&self) -> *mut c_void;\n" % (t.rust_local))
for fi in ci.methods:
if not fi.static:
self.gen_func(fi)
self.moduleSafeRust.write("}\n")
self.moduleSafeRust.write("impl<'a> %s + 'a {\n\n" % (t.rust_local))
for fi in ci.methods:
if fi.static:
self.gen_func(fi)
self.moduleSafeRust.write("}\n\n")
else:
if isinstance(t, BoxedClassTypeInfo):
self.gen_boxed_class(ci.fullname)
logging.info("Generating impl for struct %s", ci)
self.moduleSafeRust.write("impl %s {\n\n" % (t.rust_local))
for fi in ci.methods:
self.gen_func(fi)
self.moduleSafeRust.write("}\n")
def reformat_doc(self, text):
text = text.strip()
if len(text) == 0:
return ""
text = re.sub(r"^\s*\*$", "", text, 0, re.M)
text = re.sub(r"^\* ", "", text, 0, re.M)
text = text.replace("@brief", "").replace("@note", "\nNote:")
text = text.replace("@code", "```ignore").replace("@endcode", "```\n")
text = re.sub("^(.*?@param)", "## Parameters\n\\1", text, 1, re.M)
text = re.sub(r".*\*\*\*\*\*", "", text, 0, re.M)
text = re.sub("@defgroup [^ ]+ (.*)", "\\1\n\n# \\1", text)
text = re.sub("^.*?@param ([^ ]+) (.*)", "* \\1: \\2", text, 0, re.M)
text = re.sub("^- (.*)", "* \\1", text, 0, re.M)
text = re.sub("\\\\f\[", "<div lang='latex'>", text, 0, re.M)
text = re.sub("\\\\f\]", "</div>", text, 0, re.M)
text = re.sub(r"\\f\$(.*?)\\f\$", "<span lang='latex'>\\1</span>", text, 0, re.M)
text = re.sub("^", "/// ", text.strip(), 0, re.M) + "\n"
return text
def main():
cpp_dir = sys.argv[2]
rust_dir = sys.argv[3]
module = sys.argv[4]
srcfiles = sys.argv[5:]
logging.basicConfig(filename='%s/%s.log' % (cpp_dir, module), format=None, filemode='w', level=logging.INFO)
handler = logging.StreamHandler()
handler.setLevel(logging.WARNING)
logging.getLogger().addHandler(handler)
print("Generating module '" + module + "' from headers:\n\t" + "\n\t".join(srcfiles))
generator = RustWrapperGenerator()
generator.gen(srcfiles, module, cpp_dir, rust_dir)
if __name__ == "__main__":
if len(sys.argv) < 5:
print("Usage:\n", \
os.path.basename(sys.argv[0]), \
"<full path to hdr_parser.py> <cpp_out_dir> <rust_out_dir> <module name> <C++ header> [<C++ header>...]")
print("Current args are: ", ", ".join(["'"+a+"'" for a in sys.argv]))
exit(0)
hdr_parser_path = os.path.abspath(sys.argv[1])
if hdr_parser_path.endswith(".py"):
hdr_parser_path = os.path.dirname(hdr_parser_path)
sys.path.append(hdr_parser_path)
import hdr_parser
main()