baml-cc 0.208.5
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.
- checksums.yaml +7 -0
- data/exe/baml +1 -0
- data/exe/baml-cli +4 -0
- data/ext/ruby_ffi/Cargo.toml +52 -0
- data/ext/ruby_ffi/build.rs +21 -0
- data/ext/ruby_ffi/extconf.rb +17 -0
- data/ext/ruby_ffi/src/function_result.rs +75 -0
- data/ext/ruby_ffi/src/function_result_stream.rs +63 -0
- data/ext/ruby_ffi/src/lib.rs +388 -0
- data/ext/ruby_ffi/src/ruby_to_json.rs +651 -0
- data/ext/ruby_ffi/src/types/client_registry.rs +71 -0
- data/ext/ruby_ffi/src/types/lang_wrapper.rs +60 -0
- data/ext/ruby_ffi/src/types/log_collector.rs +607 -0
- data/ext/ruby_ffi/src/types/media.rs +142 -0
- data/ext/ruby_ffi/src/types/mod.rs +8 -0
- data/ext/ruby_ffi/src/types/request.rs +107 -0
- data/ext/ruby_ffi/src/types/response.rs +48 -0
- data/ext/ruby_ffi/src/types/runtime_ctx_manager.rs +18 -0
- data/ext/ruby_ffi/src/types/type_builder.rs +334 -0
- data/lib/baml.rb +63 -0
- data/lib/checked.rb +36 -0
- data/lib/stream.rb +87 -0
- data/lib/struct.rb +66 -0
- metadata +69 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
use baml_types::{BamlMedia, BamlMediaType, BamlValue};
|
|
2
|
+
use magnus::{class, function, Module, Object, RModule};
|
|
3
|
+
|
|
4
|
+
use crate::Result;
|
|
5
|
+
|
|
6
|
+
pub(crate) trait CloneAsBamlValue {
|
|
7
|
+
fn clone_as_baml_value(&self) -> BamlValue;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
#[magnus::wrap(class = "Baml::Ffi::Image", free_immediately, size)]
|
|
11
|
+
pub(crate) struct Image {
|
|
12
|
+
pub(crate) inner: baml_types::BamlMedia,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
impl Image {
|
|
16
|
+
pub fn from_url(url: String, media_type: Option<String>) -> Self {
|
|
17
|
+
Self {
|
|
18
|
+
inner: BamlMedia::url(BamlMediaType::Image, url, media_type),
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
pub fn from_base64(media_type: String, base64: String) -> Self {
|
|
23
|
+
Self {
|
|
24
|
+
inner: BamlMedia::base64(BamlMediaType::Image, base64, Some(media_type)),
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
pub fn define_in_ruby(module: &RModule) -> Result<()> {
|
|
29
|
+
let cls = module.define_class("Image", class::object())?;
|
|
30
|
+
cls.define_singleton_method("from_url", function!(Image::from_url, 2))?;
|
|
31
|
+
cls.define_singleton_method("from_base64", function!(Image::from_base64, 2))?;
|
|
32
|
+
|
|
33
|
+
Ok(())
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
impl CloneAsBamlValue for Image {
|
|
38
|
+
fn clone_as_baml_value(&self) -> BamlValue {
|
|
39
|
+
BamlValue::Media(self.inner.clone())
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#[magnus::wrap(class = "Baml::Ffi::Audio", free_immediately, size)]
|
|
44
|
+
pub(crate) struct Audio {
|
|
45
|
+
pub(crate) inner: BamlMedia,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
impl Audio {
|
|
49
|
+
pub fn from_url(url: String, media_type: Option<String>) -> Self {
|
|
50
|
+
Self {
|
|
51
|
+
inner: BamlMedia::url(BamlMediaType::Audio, url, media_type),
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
pub fn from_base64(media_type: String, base64: String) -> Self {
|
|
55
|
+
Self {
|
|
56
|
+
inner: BamlMedia::base64(BamlMediaType::Audio, base64, Some(media_type)),
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
pub fn define_in_ruby(module: &RModule) -> Result<()> {
|
|
61
|
+
let cls = module.define_class("Audio", class::object())?;
|
|
62
|
+
cls.define_singleton_method("from_url", function!(Audio::from_url, 2))?;
|
|
63
|
+
cls.define_singleton_method("from_base64", function!(Audio::from_base64, 2))?;
|
|
64
|
+
|
|
65
|
+
Ok(())
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
impl CloneAsBamlValue for Audio {
|
|
70
|
+
fn clone_as_baml_value(&self) -> BamlValue {
|
|
71
|
+
BamlValue::Media(self.inner.clone())
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
#[magnus::wrap(class = "Baml::Ffi::Pdf", free_immediately, size)]
|
|
76
|
+
pub(crate) struct Pdf {
|
|
77
|
+
pub(crate) inner: BamlMedia,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
impl Pdf {
|
|
81
|
+
pub fn from_url(url: String) -> Self {
|
|
82
|
+
Self {
|
|
83
|
+
inner: BamlMedia::url(BamlMediaType::Pdf, url, Some("application/pdf".to_string())),
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
pub fn from_base64(base64: String) -> Self {
|
|
88
|
+
Self {
|
|
89
|
+
inner: BamlMedia::base64(
|
|
90
|
+
BamlMediaType::Pdf,
|
|
91
|
+
base64,
|
|
92
|
+
Some("application/pdf".to_string()),
|
|
93
|
+
),
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
pub fn define_in_ruby(module: &RModule) -> Result<()> {
|
|
98
|
+
let cls = module.define_class("Pdf", class::object())?;
|
|
99
|
+
cls.define_singleton_method("from_url", function!(Pdf::from_url, 1))?;
|
|
100
|
+
cls.define_singleton_method("from_base64", function!(Pdf::from_base64, 1))?;
|
|
101
|
+
|
|
102
|
+
Ok(())
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
impl CloneAsBamlValue for Pdf {
|
|
107
|
+
fn clone_as_baml_value(&self) -> BamlValue {
|
|
108
|
+
BamlValue::Media(self.inner.clone())
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
#[magnus::wrap(class = "Baml::Ffi::Video", free_immediately, size)]
|
|
113
|
+
pub(crate) struct Video {
|
|
114
|
+
pub(crate) inner: BamlMedia,
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
impl Video {
|
|
118
|
+
pub fn from_url(url: String, media_type: Option<String>) -> Self {
|
|
119
|
+
Self {
|
|
120
|
+
inner: BamlMedia::url(BamlMediaType::Video, url, media_type),
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
pub fn from_base64(media_type: String, base64: String) -> Self {
|
|
124
|
+
Self {
|
|
125
|
+
inner: BamlMedia::base64(BamlMediaType::Video, base64, Some(media_type)),
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
pub fn define_in_ruby(module: &RModule) -> Result<()> {
|
|
130
|
+
let cls = module.define_class("Video", class::object())?;
|
|
131
|
+
cls.define_singleton_method("from_url", function!(Video::from_url, 2))?;
|
|
132
|
+
cls.define_singleton_method("from_base64", function!(Video::from_base64, 2))?;
|
|
133
|
+
|
|
134
|
+
Ok(())
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
impl CloneAsBamlValue for Video {
|
|
139
|
+
fn clone_as_baml_value(&self) -> BamlValue {
|
|
140
|
+
BamlValue::Media(self.inner.clone())
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
use magnus::{class, method, r_array::TypedArray, Error, Module, RModule, Ruby};
|
|
2
|
+
|
|
3
|
+
use crate::Result;
|
|
4
|
+
|
|
5
|
+
crate::lang_wrapper!(
|
|
6
|
+
HTTPRequest,
|
|
7
|
+
"Baml::Ffi::HTTPRequest",
|
|
8
|
+
baml_types::tracing::events::HTTPRequest,
|
|
9
|
+
clone_safe
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
crate::lang_wrapper!(
|
|
13
|
+
HTTPBody,
|
|
14
|
+
"Baml::Ffi::HTTPBody",
|
|
15
|
+
baml_types::tracing::events::HTTPBody,
|
|
16
|
+
clone_safe
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
impl HTTPRequest {
|
|
20
|
+
pub fn to_s(&self) -> String {
|
|
21
|
+
format!(
|
|
22
|
+
"HTTPRequest(url={}, method={}, headers={}, body={})",
|
|
23
|
+
self.inner.url(),
|
|
24
|
+
self.inner.method(),
|
|
25
|
+
serde_json::to_string_pretty(&self.inner.headers()).unwrap_or_default(),
|
|
26
|
+
serde_json::to_string_pretty(&self.inner.body().as_serde_value()).unwrap_or_default()
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
pub fn id(&self) -> String {
|
|
31
|
+
self.inner.id().to_string()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
pub fn url(&self) -> String {
|
|
35
|
+
self.inner.url().to_string()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
pub fn method(&self) -> String {
|
|
39
|
+
self.inner.method().to_string()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
pub fn headers(ruby: &Ruby, rb_self: &Self) -> Result<magnus::Value> {
|
|
43
|
+
// Convert headers to Ruby hash
|
|
44
|
+
serde_magnus::serialize(&rb_self.inner.headers())
|
|
45
|
+
.map_err(|e| Error::new(ruby.exception_runtime_error(), format!("{e:?}")))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
pub fn body(&self) -> HTTPBody {
|
|
49
|
+
// TODO: Avoid clone.
|
|
50
|
+
HTTPBody::from(self.inner.body().clone())
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
pub fn define_in_ruby(module: &RModule) -> Result<()> {
|
|
54
|
+
let cls = module.define_class("HTTPRequest", class::object())?;
|
|
55
|
+
|
|
56
|
+
cls.define_method("to_s", method!(HTTPRequest::to_s, 0))?;
|
|
57
|
+
cls.define_method("id", method!(HTTPRequest::id, 0))?;
|
|
58
|
+
cls.define_method("url", method!(HTTPRequest::url, 0))?;
|
|
59
|
+
cls.define_method("method", method!(HTTPRequest::method, 0))?;
|
|
60
|
+
cls.define_method("headers", method!(HTTPRequest::headers, 0))?;
|
|
61
|
+
cls.define_method("body", method!(HTTPRequest::body, 0))?;
|
|
62
|
+
|
|
63
|
+
Ok(())
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
impl HTTPBody {
|
|
68
|
+
pub fn raw(ruby: &Ruby, rb_self: &Self) -> Result<TypedArray<u8>> {
|
|
69
|
+
let array = ruby.typed_ary_new();
|
|
70
|
+
|
|
71
|
+
// TODO: Can we avoid cloning or at least do this faster than byte by
|
|
72
|
+
// byte?
|
|
73
|
+
for byte in rb_self.inner.raw() {
|
|
74
|
+
array.push(*byte)?;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
Ok(array)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
pub fn text(ruby: &Ruby, rb_self: &Self) -> Result<String> {
|
|
81
|
+
rb_self.inner.text().map(String::from).map_err(|e| {
|
|
82
|
+
Error::new(
|
|
83
|
+
ruby.exception_runtime_error(),
|
|
84
|
+
format!("Failed to get text from HTTP body:\n{e:?}"),
|
|
85
|
+
)
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
pub fn json(ruby: &Ruby, rb_self: &Self) -> Result<magnus::Value> {
|
|
90
|
+
serde_magnus::serialize(&rb_self.inner.json().map_err(|e| {
|
|
91
|
+
Error::new(
|
|
92
|
+
ruby.exception_runtime_error(),
|
|
93
|
+
format!("Failed deserializing HTTP body as JSON:\n{e:?}"),
|
|
94
|
+
)
|
|
95
|
+
})?)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
pub fn define_in_ruby(module: &RModule) -> Result<()> {
|
|
99
|
+
let cls = module.define_class("HTTPBody", class::object())?;
|
|
100
|
+
|
|
101
|
+
cls.define_method("raw", method!(HTTPBody::raw, 0))?;
|
|
102
|
+
cls.define_method("text", method!(HTTPBody::text, 0))?;
|
|
103
|
+
cls.define_method("json", method!(HTTPBody::json, 0))?;
|
|
104
|
+
|
|
105
|
+
Ok(())
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
use magnus::{class, method, Error, Module, RModule, Ruby};
|
|
2
|
+
|
|
3
|
+
use super::request::HTTPBody;
|
|
4
|
+
use crate::Result;
|
|
5
|
+
|
|
6
|
+
crate::lang_wrapper!(
|
|
7
|
+
HTTPResponse,
|
|
8
|
+
"Baml::Ffi::HTTPResponse",
|
|
9
|
+
baml_types::tracing::events::HTTPResponse,
|
|
10
|
+
clone_safe
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
impl HTTPResponse {
|
|
14
|
+
pub fn to_s(&self) -> String {
|
|
15
|
+
format!(
|
|
16
|
+
"HTTPResponse(status={}, headers={}, body={})",
|
|
17
|
+
self.inner.status,
|
|
18
|
+
serde_json::to_string_pretty(&self.inner.headers()).unwrap_or_default(),
|
|
19
|
+
serde_json::to_string_pretty(&self.inner.body.as_serde_value()).unwrap_or_default()
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
pub fn status(&self) -> u16 {
|
|
24
|
+
self.inner.status
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pub fn headers(ruby: &Ruby, rb_self: &Self) -> Result<magnus::Value> {
|
|
28
|
+
// Convert headers to Ruby hash
|
|
29
|
+
serde_magnus::serialize(&rb_self.inner.headers())
|
|
30
|
+
.map_err(|e| Error::new(ruby.exception_runtime_error(), format!("{e:?}")))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
pub fn body(&self) -> HTTPBody {
|
|
34
|
+
// TODO: Avoid clone.
|
|
35
|
+
HTTPBody::from(self.inner.body.clone())
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
pub fn define_in_ruby(module: &RModule) -> Result<()> {
|
|
39
|
+
let cls = module.define_class("HTTPResponse", class::object())?;
|
|
40
|
+
|
|
41
|
+
cls.define_method("to_s", method!(HTTPResponse::to_s, 0))?;
|
|
42
|
+
cls.define_method("status", method!(HTTPResponse::status, 0))?;
|
|
43
|
+
cls.define_method("headers", method!(HTTPResponse::headers, 0))?;
|
|
44
|
+
cls.define_method("body", method!(HTTPResponse::body, 0))?;
|
|
45
|
+
|
|
46
|
+
Ok(())
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
use magnus::{class, prelude::*, RModule};
|
|
2
|
+
|
|
3
|
+
use crate::Result;
|
|
4
|
+
|
|
5
|
+
#[magnus::wrap(class = "Baml::Ffi::RuntimeContextManager", free_immediately, size)]
|
|
6
|
+
pub struct RuntimeContextManager {
|
|
7
|
+
pub inner: baml_runtime::RuntimeContextManager,
|
|
8
|
+
}
|
|
9
|
+
impl RuntimeContextManager {
|
|
10
|
+
pub fn define_in_ruby(module: &RModule) -> Result<()> {
|
|
11
|
+
module.define_class("RuntimeContextManager", class::object())?;
|
|
12
|
+
|
|
13
|
+
//cls.define_method("upsert_tags", method!(RuntimeContextManager::upsert_tags, 1))?;
|
|
14
|
+
//cls.define_method("deep_clone", method!(RuntimeContextManager::deep_clone, 0))?;
|
|
15
|
+
|
|
16
|
+
Ok(())
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
#![allow(dead_code)]
|
|
2
|
+
|
|
3
|
+
use baml_runtime::type_builder::{self, WithMeta};
|
|
4
|
+
use baml_types::{ir_type::UnionConstructor, BamlValue};
|
|
5
|
+
use magnus::{
|
|
6
|
+
class, function, method, scan_args::scan_args, try_convert::TryConvertOwned, Module, Object,
|
|
7
|
+
RModule, Value,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
use crate::Result;
|
|
11
|
+
|
|
12
|
+
#[magnus::wrap(class = "Baml::Ffi::TypeBuilder", free_immediately, size)]
|
|
13
|
+
pub(crate) struct TypeBuilder {
|
|
14
|
+
pub(crate) inner: type_builder::TypeBuilder,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
crate::lang_wrapper!(EnumBuilder, "Baml::Ffi::EnumBuilder", type_builder::EnumBuilder, sync_thread_safe, name: String);
|
|
18
|
+
crate::lang_wrapper!(ClassBuilder, "Baml::Ffi::ClassBuilder", type_builder::ClassBuilder, sync_thread_safe, name: String);
|
|
19
|
+
crate::lang_wrapper!(
|
|
20
|
+
EnumValueBuilder,
|
|
21
|
+
"Baml::Ffi::EnumValueBuilder",
|
|
22
|
+
type_builder::EnumValueBuilder,
|
|
23
|
+
sync_thread_safe
|
|
24
|
+
);
|
|
25
|
+
crate::lang_wrapper!(
|
|
26
|
+
ClassPropertyBuilder,
|
|
27
|
+
"Baml::Ffi::ClassPropertyBuilder",
|
|
28
|
+
type_builder::ClassPropertyBuilder,
|
|
29
|
+
sync_thread_safe
|
|
30
|
+
);
|
|
31
|
+
crate::lang_wrapper!(
|
|
32
|
+
FieldType,
|
|
33
|
+
"Baml::Ffi::FieldType",
|
|
34
|
+
baml_types::TypeIR,
|
|
35
|
+
sync_thread_safe
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
impl TypeBuilder {
|
|
39
|
+
pub fn new() -> Self {
|
|
40
|
+
Self {
|
|
41
|
+
inner: type_builder::TypeBuilder::new(),
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
pub fn reset(&self) {
|
|
46
|
+
self.inner.reset();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
pub fn r#enum(&self, name: String) -> EnumBuilder {
|
|
50
|
+
EnumBuilder {
|
|
51
|
+
inner: self.inner.upsert_enum(name.as_str()),
|
|
52
|
+
name: name.to_string(),
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
pub fn class(&self, name: String) -> ClassBuilder {
|
|
57
|
+
ClassBuilder {
|
|
58
|
+
inner: self.inner.upsert_class(name.as_str()),
|
|
59
|
+
name: name.to_string(),
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
pub fn list(&self, inner: &FieldType) -> FieldType {
|
|
64
|
+
inner.inner.lock().unwrap().clone().as_list().into()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
pub fn optional(&self, inner: &FieldType) -> FieldType {
|
|
68
|
+
inner.inner.lock().unwrap().clone().as_optional().into()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
pub fn string(&self) -> FieldType {
|
|
72
|
+
baml_types::TypeIR::string().into()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
pub fn literal_string(&self, value: String) -> FieldType {
|
|
76
|
+
baml_types::TypeIR::literal_string(value).into()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
pub fn literal_int(&self, value: i64) -> FieldType {
|
|
80
|
+
baml_types::TypeIR::literal_int(value).into()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
pub fn literal_bool(&self, value: bool) -> FieldType {
|
|
84
|
+
baml_types::TypeIR::literal_bool(value).into()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
pub fn int(&self) -> FieldType {
|
|
88
|
+
baml_types::TypeIR::int().into()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
pub fn float(&self) -> FieldType {
|
|
92
|
+
baml_types::TypeIR::float().into()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
pub fn bool(&self) -> FieldType {
|
|
96
|
+
baml_types::TypeIR::bool().into()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
pub fn null(&self) -> FieldType {
|
|
100
|
+
baml_types::TypeIR::null().into()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
pub fn map(&self, key: &FieldType, value: &FieldType) -> FieldType {
|
|
104
|
+
baml_types::TypeIR::map(
|
|
105
|
+
key.inner.lock().unwrap().clone(),
|
|
106
|
+
value.inner.lock().unwrap().clone(),
|
|
107
|
+
)
|
|
108
|
+
.into()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
pub fn union(&self, args: &[Value]) -> Result<FieldType> {
|
|
112
|
+
let args = scan_args::<(), (), _, (), (), ()>(args)?;
|
|
113
|
+
let types: Vec<&FieldType> = args.splat;
|
|
114
|
+
Ok(baml_types::TypeIR::union(
|
|
115
|
+
types
|
|
116
|
+
.into_iter()
|
|
117
|
+
.map(|t| t.inner.lock().unwrap().clone())
|
|
118
|
+
.collect(),
|
|
119
|
+
)
|
|
120
|
+
.into())
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
pub fn add_baml(
|
|
124
|
+
ruby: &magnus::Ruby,
|
|
125
|
+
rb_self: &TypeBuilder,
|
|
126
|
+
baml: String,
|
|
127
|
+
runtime: &crate::BamlRuntimeFfi,
|
|
128
|
+
) -> Result<()> {
|
|
129
|
+
rb_self
|
|
130
|
+
.inner
|
|
131
|
+
.add_baml(&baml, runtime.inner.internal())
|
|
132
|
+
.map_err(|e| magnus::Error::new(ruby.exception_runtime_error(), e.to_string()))
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// this implements ruby's friendly to_s method for converting objects to strings
|
|
136
|
+
// when someone calls .to_s on a typebuilder in ruby, this method gets called
|
|
137
|
+
// under the hood, it uses rust's display trait to format everything nicely
|
|
138
|
+
// by using the same display logic across languages, we keep things consistent
|
|
139
|
+
// this helps make debugging and logging work the same way everywhere :D
|
|
140
|
+
pub fn to_s(&self) -> String {
|
|
141
|
+
self.inner.to_string()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
pub fn define_in_ruby(module: &RModule) -> Result<()> {
|
|
145
|
+
let cls = module.define_class("TypeBuilder", class::object())?;
|
|
146
|
+
|
|
147
|
+
cls.define_singleton_method("new", function!(TypeBuilder::new, 0))?;
|
|
148
|
+
cls.define_method("to_s", method!(TypeBuilder::to_s, 0))?;
|
|
149
|
+
cls.define_method("enum", method!(TypeBuilder::r#enum, 1))?;
|
|
150
|
+
// TODO: Not exposed, Ruby doesn't work right now.
|
|
151
|
+
// cls.define_method("reset", method!(TypeBuilder::reset, 0))?;
|
|
152
|
+
// "class" is used by Kernel: https://ruby-doc.org/core-3.0.2/Kernel.html#method-i-class
|
|
153
|
+
cls.define_method("class_", method!(TypeBuilder::class, 1))?;
|
|
154
|
+
cls.define_method("list", method!(TypeBuilder::list, 1))?;
|
|
155
|
+
cls.define_method("optional", method!(TypeBuilder::optional, 1))?;
|
|
156
|
+
cls.define_method("string", method!(TypeBuilder::string, 0))?;
|
|
157
|
+
cls.define_method("int", method!(TypeBuilder::int, 0))?;
|
|
158
|
+
cls.define_method("float", method!(TypeBuilder::float, 0))?;
|
|
159
|
+
cls.define_method("bool", method!(TypeBuilder::bool, 0))?;
|
|
160
|
+
cls.define_method("null", method!(TypeBuilder::null, 0))?;
|
|
161
|
+
cls.define_method("map", method!(TypeBuilder::map, 2))?;
|
|
162
|
+
cls.define_method("union", method!(TypeBuilder::union, -1))?;
|
|
163
|
+
cls.define_method("literal_string", method!(TypeBuilder::literal_string, 1))?;
|
|
164
|
+
cls.define_method("literal_int", method!(TypeBuilder::literal_int, 1))?;
|
|
165
|
+
cls.define_method("literal_bool", method!(TypeBuilder::literal_bool, 1))?;
|
|
166
|
+
cls.define_method("add_baml", method!(TypeBuilder::add_baml, 2))?;
|
|
167
|
+
|
|
168
|
+
Ok(())
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
impl FieldType {
|
|
173
|
+
pub fn list(&self) -> FieldType {
|
|
174
|
+
self.inner.lock().unwrap().clone().as_list().into()
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
pub fn optional(&self) -> FieldType {
|
|
178
|
+
self.inner.lock().unwrap().clone().as_optional().into()
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
pub fn define_in_ruby(module: &RModule) -> Result<()> {
|
|
182
|
+
let cls = module.define_class("FieldType", class::object())?;
|
|
183
|
+
|
|
184
|
+
cls.define_method("list", method!(FieldType::list, 0))?;
|
|
185
|
+
cls.define_method("optional", method!(FieldType::optional, 0))?;
|
|
186
|
+
|
|
187
|
+
Ok(())
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// magnus makes it non-ergonomic to convert a ScanArgsSplat into a Vec<&T> because Vec puts
|
|
192
|
+
// stuff on the heap, and moving Ruby-owned objects to the heap is very unsafe. It does so
|
|
193
|
+
// by bounding ScanArgsSplat using TryConvertOwned, which is not implemented for &TypedData,
|
|
194
|
+
// so we have to implement it ourselves. This is perfectly safe to do because FieldType does
|
|
195
|
+
// not have any references to Ruby objects.
|
|
196
|
+
unsafe impl TryConvertOwned for &FieldType {}
|
|
197
|
+
|
|
198
|
+
impl EnumBuilder {
|
|
199
|
+
pub fn value(&self, name: String) -> EnumValueBuilder {
|
|
200
|
+
self.inner
|
|
201
|
+
.lock()
|
|
202
|
+
.unwrap()
|
|
203
|
+
.upsert_value(name.as_str())
|
|
204
|
+
.into()
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
pub fn alias(&self, alias: Option<String>) -> Self {
|
|
208
|
+
self.inner.lock().unwrap().with_meta(
|
|
209
|
+
"alias",
|
|
210
|
+
alias.map_or(baml_types::BamlValue::Null, BamlValue::String),
|
|
211
|
+
);
|
|
212
|
+
self.inner.clone().into()
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
pub fn field(&self) -> FieldType {
|
|
216
|
+
baml_types::TypeIR::r#enum(&self.name).into()
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
pub fn define_in_ruby(module: &RModule) -> Result<()> {
|
|
220
|
+
let cls = module.define_class("EnumBuilder", class::object())?;
|
|
221
|
+
|
|
222
|
+
cls.define_method("value", method!(EnumBuilder::value, 1))?;
|
|
223
|
+
cls.define_method("alias", method!(EnumBuilder::alias, 1))?;
|
|
224
|
+
cls.define_method("field", method!(EnumBuilder::field, 0))?;
|
|
225
|
+
|
|
226
|
+
Ok(())
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
impl EnumValueBuilder {
|
|
231
|
+
pub fn alias(&self, alias: Option<String>) -> Self {
|
|
232
|
+
self.inner.lock().unwrap().with_meta(
|
|
233
|
+
"alias",
|
|
234
|
+
alias.map_or(baml_types::BamlValue::Null, BamlValue::String),
|
|
235
|
+
);
|
|
236
|
+
self.inner.clone().into()
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
pub fn skip(&self, skip: Option<bool>) -> Self {
|
|
240
|
+
self.inner
|
|
241
|
+
.lock()
|
|
242
|
+
.unwrap()
|
|
243
|
+
.with_meta("skip", skip.map_or(BamlValue::Null, BamlValue::Bool));
|
|
244
|
+
self.inner.clone().into()
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
pub fn description(&self, description: Option<String>) -> Self {
|
|
248
|
+
self.inner.lock().unwrap().with_meta(
|
|
249
|
+
"description",
|
|
250
|
+
description.map_or(baml_types::BamlValue::Null, BamlValue::String),
|
|
251
|
+
);
|
|
252
|
+
self.inner.clone().into()
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
pub fn define_in_ruby(module: &RModule) -> Result<()> {
|
|
256
|
+
let cls = module.define_class("EnumValueBuilder", class::object())?;
|
|
257
|
+
|
|
258
|
+
cls.define_method("alias", method!(EnumValueBuilder::alias, 1))?;
|
|
259
|
+
cls.define_method("skip", method!(EnumValueBuilder::skip, 1))?;
|
|
260
|
+
cls.define_method("description", method!(EnumValueBuilder::description, 1))?;
|
|
261
|
+
|
|
262
|
+
Ok(())
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
impl ClassBuilder {
|
|
267
|
+
pub fn reset(&self) {
|
|
268
|
+
self.inner.lock().unwrap().reset();
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
pub fn remove_property(&self, name: String) {
|
|
272
|
+
self.inner.lock().unwrap().remove_property(name.as_str());
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
pub fn field(&self) -> FieldType {
|
|
276
|
+
baml_types::TypeIR::class(&self.name).into()
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
pub fn property(&self, name: String) -> ClassPropertyBuilder {
|
|
280
|
+
self.inner
|
|
281
|
+
.lock()
|
|
282
|
+
.unwrap()
|
|
283
|
+
.upsert_property(name.as_str())
|
|
284
|
+
.into()
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
pub fn define_in_ruby(module: &RModule) -> Result<()> {
|
|
288
|
+
let cls = module.define_class("ClassBuilder", class::object())?;
|
|
289
|
+
|
|
290
|
+
cls.define_method("field", method!(ClassBuilder::field, 0))?;
|
|
291
|
+
cls.define_method("property", method!(ClassBuilder::property, 1))?;
|
|
292
|
+
// TODO: Not exposed, Ruby doesn't work right now.
|
|
293
|
+
// cls.define_method("reset", method!(ClassBuilder::reset, 0))?;
|
|
294
|
+
// cls.define_method("remove_property", method!(ClassBuilder::remove_property, 1))?;
|
|
295
|
+
|
|
296
|
+
Ok(())
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
impl ClassPropertyBuilder {
|
|
301
|
+
pub fn r#type(&self, r#type: &FieldType) -> Self {
|
|
302
|
+
self.inner
|
|
303
|
+
.lock()
|
|
304
|
+
.unwrap()
|
|
305
|
+
.set_type(r#type.inner.lock().unwrap().clone());
|
|
306
|
+
self.inner.clone().into()
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
pub fn alias(&self, alias: Option<String>) -> Self {
|
|
310
|
+
self.inner.lock().unwrap().with_meta(
|
|
311
|
+
"alias",
|
|
312
|
+
alias.map_or(baml_types::BamlValue::Null, BamlValue::String),
|
|
313
|
+
);
|
|
314
|
+
self.inner.clone().into()
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
pub fn description(&self, description: Option<String>) -> Self {
|
|
318
|
+
self.inner.lock().unwrap().with_meta(
|
|
319
|
+
"description",
|
|
320
|
+
description.map_or(baml_types::BamlValue::Null, BamlValue::String),
|
|
321
|
+
);
|
|
322
|
+
self.inner.clone().into()
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
pub fn define_in_ruby(module: &RModule) -> Result<()> {
|
|
326
|
+
let cls = module.define_class("ClassPropertyBuilder", class::object())?;
|
|
327
|
+
|
|
328
|
+
cls.define_method("type", method!(ClassPropertyBuilder::r#type, 1))?;
|
|
329
|
+
cls.define_method("alias", method!(ClassPropertyBuilder::alias, 1))?;
|
|
330
|
+
cls.define_method("description", method!(ClassPropertyBuilder::description, 1))?;
|
|
331
|
+
|
|
332
|
+
Ok(())
|
|
333
|
+
}
|
|
334
|
+
}
|