private static ManagedArg GetManagedArg(NativeArg nativeArg, int argCount, string funcName) { var name = nativeArg.Name.OrElse(null) ?? GuessOptionSetArgName(nativeArg, argCount, funcName) ?? GuessManagedArgNameForArg(nativeArg) ?? $"p{nativeArg.Index}"; if (nativeArg.IsDelegate) { var argsLength = FindClosingParenthesis(nativeArg.NativeType, 1) - 1; var funcArgsUnparsed = nativeArg.NativeType.Substring(1, argsLength); var nativeReturnType = nativeArg.NativeType.Substring(1 + argsLength + ") -> ".Length); var delegateNativeArgs = ParseNativeArgs(funcArgsUnparsed).ToList(); var delegateManagedArgs = delegateNativeArgs.Select(dna => GetManagedArg(dna, delegateNativeArgs.Count, $"{funcName}_{name}")); var delegateManagedArgsString = string.Join(", ", delegateManagedArgs.Select(dma => dma.Variations.First())); var delegateManagedReturnType = GetManagedType(nativeReturnType); var managedType = $"({delegateManagedArgsString}) -> {delegateManagedReturnType}"; return(new ManagedArg( new[] { new ManagedArgVariation("delegate_ptr", name, "default"), new ManagedArgVariation(managedType, name, "delegate"), } )); } else { var managedTypes = GetManagedTypeOverride(nativeArg, argCount, funcName) ?? GetManagedTypeVariations(nativeArg, name); return(new ManagedArg(managedTypes.Select(mt => new ManagedArgVariation(mt.Type, name, mt.Strategy)))); } }
private static string GuessOptionSetArgName(NativeArg nativeArg, int argCount, string funcName) { return // second arg in a set operation that has 2 args // or first arg in a set operation that has one arg which is not a pointer ((nativeArg.Index == 1 && argCount == 2 && funcName != null) || (nativeArg.Index == 0 && argCount == 1 && !nativeArg.NativeType.EndsWith("*")) ? RocksDbOptionSetPattern.Match(funcName).If(m => m.Success)?.Groups[1].Value : null); }
/* Sometimes we can't determine the appropriate type automatically and we just have to override it * These are the function/argname:type -> managed type mappings */ private static IEnumerable <(string Type, string Strategy)> OverrideType(NativeArg arg, int argCount, string funcName) { // The Strategy returned allows multiple overloads for a function. // In general, just pass "default" unless you need to ensure multiple overloads // "keys" and "values" in "options" functions are strings if (funcName.IsMatchedBy(@".*options.*") && arg.Name.IsMatchedBy("keys|values") && arg.NativeType.IsMatchedBy(@".*\*\*|.*\* const\*")) { yield return("string[]", "default"); } // Some options take enumerations as values if (funcName == "rocksdb_options_set_compression_per_level" && arg.Name == "level_values") { yield return("Compression[]", "enum"); yield return("int[]", "default"); } if (funcName == "rocksdb_options_set_compression" && arg.NativeType == "int") { yield return("Compression", "enum"); yield return("int", "default"); } if (funcName == "rocksdb_options_set_compaction_style" && arg.NativeType == "int") { yield return("Compaction", "enum"); yield return("int", "default"); } if (funcName == "rocksdb_options_set_wal_recovery_mode" && arg.NativeType == "int") { yield return("Recovery", "enum"); yield return("int", "default"); } if (funcName == "rocksdb_block_based_options_set_index_type" && arg.NativeType == "int") { yield return("BlockBasedTableIndexType", "enum"); yield return("int", "default"); } if (funcName == "rocksdb_set_perf_level" && arg.NativeType == "int") { yield return("PerfLevel", "enum"); yield return("int", "default"); } if (funcName == "rocksdb_perfcontext_metric" && arg.NativeType == "int") { yield return("PerfMetric", "enum"); yield return("int", "default"); } yield break; }
private static string GetManagedType(NativeArg nativeArg) { if (nativeArg.Name == "errptr" && nativeArg.NativeType == "char**") { return("out char_ptr_ptr"); } if (nativeArg.Name == "errs" && nativeArg.NativeType == "char**") { return("char_ptr[]"); } if (nativeArg.Name.IsMatchedBy(@"len.*|size|.*len") && nativeArg.NativeType == "size_t*") { return("out size_t"); } if (nativeArg.Name == "file_list" && nativeArg.NativeType == "const char* const*") { return("string[]"); } return(GetManagedType(nativeArg.NativeType)); }
private static string GuessManagedArgNameForArg(NativeArg nativeArg) { return(RocksDbStructPtrPattern.Match(nativeArg.NativeType).If(m => m.Success)?.Groups[1].Value ?? nativeArg.NativeType.If(t => t == "size_t").Then(t => "size")); }
private static IEnumerable <(string Type, string Strategy)> GetManagedTypeOverride(NativeArg nativeArg, int argCount, string funcName) { var overrides = OverrideType(nativeArg, argCount, funcName).ToList(); return((overrides.Count > 0) ? overrides : null); }
private static IEnumerable <(string Type, string Strategy)> GetManagedTypeVariations(NativeArg nativeArg, string managedArgName) { // Note: the managedArgName can be convenient since a native arg name is not always supplied yield return(Type : GetManagedType(nativeArg), Strategy : "default"); if (managedArgName.IsMatchedBy(".*name|name.*|.*dir|.*path") && nativeArg.NativeType == "const char*") { yield return(Type : "string", Strategy : "string name"); } if (nativeArg.Name.IsMatchedBy(".*names|names.*") && nativeArg.NativeType == "const char**") { yield return(Type : "string[]", Strategy : "array"); } if (nativeArg.Name.IsMatchedBy(".*column_famil.*|iterators") && nativeArg.NativeType.EndsWith("**")) { yield return(Type : $"{AsArrayType(GetManagedType(nativeArg.NativeType))}", Strategy : "array"); } if (nativeArg.Name.IsMatchedBy(@"key|k|val|v|.*_key|.*_val") && nativeArg.NativeType.In("const char*", "char*")) { yield return(Type : "byte*", Strategy : "kv byte*"); yield return(Type : "byte[]", Strategy : "kv byte[]"); } if (nativeArg.Name.IsMatchedBy(@"rep") && nativeArg.NativeType.In("const char*", "char*")) { yield return(Type : "byte*", Strategy : "rep byte*"); yield return(Type : "byte[]", Strategy : "rep byte[]"); } if (nativeArg.Name.IsMatchedBy(@"blob") && nativeArg.NativeType.In("const char*", "char*")) { yield return(Type : "byte*", Strategy : "blob byte*"); yield return(Type : "byte[]", Strategy : "blob byte[]"); } if (nativeArg.Name.ToLower().EndsWith("list") && nativeArg.NativeType.In("const char* const*", "char**")) { yield return(Type : "IntPtr[]", Strategy : "array"); } if (nativeArg.Name.ToLower().EndsWith("sizes") && nativeArg.NativeType.In("const size_t*", "size_t*")) { yield return(Type : "size_t[]", Strategy : "array"); } if (nativeArg.Name == "column_families" && nativeArg.NativeType == "const rocksdb_column_family_handle_t* const*") { yield return(Type : "rocksdb_column_family_handle_t_ptr[]", Strategy : "array"); } if (nativeArg.Name == "level_values" && nativeArg.NativeType == "int*") { yield return(Type : "int[]", Strategy : "array"); } }