1use std::{collections::HashMap, fmt::Display, hash::Hash};
18
19use serde::{ser::SerializeMap, Serialize};
20
21use crate::tfplugin6;
22
23#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
25pub enum StringKind {
26 #[default]
28 Plain = 0,
29
30 Markdown = 1,
32}
33
34#[derive(Clone, PartialEq, Eq, Hash, Debug)]
36pub struct Description {
37 pub kind: StringKind,
39 pub content: String,
41}
42
43impl Description {
44 pub fn plain<T>(content: T) -> Self
50 where
51 T: ToString,
52 {
53 Self {
54 kind: StringKind::Plain,
55 content: content.to_string(),
56 }
57 }
58 pub fn markdown<T>(content: T) -> Self
64 where
65 T: ToString,
66 {
67 Self {
68 kind: StringKind::Markdown,
69 content: content.to_string(),
70 }
71 }
72}
73
74impl<T> From<T> for Description
75where
76 T: ToString,
77{
78 fn from(value: T) -> Self {
79 Description::plain(value.to_string())
80 }
81}
82
83#[derive(Clone, PartialEq, Eq, Debug)]
85pub enum NestedBlock {
86 Single(Block),
88 List(Block),
90 Set(Block),
92 Map(Block),
94 Group(Block),
96 Optional(Block),
115}
116
117#[derive(Clone, PartialEq, Eq, Debug)]
119pub struct Block {
120 pub version: i64,
122 pub attributes: HashMap<String, Attribute>,
124 pub blocks: HashMap<String, NestedBlock>,
126 pub description: Description,
128 pub deprecated: bool,
130}
131
132impl Default for Block {
133 fn default() -> Block {
135 Block {
136 version: 1,
137 attributes: Default::default(),
138 blocks: Default::default(),
139 description: "empty".into(),
140 deprecated: false,
141 }
142 }
143}
144
145fn cvt_nested_blocks_tf6(
146 blocks: &HashMap<String, NestedBlock>,
147) -> ::prost::alloc::vec::Vec<tfplugin6::schema::NestedBlock> {
148 use tfplugin6::schema::nested_block::NestingMode;
149 blocks
150 .iter()
151 .map(|(name, nested_block)| {
152 let (nesting_mode, block) = match nested_block {
153 NestedBlock::Single(block) => (NestingMode::Single, block),
154 NestedBlock::List(block) => (NestingMode::List, block),
155 NestedBlock::Set(block) => (NestingMode::Set, block),
156 NestedBlock::Map(block) => (NestingMode::Map, block),
157 NestedBlock::Group(block) => (NestingMode::Group, block),
158 NestedBlock::Optional(block) => (NestingMode::List, block),
159 };
160 let nitems = match nested_block {
161 NestedBlock::Single(_) => (1, 1),
162 NestedBlock::List(_) => (0, i64::MAX),
163 NestedBlock::Set(_) => (0, i64::MAX),
164 NestedBlock::Map(_) => (0, 0),
165 NestedBlock::Group(_) => (0, 0),
166 NestedBlock::Optional(_) => (0, 1),
167 };
168 tfplugin6::schema::NestedBlock {
169 type_name: name.clone(),
170 block: Some(block.into()),
171 nesting: nesting_mode as i32,
172 min_items: nitems.0,
173 max_items: nitems.1,
174 }
175 })
176 .collect()
177}
178
179#[allow(deprecated)]
180fn cvt_attributes_tf6(
181 attrs: &HashMap<String, Attribute>,
182) -> ::prost::alloc::vec::Vec<tfplugin6::schema::Attribute> {
183 use tfplugin6::schema::object::NestingMode;
184 use tfplugin6::schema::Object;
185 attrs
186 .iter()
187 .map(|(name, attr)| {
188 let attr_type = attr.attr_type.to_string().into();
189 let nested = match &attr.attr_type {
190 AttributeType::AttributeSingle(attrs) => Some((NestingMode::Single, attrs)),
191 AttributeType::AttributeList(attrs) => Some((NestingMode::List, attrs)),
192 AttributeType::AttributeSet(attrs) => Some((NestingMode::Set, attrs)),
193 AttributeType::AttributeMap(attrs) => Some((NestingMode::Map, attrs)),
194 _ => None,
195 }
196 .map(|(nesting_mode, attrs)| Object {
197 attributes: cvt_attributes_tf6(attrs),
198 nesting: nesting_mode as i32,
199 min_items: 0,
200 max_items: if nesting_mode == NestingMode::Single {
201 1
202 } else {
203 i64::MAX
204 },
205 });
206 tfplugin6::schema::Attribute {
207 name: name.clone(),
208 r#type: attr_type,
209 nested_type: nested,
210 description: attr.description.content.clone(),
211 required: attr.constraint == AttributeConstraint::Required,
212 optional: attr.constraint == AttributeConstraint::OptionalComputed
213 || attr.constraint == AttributeConstraint::Optional,
214 computed: attr.constraint == AttributeConstraint::OptionalComputed
215 || attr.constraint == AttributeConstraint::Computed,
216 sensitive: attr.sensitive,
217 description_kind: match attr.description.kind {
218 StringKind::Plain => tfplugin6::StringKind::Plain,
219 StringKind::Markdown => tfplugin6::StringKind::Markdown,
220 } as i32,
221 deprecated: attr.deprecated,
222 }
223 })
224 .collect()
225}
226
227impl From<&Block> for tfplugin6::schema::Block {
228 fn from(value: &Block) -> Self {
229 Self {
230 attributes: cvt_attributes_tf6(&value.attributes),
231 block_types: cvt_nested_blocks_tf6(&value.blocks),
232 version: value.version,
233 description: value.description.content.clone(),
234 description_kind: match value.description.kind {
235 StringKind::Plain => tfplugin6::StringKind::Plain,
236 StringKind::Markdown => tfplugin6::StringKind::Markdown,
237 } as i32,
238 deprecated: value.deprecated,
239 }
240 }
241}
242
243#[derive(Clone, PartialEq, Eq, Debug)]
245pub enum AttributeType {
246 String,
248 Number,
250 Bool,
252 List(Box<AttributeType>),
254 Set(Box<AttributeType>),
256 Map(Box<AttributeType>),
258 Object(HashMap<String, AttributeType>),
260 Tuple(Vec<AttributeType>),
262 AttributeSingle(HashMap<String, Attribute>),
264 AttributeList(HashMap<String, Attribute>),
266 AttributeSet(HashMap<String, Attribute>),
268 AttributeMap(HashMap<String, Attribute>),
270 Any,
272}
273
274impl Serialize for AttributeType {
275 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
276 where
277 S: serde::Serializer,
278 {
279 struct AttributesAsType<'a>(&'a HashMap<String, Attribute>);
280 impl<'a> Serialize for AttributesAsType<'a> {
281 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
282 where
283 S: serde::Serializer,
284 {
285 let mut map = serializer.serialize_map(Some(self.0.len()))?;
286 for (name, attr) in self.0 {
287 map.serialize_entry(name, &attr.attr_type)?;
288 }
289 map.end()
290 }
291 }
292 match self {
293 AttributeType::String => serializer.serialize_str("string"),
294 AttributeType::Number => serializer.serialize_str("number"),
295 AttributeType::Bool => serializer.serialize_str("bool"),
296 AttributeType::List(attr) => ("list", attr).serialize(serializer),
297 AttributeType::Set(attr) => ("set", attr).serialize(serializer),
298 AttributeType::Map(attr) => ("map", attr).serialize(serializer),
299 AttributeType::Object(attrs) => ("object", attrs).serialize(serializer),
300 AttributeType::Tuple(attrs) => ("tuple", attrs).serialize(serializer),
301 AttributeType::AttributeSingle(attrs) => {
302 ("object", &AttributesAsType(attrs)).serialize(serializer)
303 }
304 AttributeType::AttributeList(attrs) => {
305 ("list", ("object", &AttributesAsType(attrs))).serialize(serializer)
306 }
307 AttributeType::AttributeSet(attrs) => {
308 ("set", ("object", &AttributesAsType(attrs))).serialize(serializer)
309 }
310 AttributeType::AttributeMap(attrs) => {
311 ("map", ("object", &AttributesAsType(attrs))).serialize(serializer)
312 }
313 AttributeType::Any => serializer.serialize_str("dynamic"),
314 }
315 }
316}
317
318impl Display for AttributeType {
319 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
320 return f.write_str(
321 serde_json::to_string(self)
322 .or(Err(std::fmt::Error))?
323 .as_str(),
324 );
325 }
326}
327
328#[derive(Clone, PartialEq, Eq, Hash, Debug)]
330pub enum AttributeConstraint {
331 Computed,
333 Optional,
335 OptionalComputed,
338 Required,
340}
341
342#[derive(Clone, PartialEq, Eq, Debug)]
344pub struct Attribute {
345 pub attr_type: AttributeType,
347 pub description: Description,
349 pub constraint: AttributeConstraint,
351 pub sensitive: bool,
353 pub deprecated: bool,
355}
356
357impl Default for Attribute {
358 fn default() -> Self {
359 Self {
360 attr_type: AttributeType::Any,
361 description: "empty".into(),
362 constraint: AttributeConstraint::OptionalComputed,
363 sensitive: false,
364 deprecated: false,
365 }
366 }
367}
368
369#[derive(Clone, PartialEq, Eq, Debug)]
371pub struct Schema {
372 pub version: i64,
374 pub block: Block,
376}
377
378impl From<&Schema> for tfplugin6::Schema {
379 fn from(value: &Schema) -> Self {
380 Self {
381 version: value.version,
382 block: Some((&value.block).into()),
383 }
384 }
385}
386
387#[derive(Clone, PartialEq, Eq, Debug)]
389pub enum Type {
390 String,
392 Number,
394 Bool,
396 List(Box<Type>),
398 Set(Box<Type>),
400 Map(Box<Type>),
402 Object(HashMap<String, Type>),
404 Tuple(Vec<Type>),
406 Any,
408}
409
410impl Serialize for Type {
411 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
412 where
413 S: serde::Serializer,
414 {
415 match self {
416 Type::String => serializer.serialize_str("string"),
417 Type::Number => serializer.serialize_str("number"),
418 Type::Bool => serializer.serialize_str("bool"),
419 Type::List(attr) => ("list", attr).serialize(serializer),
420 Type::Set(attr) => ("set", attr).serialize(serializer),
421 Type::Map(attr) => ("map", attr).serialize(serializer),
422 Type::Object(attrs) => ("object", attrs).serialize(serializer),
423 Type::Tuple(attrs) => ("tuple", attrs).serialize(serializer),
424 Type::Any => serializer.serialize_str("dynamic"),
425 }
426 }
427}
428
429impl Display for Type {
430 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
431 return f.write_str(
432 serde_json::to_string(self)
433 .or(Err(std::fmt::Error))?
434 .as_str(),
435 );
436 }
437}
438
439#[derive(Clone, PartialEq, Eq, Debug)]
441pub struct Parameter {
442 pub name: String,
444 pub param_type: Type,
446 pub allow_null: bool,
452 pub allow_unknown: bool,
459 pub description: Description,
461}
462
463impl Default for Parameter {
464 fn default() -> Self {
465 Self {
466 name: Default::default(),
467 param_type: Type::Any,
468 allow_null: Default::default(),
469 allow_unknown: Default::default(),
470 description: Description::plain(""),
471 }
472 }
473}
474
475impl From<&Parameter> for tfplugin6::function::Parameter {
476 fn from(value: &Parameter) -> Self {
477 Self {
478 name: value.name.clone(),
479 r#type: value.param_type.to_string().into(),
480 allow_null_value: value.allow_null,
481 allow_unknown_values: value.allow_unknown,
482 description: value.description.content.clone(),
483 description_kind: match value.description.kind {
484 StringKind::Markdown => tfplugin6::StringKind::Markdown,
485 StringKind::Plain => tfplugin6::StringKind::Plain,
486 } as i32,
487 }
488 }
489}
490
491#[derive(Debug, Clone, PartialEq, Eq)]
493pub struct FunctionSchema {
494 pub parameters: Vec<Parameter>,
496 pub variadic: Option<Parameter>,
500 pub return_type: Type,
502 pub summary: String,
504 pub description: Description,
506 pub deprecated: Option<String>,
510}
511
512impl Default for FunctionSchema {
513 fn default() -> Self {
514 Self {
515 parameters: Default::default(),
516 variadic: Default::default(),
517 return_type: Type::Any,
518 summary: Default::default(),
519 description: Description::plain(""),
520 deprecated: Default::default(),
521 }
522 }
523}
524
525impl From<&FunctionSchema> for tfplugin6::Function {
526 fn from(value: &FunctionSchema) -> Self {
527 Self {
528 parameters: value.parameters.iter().map(Into::into).collect(),
529 variadic_parameter: value.variadic.as_ref().map(Into::into),
530 r#return: Some(tfplugin6::function::Return {
531 r#type: value.return_type.to_string().into_bytes(),
532 }),
533 summary: value.summary.clone(),
534 description: value.description.content.clone(),
535 description_kind: match value.description.kind {
536 StringKind::Markdown => tfplugin6::StringKind::Markdown,
537 StringKind::Plain => tfplugin6::StringKind::Plain,
538 } as i32,
539 deprecation_message: match &value.deprecated {
540 Some(msg) if msg.is_empty() => "deprecated".to_owned(),
541 Some(msg) => msg.clone(),
542 None => String::new(),
543 },
544 }
545 }
546}