1#[expect(
2 clippy::unnecessary_box_returns,
3 reason = "Diplomat requires `Box<T>` returns for opaque constructors"
4)]
5#[expect(
6 clippy::use_self,
7 reason = "Diplomat expands macros using the concrete type name rather than `Self`."
8)]
9#[diplomat::bridge]
10mod ffi {
11 use mlt_core::encoder::EncoderConfig;
12 use mlt_core::mvt::{mvt_to_tile_layers, tile_layers_to_mvt};
13 use mlt_core::{Decoder, Layer, Parser};
14
15 #[diplomat::attr(auto, error)]
17 pub enum ConvertError {
18 InvalidInput,
20 EncodingFailed,
22 }
23
24 #[diplomat::opaque]
29 pub struct MltBuffer(Vec<u8>);
30
31 impl MltBuffer {
32 #[diplomat::attr(auto, getter = "bytes")]
34 #[expect(
35 clippy::needless_lifetimes,
36 reason = "diplomat requires explicit lifetimes"
37 )]
38 pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
39 &self.0
40 }
41
42 #[diplomat::attr(auto, getter = "len")]
44 pub fn len(&self) -> usize {
45 self.0.len()
46 }
47 }
48
49 #[diplomat::opaque_mut]
56 pub struct MltEncoderOptions(EncoderConfig);
57
58 impl MltEncoderOptions {
59 #[diplomat::attr(auto, constructor)]
62 pub fn new() -> Box<MltEncoderOptions> {
63 Box::new(MltEncoderOptions(EncoderConfig::default()))
64 }
65
66 pub fn set_tessellate(&mut self, enabled: bool) {
68 self.0 = self.0.with_tessellation(enabled);
69 }
70
71 pub fn set_attempt_spatial_morton_sort(&mut self, enabled: bool) {
73 self.0 = self.0.with_spatial_morton_sort(enabled);
74 }
75
76 pub fn set_attempt_spatial_hilbert_sort(&mut self, enabled: bool) {
78 self.0 = self.0.with_spatial_hilbert_sort(enabled);
79 }
80
81 pub fn set_attempt_id_sort(&mut self, enabled: bool) {
83 self.0 = self.0.with_id_sort(enabled);
84 }
85
86 pub fn set_allow_fsst(&mut self, enabled: bool) {
88 self.0 = self.0.with_fsst(enabled);
89 }
90
91 pub fn set_allow_fastpfor(&mut self, enabled: bool) {
93 self.0 = self.0.with_fastpfor(enabled);
94 }
95
96 pub fn set_allow_shared_dict(&mut self, enabled: bool) {
98 self.0 = self.0.with_shared_dict(enabled);
99 }
100 }
101
102 #[diplomat::opaque]
104 pub struct MltConverter;
105
106 impl MltConverter {
107 pub fn mlt_to_mvt(mlt: &[u8]) -> Result<Box<MltBuffer>, ConvertError> {
109 let layers = Parser::default()
110 .parse_layers(mlt)
111 .map_err(|_| ConvertError::InvalidInput)?;
112 let mut dec = Decoder::default();
113 let mut tiles = Vec::new();
114 for layer in layers {
115 if let Layer::Tag01(l) = layer {
116 let tile = l
117 .into_tile(&mut dec)
118 .map_err(|_| ConvertError::InvalidInput)?;
119 tiles.push(tile);
120 }
121 }
122 let out = tile_layers_to_mvt(tiles).map_err(|_| ConvertError::InvalidInput)?;
123 Ok(Box::new(MltBuffer(out)))
124 }
125
126 pub fn mvt_to_mlt(
128 mvt: &[u8],
129 options: &MltEncoderOptions,
130 ) -> Result<Box<MltBuffer>, ConvertError> {
131 let mut out = Vec::new();
132 let layers = mvt_to_tile_layers(mvt).map_err(|_| ConvertError::EncodingFailed)?;
133 for tile in layers {
134 let encoded_tile = tile
135 .encode(options.0)
136 .map_err(|_| ConvertError::EncodingFailed)?;
137 out.extend_from_slice(&encoded_tile);
138 }
139 Ok(Box::new(MltBuffer(out)))
140 }
141 }
142}