tsrs 0.18.0-x86_64-darwin

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +177 -0
  4. data/ext/tsrs/extconf.rb +121 -0
  5. data/ext/tsrs/include/tsrs.h +113 -0
  6. data/ext/tsrs/tsrs.c +261 -0
  7. data/lib/tsrs/3.2/tsrs.bundle +0 -0
  8. data/lib/tsrs/3.3/tsrs.bundle +0 -0
  9. data/lib/tsrs/3.4/tsrs.bundle +0 -0
  10. data/lib/tsrs/4.0/tsrs.bundle +0 -0
  11. data/lib/tsrs/backend.rb +66 -0
  12. data/lib/tsrs/check_result.rb +61 -0
  13. data/lib/tsrs/diagnosed.rb +21 -0
  14. data/lib/tsrs/diagnostic.rb +112 -0
  15. data/lib/tsrs/errors.rb +25 -0
  16. data/lib/tsrs/options.rb +62 -0
  17. data/lib/tsrs/session.rb +57 -0
  18. data/lib/tsrs/transpile_result.rb +54 -0
  19. data/lib/tsrs/version.rb +5 -0
  20. data/lib/tsrs.rb +80 -0
  21. data/licenses/README.md +11 -0
  22. data/licenses/tsrs-Apache-2.0.txt +55 -0
  23. data/licenses/tsrs-NOTICE.txt +416 -0
  24. data/rust/.cargo/config.toml +5 -0
  25. data/rust/Cargo.lock +1301 -0
  26. data/rust/Cargo.toml +39 -0
  27. data/rust/build.rs +77 -0
  28. data/rust/cbindgen.toml +25 -0
  29. data/rust/rust-toolchain.toml +5 -0
  30. data/rust/rustfmt.toml +3 -0
  31. data/rust/src/check.rs +136 -0
  32. data/rust/src/lib.rs +213 -0
  33. data/rust/src/options.rs +60 -0
  34. data/rust/src/result.rs +52 -0
  35. data/rust/src/session.rs +194 -0
  36. data/rust/src/status.rs +26 -0
  37. data/rust/src/transpile.rs +66 -0
  38. data/rust/src/worker.rs +84 -0
  39. data/sig/tsrs/backend.rbs +44 -0
  40. data/sig/tsrs/check_result.rbs +33 -0
  41. data/sig/tsrs/diagnosed.rbs +15 -0
  42. data/sig/tsrs/diagnostic.rbs +66 -0
  43. data/sig/tsrs/errors.rbs +37 -0
  44. data/sig/tsrs/options.rbs +19 -0
  45. data/sig/tsrs/session.rbs +26 -0
  46. data/sig/tsrs/transpile_result.rbs +29 -0
  47. data/sig/tsrs/types.rbs +5 -0
  48. data/sig/tsrs/version.rbs +5 -0
  49. data/sig/tsrs.rbs +27 -0
  50. data/tsrs.gemspec +45 -0
  51. metadata +102 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 54dfa287579ab012e083b72dcd0132cefe15327ee95c342937f9d263f174e8dc
4
+ data.tar.gz: a3e0cf047c019fdd8b3a10f708e13415daff54ca5c71ee0fc9274059622cfb67
5
+ SHA512:
6
+ metadata.gz: 6fdcc45c8930c1ad1a2945ec5af8e34f291c92ed9bd6b42e2dea07bdc2b064a874b7a4b3f87d902b5d3026bcea78a635f29f16b7a056661d7d78fff9875ae846
7
+ data.tar.gz: 6aa94d90b397fe363641d1943db38e739537fc08f968ee2ff4e8326f105500f5a6cc7da7522ee531761fe4e43b0cffa8157816a2d6216f8da7ba9f4f28001a79
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Marco Roth
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,177 @@
1
+ <h2 align="center">🦀 tsrs for Ruby</h2>
2
+
3
+ <h4 align="center">A drop-in replacement for the TypeScript 7 compiler and language server, written in Rust.</h4>
4
+
5
+ <div align="center">Ruby bindings for <a href="https://github.com/oxc-project/tsrs">tsrs</a>, the Rust port of the TypeScript 7 type checker.</div><br/>
6
+
7
+ <p align="center">
8
+ <a href="https://rubygems.org/gems/tsrs"><img alt="Gem Version" src="https://img.shields.io/gem/v/tsrs"></a>
9
+ <a href="https://github.com/oxc-project/tsrs"><img alt="Documentation" src="https://img.shields.io/badge/oxc--project%2Ftsrs-documentation-green"></a>
10
+ <a href="https://github.com/marcoroth/tsrs-ruby/blob/main/LICENSE.txt"><img alt="License" src="https://img.shields.io/github/license/marcoroth/tsrs-ruby"></a>
11
+ <a href="https://github.com/marcoroth/tsrs-ruby/issues"><img alt="Issues" src="https://img.shields.io/github/issues/marcoroth/tsrs-ruby"></a>
12
+ </p>
13
+
14
+ <br/>
15
+
16
+ ### What is tsrs for Ruby?
17
+
18
+ Ruby bindings for [tsrs](https://github.com/oxc-project/tsrs), a drop-in replacement for the TypeScript 7 compiler and language server, written in Rust. Type check, compile and transpile TypeScript from Ruby, without the need for a JavaScript runtime.
19
+
20
+ Everything here is tsrs doing the work. For what the options mean and what it can do, the [TypeScript documentation](https://www.typescriptlang.org/tsconfig/) is the reference.
21
+
22
+ ### Installation
23
+
24
+ ```bash
25
+ bundle add tsrs
26
+ ```
27
+
28
+ Anywhere a precompiled gem is not published, the gem builds from source and needs the [Rust toolchain](https://rustup.rs). tsrs needs a recent Rust, 1.99.1 at the moment. `rust/rust-toolchain.toml` pins it, so rustup installs it for the build.
29
+
30
+ tsrs only runs on 64-bit platforms, so the gem doesn't support 32-bit ARM or x86.
31
+
32
+ ### Versioning
33
+
34
+ The gem carries the version of tsrs it packages. Gem v0.18.0 bundles tsrs v0.18.0. `Tsrs.tsrs_version` reports what a given build was compiled against, and `Tsrs.typescript_version` reports the TypeScript version that tsrs release is a port of.
35
+
36
+ So the version tracks tsrs, not the Ruby API here. If the gem needs releasing again for the same tsrs version, that release adds a fourth digit, as in v0.18.0.1.
37
+
38
+ ### Usage
39
+
40
+ #### Type checking
41
+
42
+ ```ruby
43
+ require "tsrs"
44
+
45
+ result = Tsrs.check(cwd: "app/javascript")
46
+ # => #<Tsrs::CheckResult status=2 errors=1 diagnostics=1>
47
+
48
+ result.success?
49
+ # => false
50
+
51
+ puts result
52
+ # app/javascript/src/index.ts:1:7 - error TS2322: Type 'string' is not assignable to type 'number'.
53
+
54
+ result.errors.first.code
55
+ # => 2322
56
+ ```
57
+
58
+ Without arguments, tsc finds the `tsconfig.json` in `cwd`. You can also point it at a project, or at files:
59
+
60
+ ```ruby
61
+ Tsrs.check(project: "app/javascript/tsconfig.json")
62
+ Tsrs.check("app/javascript/index.ts", strict: true)
63
+ ```
64
+
65
+ `Tsrs.check` never writes anything, as with `tsc --noEmit`. `validate!` raises `Tsrs::TypeError` if there were errors, so a rake task can fail on them:
66
+
67
+ ```ruby
68
+ task :typecheck do
69
+ Tsrs.check(cwd: "app/javascript").validate!
70
+ end
71
+ ```
72
+
73
+ #### Checking again and again
74
+
75
+ `Tsrs.check` runs tsc's command line, which is built to check once and exit, so a check's memory stays with the process. For anything long-lived, like a web server, a file watcher or a test suite that checks often, use a session instead:
76
+
77
+ ```ruby
78
+ session = Tsrs::Session.new(cwd: "app/javascript")
79
+
80
+ session.check.validate! # tsconfig.json in cwd
81
+ session.check("admin/tsconfig.json").errors # or any other project
82
+
83
+ session.close
84
+ ```
85
+
86
+ `Tsrs::Session.open(cwd: ...) { |session| ... }` closes the session when the block returns. A session is tsrs's API server, the same one behind tsrs's Node API. Each check builds the program in a snapshot and releases it afterwards, so memory levels off instead of growing by about 38 MB a check. Checks report the same diagnostics as `Tsrs.check`. They pick up what changed on disk since the last check, including the `tsconfig.json`, and can run from several threads at once.
87
+
88
+ The project's `tsconfig.json` decides the compiler options: a session check takes none of its own. It never writes anything, and raises `Tsrs::CheckError` when there is no project to load.
89
+
90
+ #### Compiling
91
+
92
+ `Tsrs.compile` runs tsc and writes its outputs, the way `tsc` does:
93
+
94
+ ```ruby
95
+ Tsrs.compile(project: "tsconfig.json", declaration: true)
96
+ ```
97
+
98
+ `Tsrs.tsc` takes command-line arguments exactly as `tsc` would:
99
+
100
+ ```ruby
101
+ Tsrs.tsc("--listFilesOnly", cwd: "app/javascript").output
102
+ ```
103
+
104
+ #### Transpiling one file
105
+
106
+ `Tsrs.transpile` turns one TypeScript source into JavaScript without type checking it, like TypeScript's `transpileModule`. It doesn't look at the file system:
107
+
108
+ ```ruby
109
+ Tsrs.transpile("export const answer: number = 42;", target: "es2020").code
110
+ # => "export const answer = 42;\n"
111
+
112
+ result = Tsrs.transpile(source, file_name: "app.tsx", jsx: "react-jsx", source_map: true)
113
+ result.code
114
+ result.map
115
+ ```
116
+
117
+ `Tsrs.transpile_declaration` emits the `.d.ts` for a source written for `isolatedDeclarations`:
118
+
119
+ ```ruby
120
+ Tsrs.transpile_declaration("export function greet(name: string): string { return name; }").code
121
+ # => "export declare function greet(name: string): string;\n"
122
+ ```
123
+
124
+ A source that doesn't parse raises `Tsrs::SyntaxError`, which carries the diagnostics.
125
+
126
+ #### Compiler options
127
+
128
+ Compiler options are tsc's, written in snake case or as tsc spells them. They are passed to tsc as command-line flags, so tsc reads them the way it always does:
129
+
130
+ | Ruby | tsc |
131
+ | --- | --- |
132
+ | `strict: true` | `--strict` |
133
+ | `no_emit: false` | `--noEmit false` |
134
+ | `target: "es2022"` | `--target es2022` |
135
+ | `lib: ["es2022", "dom"]` | `--lib es2022,dom` |
136
+ | `"esModuleInterop" => true` | `--esModuleInterop` |
137
+
138
+ Options that only make sense in a terminal, like `watch`, `build`, `init` and `help`, raise `Tsrs::OptionError`. So does a hash, which tsc's command line can't express. Put options like `paths` in a `tsconfig.json`.
139
+
140
+ #### Diagnostics
141
+
142
+ Each `Tsrs::Diagnostic` has a `code`, a `category` (`:error`, `:warning`, `:suggestion` or `:message`), a `message`, a `file`, and a 1-based `line` and `column`. `start` and `finish` are offsets in UTF-16 code units, the unit TypeScript counts in. `message_chain` and `related_information` hold the elaborations tsc attaches, and `to_s` prints a diagnostic the way tsc does.
143
+
144
+ #### Threads and memory
145
+
146
+ Every call releases the GVL, so other Ruby threads keep running and several checks can run at once. The work runs on a few long-lived native threads with large stacks, since type checking recurses deeply.
147
+
148
+ Transpiling gives back all the memory it used, and so does checking with a `Tsrs::Session`. `Tsrs.check`, `Tsrs.compile` and `Tsrs.tsc` don't: tsrs runs them like `tsc`, a process that checks once and exits, so much of what they allocate stays with the process. That's fine for a rake task or CI. In a long-lived process, check with a session instead.
149
+
150
+ ### Development
151
+
152
+ The gem is a C extension over a Rust crate. `rust/` builds a static library and generates the C header with [cbindgen](https://github.com/mozilla/cbindgen), `ext/tsrs/` wraps it, and `lib/` is the Ruby API over that.
153
+
154
+ tsrs doesn't publish its crates, so `rust/Cargo.toml` takes them from the release tag on GitHub. `rust/.cargo/config.toml` stamps the TypeScript version the way tsrs's own release builds do. The upstream workflow keeps the tag, that version, and the Rust toolchain in step with each tsrs release.
155
+
156
+ ```bash
157
+ bin/setup
158
+ bundle exec rake
159
+ ```
160
+
161
+ `sig/` is generated from the `#:` annotations next to the code. Regenerate it with `rake rbs` after changing a signature, and CI checks that it matches.
162
+
163
+ ### Acknowledgements
164
+
165
+ [tsrs](https://github.com/oxc-project/tsrs) is maintained at [oxc-project/tsrs](https://github.com/oxc-project/tsrs), and is a port of [TypeScript](https://github.com/microsoft/TypeScript). This gem only calls into it. Thank you for building these tools!
166
+
167
+ ### Contributing
168
+
169
+ Bug reports and pull requests are welcome on GitHub at https://github.com/marcoroth/tsrs-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/marcoroth/tsrs-ruby/blob/main/CODE_OF_CONDUCT.md).
170
+
171
+ Issues with type checking or emit belong [upstream](https://github.com/oxc-project/tsrs/issues), with a minimal reproduction, since this gem does none of that itself. Issues with the Ruby API, the build, or the bindings belong here.
172
+
173
+ ### License
174
+
175
+ The Ruby, C, and Rust code in this gem is available under the terms of the [MIT License](https://opensource.org/licenses/MIT).
176
+
177
+ It builds against [tsrs](https://github.com/oxc-project/tsrs), which is Apache-2.0 licensed and a derivative of TypeScript. Its native extension embeds TypeScript's `lib.*.d.ts` files. tsrs's license and NOTICE travel with the gem in [`licenses/`](licenses).
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+ require "fileutils"
5
+
6
+ ext_dir = __dir__
7
+ root_dir = File.expand_path("../..", ext_dir)
8
+
9
+ rust_dir = File.join(root_dir, "rust")
10
+
11
+ unless File.exist?(File.join(rust_dir, "Cargo.toml"))
12
+ abort <<~MESSAGE
13
+
14
+ ERROR: Rust sources not found at #{rust_dir}.
15
+
16
+ MESSAGE
17
+ end
18
+
19
+ unless system("cargo --version > /dev/null 2>&1")
20
+ abort <<~MESSAGE
21
+
22
+ ERROR: Rust toolchain not found.
23
+
24
+ tsrs requires the Rust toolchain to compile from source.
25
+
26
+ Install Rust: https://rustup.rs
27
+
28
+ MESSAGE
29
+ end
30
+
31
+ RUST_TARGETS = {
32
+ "aarch64-linux-gnu" => "aarch64-unknown-linux-gnu",
33
+ "aarch64-linux-musl" => "aarch64-unknown-linux-musl",
34
+ "arm64-darwin" => "aarch64-apple-darwin",
35
+ "x86_64-darwin" => "x86_64-apple-darwin",
36
+ "x86_64-linux-gnu" => "x86_64-unknown-linux-gnu",
37
+ "x86_64-linux-musl" => "x86_64-unknown-linux-musl",
38
+ }.freeze
39
+
40
+ cross_compiling = ENV.key?("RUBY_CC_VERSION")
41
+ target_platform = ENV.fetch("CARGO_BUILD_TARGET", nil)
42
+
43
+ if cross_compiling && target_platform.nil?
44
+ rcd_platform = ENV.fetch("RCD_PLATFORM", "")
45
+ target_platform = RUST_TARGETS[rcd_platform]
46
+
47
+ if target_platform.nil?
48
+ ruby_platform = RbConfig::CONFIG["arch"]
49
+ target_platform = RUST_TARGETS.values.find { |target| ruby_platform.include?(target.split("-").first) }
50
+ end
51
+ end
52
+
53
+ header_path = File.join(ext_dir, "include", "tsrs.h")
54
+
55
+ FileUtils.mkdir_p(File.dirname(header_path))
56
+
57
+ target_dir = File.join(rust_dir, "target")
58
+
59
+ if target_platform
60
+ puts "tsrs: Cross-compiling Rust for target: #{target_platform}"
61
+
62
+ system("cd #{rust_dir} && rustup target add #{target_platform}") || warn("tsrs: Failed to add Rust target #{target_platform}")
63
+
64
+ cargo_args = "--release --locked --target #{target_platform}"
65
+ lib_dir = File.join(target_dir, target_platform, "release")
66
+ else
67
+ puts "tsrs: Compiling Rust library for native platform..."
68
+
69
+ cargo_args = "--release --locked"
70
+ lib_dir = File.join(target_dir, "release")
71
+ end
72
+
73
+ unless system("cd #{rust_dir} && cargo build #{cargo_args}")
74
+ abort "ERROR: Failed to compile tsrs from Rust source."
75
+ end
76
+
77
+ unless File.exist?(header_path)
78
+ abort "ERROR: cbindgen did not generate #{header_path}. Try `cargo clean` in #{rust_dir} and reinstall."
79
+ end
80
+
81
+ static_lib = File.join(lib_dir, "libtsrs_ffi.a")
82
+ developing = File.exist?(File.join(root_dir, ".git"))
83
+
84
+ if File.exist?(static_lib) && !developing
85
+ vendored = File.join(ext_dir, "libtsrs_ffi.a")
86
+
87
+ FileUtils.cp(static_lib, vendored)
88
+ FileUtils.rm_rf(target_dir)
89
+
90
+ puts "tsrs: Static library vendored at #{vendored}, Rust build directory removed"
91
+
92
+ $LDFLAGS << " #{vendored}"
93
+ elsif File.exist?(static_lib)
94
+ puts "tsrs: Static library found at #{static_lib}"
95
+
96
+ $LDFLAGS << " #{static_lib}"
97
+ else
98
+ host_os = target_platform || RbConfig::CONFIG["host_os"]
99
+
100
+ lib_name = case host_os
101
+ when /darwin/
102
+ "libtsrs_ffi.dylib"
103
+ when /mingw|mswin|windows/
104
+ "tsrs_ffi.dll"
105
+ else
106
+ "libtsrs_ffi.so"
107
+ end
108
+
109
+ lib_path = File.join(lib_dir, lib_name)
110
+
111
+ abort "ERROR: Shared library not found at #{lib_path}" unless File.exist?(lib_path)
112
+
113
+ puts "tsrs: Shared library found at #{lib_path} (dynamic)"
114
+
115
+ $LDFLAGS << " -L#{lib_dir} -ltsrs_ffi"
116
+ $LDFLAGS << " -Wl,-rpath,#{lib_dir}" if RbConfig::CONFIG["host_os"].match?(/darwin|linux/)
117
+ end
118
+
119
+ $CFLAGS << " -I#{ext_dir}"
120
+
121
+ create_makefile("tsrs/tsrs")
@@ -0,0 +1,113 @@
1
+ /* Generated by cbindgen, do not edit manually */
2
+
3
+ #include <stdbool.h>
4
+ #include <stdint.h>
5
+ #include <stddef.h>
6
+
7
+ #ifndef TSRS_H
8
+ #define TSRS_H
9
+
10
+ typedef enum TsrsErrorCode {
11
+ TSRS_ERROR_CODE_NONE = 0,
12
+ TSRS_ERROR_CODE_OPTION,
13
+ TSRS_ERROR_CODE_ENCODING,
14
+ TSRS_ERROR_CODE_TRANSPILE,
15
+ TSRS_ERROR_CODE_CHECK,
16
+ TSRS_ERROR_CODE_INTERNAL,
17
+ TSRS_ERROR_CODE_PANIC,
18
+ } TsrsErrorCode;
19
+
20
+ typedef struct TsrsSession TsrsSession;
21
+
22
+ typedef struct TsrsResult {
23
+ char *value;
24
+ uintptr_t value_len;
25
+ char *error;
26
+ enum TsrsErrorCode code;
27
+ } TsrsResult;
28
+
29
+ /**
30
+ * # Safety
31
+ *
32
+ * `source` and `options_json` must be valid, nul-terminated UTF-8 strings.
33
+ */
34
+ struct TsrsResult tsrs_transpile(const char *source, const char *options_json);
35
+
36
+ /**
37
+ * # Safety
38
+ *
39
+ * `source` and `options_json` must be valid, nul-terminated UTF-8 strings.
40
+ */
41
+ struct TsrsResult tsrs_transpile_declaration(const char *source, const char *options_json);
42
+
43
+ /**
44
+ * # Safety
45
+ *
46
+ * `options_json` must be a valid, nul-terminated UTF-8 string.
47
+ */
48
+ struct TsrsResult tsrs_check(const char *options_json);
49
+
50
+ /**
51
+ * # Safety
52
+ *
53
+ * `cwd` must be a valid, nul-terminated UTF-8 string.
54
+ */
55
+ struct TsrsSession *tsrs_session_new(const char *cwd);
56
+
57
+ /**
58
+ * Taken before a check that runs without the GVL, so that freeing the original meanwhile cannot free the session.
59
+ *
60
+ * # Safety
61
+ *
62
+ * `session` must be a live pointer from `tsrs_session_new` or `tsrs_session_retain`.
63
+ */
64
+ struct TsrsSession *tsrs_session_retain(const struct TsrsSession *session);
65
+
66
+ /**
67
+ * # Safety
68
+ *
69
+ * `session` must be a live pointer from `tsrs_session_new` or `tsrs_session_retain`, and `options_json` a valid,
70
+ * nul-terminated UTF-8 string.
71
+ */
72
+ struct TsrsResult tsrs_session_check(const struct TsrsSession *session,
73
+ const char *options_json);
74
+
75
+ /**
76
+ * The pointer stays valid until `tsrs_session_free`.
77
+ *
78
+ * # Safety
79
+ *
80
+ * `session` must be a live pointer from `tsrs_session_new` or `tsrs_session_retain`, or null.
81
+ */
82
+ void tsrs_session_close(const struct TsrsSession *session);
83
+
84
+ /**
85
+ * # Safety
86
+ *
87
+ * `session` must be a pointer from `tsrs_session_new` or `tsrs_session_retain` that is not used afterwards, or null.
88
+ */
89
+ void tsrs_session_free(struct TsrsSession *session);
90
+
91
+ char *tsrs_version(void);
92
+
93
+ char *tsrs_tsrs_version(void);
94
+
95
+ char *tsrs_typescript_version(void);
96
+
97
+ /**
98
+ * # Safety
99
+ *
100
+ * `value` must be a pointer this library returned, and must not be used afterwards.
101
+ */
102
+ void tsrs_string_free(char *value);
103
+
104
+ /**
105
+ * # Safety
106
+ *
107
+ * `result` must be one this library returned, and must not be used afterwards.
108
+ */
109
+ void tsrs_result_free(struct TsrsResult result);
110
+
111
+ struct TsrsResult tsrs_panic_for_test(void);
112
+
113
+ #endif /* TSRS_H */