1use crate::export::ExportError;
6use crate::models::cads::*;
7use serde_yaml;
8
9pub struct CADSExporter;
11
12impl CADSExporter {
13 pub fn export(&self, asset: &CADSAsset) -> Result<String, ExportError> {
23 let yaml = Self::export_asset(asset);
24
25 #[cfg(feature = "schema-validation")]
27 {
28 use crate::validation::schema::validate_cads_internal;
29 validate_cads_internal(&yaml).map_err(ExportError::ValidationError)?;
30 }
31
32 Ok(yaml)
33 }
34
35 pub fn export_asset(asset: &CADSAsset) -> String {
81 let mut yaml = serde_yaml::Mapping::new();
82
83 yaml.insert(
85 serde_yaml::Value::String("apiVersion".to_string()),
86 serde_yaml::Value::String(asset.api_version.clone()),
87 );
88
89 let kind_str = match asset.kind {
90 CADSKind::AIModel => "AIModel",
91 CADSKind::MLPipeline => "MLPipeline",
92 CADSKind::Application => "Application",
93 CADSKind::ETLPipeline => "ETLPipeline",
94 CADSKind::SourceSystem => "SourceSystem",
95 CADSKind::DestinationSystem => "DestinationSystem",
96 CADSKind::DataPipeline => "DataPipeline",
97 CADSKind::ETLProcess => "ETLProcess",
98 };
99 yaml.insert(
100 serde_yaml::Value::String("kind".to_string()),
101 serde_yaml::Value::String(kind_str.to_string()),
102 );
103
104 yaml.insert(
105 serde_yaml::Value::String("id".to_string()),
106 serde_yaml::Value::String(asset.id.clone()),
107 );
108
109 yaml.insert(
110 serde_yaml::Value::String("name".to_string()),
111 serde_yaml::Value::String(asset.name.clone()),
112 );
113
114 yaml.insert(
115 serde_yaml::Value::String("version".to_string()),
116 serde_yaml::Value::String(asset.version.clone()),
117 );
118
119 let status_str = match asset.status {
120 CADSStatus::Draft => "draft",
121 CADSStatus::Validated => "validated",
122 CADSStatus::Production => "production",
123 CADSStatus::Deprecated => "deprecated",
124 };
125 yaml.insert(
126 serde_yaml::Value::String("status".to_string()),
127 serde_yaml::Value::String(status_str.to_string()),
128 );
129
130 if let Some(domain) = &asset.domain {
132 yaml.insert(
133 serde_yaml::Value::String("domain".to_string()),
134 serde_yaml::Value::String(domain.clone()),
135 );
136 }
137
138 if !asset.tags.is_empty() {
139 let tags_yaml: Vec<serde_yaml::Value> = asset
140 .tags
141 .iter()
142 .map(|t| serde_yaml::Value::String(t.to_string()))
143 .collect();
144 yaml.insert(
145 serde_yaml::Value::String("tags".to_string()),
146 serde_yaml::Value::Sequence(tags_yaml),
147 );
148 }
149
150 if let Some(description) = &asset.description {
151 let mut desc_map = serde_yaml::Mapping::new();
152 if let Some(purpose) = &description.purpose {
153 desc_map.insert(
154 serde_yaml::Value::String("purpose".to_string()),
155 serde_yaml::Value::String(purpose.clone()),
156 );
157 }
158 if let Some(usage) = &description.usage {
159 desc_map.insert(
160 serde_yaml::Value::String("usage".to_string()),
161 serde_yaml::Value::String(usage.clone()),
162 );
163 }
164 if let Some(limitations) = &description.limitations {
165 desc_map.insert(
166 serde_yaml::Value::String("limitations".to_string()),
167 serde_yaml::Value::String(limitations.clone()),
168 );
169 }
170 if let Some(external_links) = &description.external_links {
171 let links_yaml: Vec<serde_yaml::Value> = external_links
172 .iter()
173 .map(|link| {
174 let mut link_map = serde_yaml::Mapping::new();
175 link_map.insert(
176 serde_yaml::Value::String("url".to_string()),
177 serde_yaml::Value::String(link.url.clone()),
178 );
179 if let Some(desc) = &link.description {
180 link_map.insert(
181 serde_yaml::Value::String("description".to_string()),
182 serde_yaml::Value::String(desc.clone()),
183 );
184 }
185 serde_yaml::Value::Mapping(link_map)
186 })
187 .collect();
188 desc_map.insert(
189 serde_yaml::Value::String("externalLinks".to_string()),
190 serde_yaml::Value::Sequence(links_yaml),
191 );
192 }
193 if !desc_map.is_empty() {
194 yaml.insert(
195 serde_yaml::Value::String("description".to_string()),
196 serde_yaml::Value::Mapping(desc_map),
197 );
198 }
199 }
200
201 if let Some(runtime) = &asset.runtime {
202 let mut runtime_map = serde_yaml::Mapping::new();
203 if let Some(environment) = &runtime.environment {
204 runtime_map.insert(
205 serde_yaml::Value::String("environment".to_string()),
206 serde_yaml::Value::String(environment.clone()),
207 );
208 }
209 if let Some(endpoints) = &runtime.endpoints {
210 let endpoints_yaml: Vec<serde_yaml::Value> = endpoints
211 .iter()
212 .map(|e| serde_yaml::Value::String(e.clone()))
213 .collect();
214 runtime_map.insert(
215 serde_yaml::Value::String("endpoints".to_string()),
216 serde_yaml::Value::Sequence(endpoints_yaml),
217 );
218 }
219 if let Some(container) = &runtime.container {
220 let mut container_map = serde_yaml::Mapping::new();
221 if let Some(image) = &container.image {
222 container_map.insert(
223 serde_yaml::Value::String("image".to_string()),
224 serde_yaml::Value::String(image.clone()),
225 );
226 }
227 if !container_map.is_empty() {
228 runtime_map.insert(
229 serde_yaml::Value::String("container".to_string()),
230 serde_yaml::Value::Mapping(container_map),
231 );
232 }
233 }
234 if let Some(resources) = &runtime.resources {
235 let mut resources_map = serde_yaml::Mapping::new();
236 if let Some(cpu) = &resources.cpu {
237 resources_map.insert(
238 serde_yaml::Value::String("cpu".to_string()),
239 serde_yaml::Value::String(cpu.clone()),
240 );
241 }
242 if let Some(memory) = &resources.memory {
243 resources_map.insert(
244 serde_yaml::Value::String("memory".to_string()),
245 serde_yaml::Value::String(memory.clone()),
246 );
247 }
248 if let Some(gpu) = &resources.gpu {
249 resources_map.insert(
250 serde_yaml::Value::String("gpu".to_string()),
251 serde_yaml::Value::String(gpu.clone()),
252 );
253 }
254 if !resources_map.is_empty() {
255 runtime_map.insert(
256 serde_yaml::Value::String("resources".to_string()),
257 serde_yaml::Value::Mapping(resources_map),
258 );
259 }
260 }
261 if !runtime_map.is_empty() {
262 yaml.insert(
263 serde_yaml::Value::String("runtime".to_string()),
264 serde_yaml::Value::Mapping(runtime_map),
265 );
266 }
267 }
268
269 if let Some(sla) = &asset.sla
270 && let Some(properties) = &sla.properties
271 {
272 let mut sla_map = serde_yaml::Mapping::new();
273 let props_yaml: Vec<serde_yaml::Value> = properties
274 .iter()
275 .map(|prop| {
276 let mut prop_map = serde_yaml::Mapping::new();
277 prop_map.insert(
278 serde_yaml::Value::String("element".to_string()),
279 serde_yaml::Value::String(prop.element.clone()),
280 );
281 prop_map.insert(
282 serde_yaml::Value::String("value".to_string()),
283 Self::json_to_yaml_value(&prop.value),
284 );
285 prop_map.insert(
286 serde_yaml::Value::String("unit".to_string()),
287 serde_yaml::Value::String(prop.unit.clone()),
288 );
289 if let Some(driver) = &prop.driver {
290 prop_map.insert(
291 serde_yaml::Value::String("driver".to_string()),
292 serde_yaml::Value::String(driver.clone()),
293 );
294 }
295 serde_yaml::Value::Mapping(prop_map)
296 })
297 .collect();
298 sla_map.insert(
299 serde_yaml::Value::String("properties".to_string()),
300 serde_yaml::Value::Sequence(props_yaml),
301 );
302 yaml.insert(
303 serde_yaml::Value::String("sla".to_string()),
304 serde_yaml::Value::Mapping(sla_map),
305 );
306 }
307
308 if let Some(pricing) = &asset.pricing {
309 let mut pricing_map = serde_yaml::Mapping::new();
310 if let Some(model) = &pricing.model {
311 let model_str = match model {
312 CADSPricingModel::PerRequest => "per_request",
313 CADSPricingModel::PerHour => "per_hour",
314 CADSPricingModel::PerBatch => "per_batch",
315 CADSPricingModel::Subscription => "subscription",
316 CADSPricingModel::Internal => "internal",
317 };
318 pricing_map.insert(
319 serde_yaml::Value::String("model".to_string()),
320 serde_yaml::Value::String(model_str.to_string()),
321 );
322 }
323 if let Some(currency) = &pricing.currency {
324 pricing_map.insert(
325 serde_yaml::Value::String("currency".to_string()),
326 serde_yaml::Value::String(currency.clone()),
327 );
328 }
329 if let Some(unit_cost) = pricing.unit_cost {
330 pricing_map.insert(
331 serde_yaml::Value::String("unitCost".to_string()),
332 serde_yaml::Value::Number(serde_yaml::Number::from(unit_cost)),
333 );
334 }
335 if let Some(billing_unit) = &pricing.billing_unit {
336 pricing_map.insert(
337 serde_yaml::Value::String("billingUnit".to_string()),
338 serde_yaml::Value::String(billing_unit.clone()),
339 );
340 }
341 if let Some(notes) = &pricing.notes {
342 pricing_map.insert(
343 serde_yaml::Value::String("notes".to_string()),
344 serde_yaml::Value::String(notes.clone()),
345 );
346 }
347 if !pricing_map.is_empty() {
348 yaml.insert(
349 serde_yaml::Value::String("pricing".to_string()),
350 serde_yaml::Value::Mapping(pricing_map),
351 );
352 }
353 }
354
355 if let Some(team) = &asset.team {
356 let team_yaml: Vec<serde_yaml::Value> = team
357 .iter()
358 .map(|member| {
359 let mut member_map = serde_yaml::Mapping::new();
360 member_map.insert(
361 serde_yaml::Value::String("role".to_string()),
362 serde_yaml::Value::String(member.role.clone()),
363 );
364 member_map.insert(
365 serde_yaml::Value::String("name".to_string()),
366 serde_yaml::Value::String(member.name.clone()),
367 );
368 if let Some(contact) = &member.contact {
369 member_map.insert(
370 serde_yaml::Value::String("contact".to_string()),
371 serde_yaml::Value::String(contact.clone()),
372 );
373 }
374 serde_yaml::Value::Mapping(member_map)
375 })
376 .collect();
377 yaml.insert(
378 serde_yaml::Value::String("team".to_string()),
379 serde_yaml::Value::Sequence(team_yaml),
380 );
381 }
382
383 if let Some(risk) = &asset.risk {
384 let mut risk_map = serde_yaml::Mapping::new();
385 if let Some(classification) = &risk.classification {
386 let class_str = match classification {
387 CADSRiskClassification::Minimal => "minimal",
388 CADSRiskClassification::Low => "low",
389 CADSRiskClassification::Medium => "medium",
390 CADSRiskClassification::High => "high",
391 };
392 risk_map.insert(
393 serde_yaml::Value::String("classification".to_string()),
394 serde_yaml::Value::String(class_str.to_string()),
395 );
396 }
397 if let Some(impact_areas) = &risk.impact_areas {
398 let areas_yaml: Vec<serde_yaml::Value> = impact_areas
399 .iter()
400 .map(|area| {
401 let area_str = match area {
402 CADSImpactArea::Fairness => "fairness",
403 CADSImpactArea::Privacy => "privacy",
404 CADSImpactArea::Safety => "safety",
405 CADSImpactArea::Security => "security",
406 CADSImpactArea::Financial => "financial",
407 CADSImpactArea::Operational => "operational",
408 CADSImpactArea::Reputational => "reputational",
409 };
410 serde_yaml::Value::String(area_str.to_string())
411 })
412 .collect();
413 risk_map.insert(
414 serde_yaml::Value::String("impactAreas".to_string()),
415 serde_yaml::Value::Sequence(areas_yaml),
416 );
417 }
418 if let Some(intended_use) = &risk.intended_use {
419 risk_map.insert(
420 serde_yaml::Value::String("intendedUse".to_string()),
421 serde_yaml::Value::String(intended_use.clone()),
422 );
423 }
424 if let Some(out_of_scope_use) = &risk.out_of_scope_use {
425 risk_map.insert(
426 serde_yaml::Value::String("outOfScopeUse".to_string()),
427 serde_yaml::Value::String(out_of_scope_use.clone()),
428 );
429 }
430 if let Some(assessment) = &risk.assessment {
431 let mut assess_map = serde_yaml::Mapping::new();
432 if let Some(methodology) = &assessment.methodology {
433 assess_map.insert(
434 serde_yaml::Value::String("methodology".to_string()),
435 serde_yaml::Value::String(methodology.clone()),
436 );
437 }
438 if let Some(date) = &assessment.date {
439 assess_map.insert(
440 serde_yaml::Value::String("date".to_string()),
441 serde_yaml::Value::String(date.clone()),
442 );
443 }
444 if let Some(assessor) = &assessment.assessor {
445 assess_map.insert(
446 serde_yaml::Value::String("assessor".to_string()),
447 serde_yaml::Value::String(assessor.clone()),
448 );
449 }
450 if !assess_map.is_empty() {
451 risk_map.insert(
452 serde_yaml::Value::String("assessment".to_string()),
453 serde_yaml::Value::Mapping(assess_map),
454 );
455 }
456 }
457 if let Some(mitigations) = &risk.mitigations {
458 let mitigations_yaml: Vec<serde_yaml::Value> = mitigations
459 .iter()
460 .map(|mit| {
461 let mut mit_map = serde_yaml::Mapping::new();
462 mit_map.insert(
463 serde_yaml::Value::String("description".to_string()),
464 serde_yaml::Value::String(mit.description.clone()),
465 );
466 let status_str = match mit.status {
467 CADSMitigationStatus::Planned => "planned",
468 CADSMitigationStatus::Implemented => "implemented",
469 CADSMitigationStatus::Verified => "verified",
470 };
471 mit_map.insert(
472 serde_yaml::Value::String("status".to_string()),
473 serde_yaml::Value::String(status_str.to_string()),
474 );
475 serde_yaml::Value::Mapping(mit_map)
476 })
477 .collect();
478 risk_map.insert(
479 serde_yaml::Value::String("mitigations".to_string()),
480 serde_yaml::Value::Sequence(mitigations_yaml),
481 );
482 }
483 if !risk_map.is_empty() {
484 yaml.insert(
485 serde_yaml::Value::String("risk".to_string()),
486 serde_yaml::Value::Mapping(risk_map),
487 );
488 }
489 }
490
491 if let Some(compliance) = &asset.compliance {
492 let mut comp_map = serde_yaml::Mapping::new();
493 if let Some(frameworks) = &compliance.frameworks {
494 let frameworks_yaml: Vec<serde_yaml::Value> = frameworks
495 .iter()
496 .map(|fw| {
497 let mut fw_map = serde_yaml::Mapping::new();
498 fw_map.insert(
499 serde_yaml::Value::String("name".to_string()),
500 serde_yaml::Value::String(fw.name.clone()),
501 );
502 if let Some(category) = &fw.category {
503 fw_map.insert(
504 serde_yaml::Value::String("category".to_string()),
505 serde_yaml::Value::String(category.clone()),
506 );
507 }
508 let status_str = match fw.status {
509 CADSComplianceStatus::NotApplicable => "not_applicable",
510 CADSComplianceStatus::Assessed => "assessed",
511 CADSComplianceStatus::Compliant => "compliant",
512 CADSComplianceStatus::NonCompliant => "non_compliant",
513 };
514 fw_map.insert(
515 serde_yaml::Value::String("status".to_string()),
516 serde_yaml::Value::String(status_str.to_string()),
517 );
518 serde_yaml::Value::Mapping(fw_map)
519 })
520 .collect();
521 comp_map.insert(
522 serde_yaml::Value::String("frameworks".to_string()),
523 serde_yaml::Value::Sequence(frameworks_yaml),
524 );
525 }
526 if let Some(controls) = &compliance.controls {
527 let controls_yaml: Vec<serde_yaml::Value> = controls
528 .iter()
529 .map(|ctrl| {
530 let mut ctrl_map = serde_yaml::Mapping::new();
531 ctrl_map.insert(
532 serde_yaml::Value::String("id".to_string()),
533 serde_yaml::Value::String(ctrl.id.clone()),
534 );
535 ctrl_map.insert(
536 serde_yaml::Value::String("description".to_string()),
537 serde_yaml::Value::String(ctrl.description.clone()),
538 );
539 if let Some(evidence) = &ctrl.evidence {
540 ctrl_map.insert(
541 serde_yaml::Value::String("evidence".to_string()),
542 serde_yaml::Value::String(evidence.clone()),
543 );
544 }
545 serde_yaml::Value::Mapping(ctrl_map)
546 })
547 .collect();
548 comp_map.insert(
549 serde_yaml::Value::String("controls".to_string()),
550 serde_yaml::Value::Sequence(controls_yaml),
551 );
552 }
553 if !comp_map.is_empty() {
554 yaml.insert(
555 serde_yaml::Value::String("compliance".to_string()),
556 serde_yaml::Value::Mapping(comp_map),
557 );
558 }
559 }
560
561 if let Some(validation_profiles) = &asset.validation_profiles {
562 let profiles_yaml: Vec<serde_yaml::Value> = validation_profiles
563 .iter()
564 .map(|profile| {
565 let mut profile_map = serde_yaml::Mapping::new();
566 profile_map.insert(
567 serde_yaml::Value::String("name".to_string()),
568 serde_yaml::Value::String(profile.name.clone()),
569 );
570 if let Some(applies_to) = &profile.applies_to {
571 let mut applies_map = serde_yaml::Mapping::new();
572 if let Some(kind) = &applies_to.kind {
573 applies_map.insert(
574 serde_yaml::Value::String("kind".to_string()),
575 serde_yaml::Value::String(kind.clone()),
576 );
577 }
578 if let Some(risk_classification) = &applies_to.risk_classification {
579 applies_map.insert(
580 serde_yaml::Value::String("riskClassification".to_string()),
581 serde_yaml::Value::String(risk_classification.clone()),
582 );
583 }
584 if !applies_map.is_empty() {
585 profile_map.insert(
586 serde_yaml::Value::String("appliesTo".to_string()),
587 serde_yaml::Value::Mapping(applies_map),
588 );
589 }
590 }
591 let checks_yaml: Vec<serde_yaml::Value> = profile
592 .required_checks
593 .iter()
594 .map(|c| serde_yaml::Value::String(c.clone()))
595 .collect();
596 profile_map.insert(
597 serde_yaml::Value::String("requiredChecks".to_string()),
598 serde_yaml::Value::Sequence(checks_yaml),
599 );
600 serde_yaml::Value::Mapping(profile_map)
601 })
602 .collect();
603 yaml.insert(
604 serde_yaml::Value::String("validationProfiles".to_string()),
605 serde_yaml::Value::Sequence(profiles_yaml),
606 );
607 }
608
609 if let Some(bpmn_models) = &asset.bpmn_models {
610 let models_yaml: Vec<serde_yaml::Value> = bpmn_models
611 .iter()
612 .map(|model| {
613 let mut model_map = serde_yaml::Mapping::new();
614 model_map.insert(
615 serde_yaml::Value::String("name".to_string()),
616 serde_yaml::Value::String(model.name.clone()),
617 );
618 model_map.insert(
619 serde_yaml::Value::String("reference".to_string()),
620 serde_yaml::Value::String(model.reference.clone()),
621 );
622 let format_str = match model.format {
623 CADSBPMNFormat::Bpmn20Xml => "bpmn20-xml",
624 CADSBPMNFormat::Json => "json",
625 };
626 model_map.insert(
627 serde_yaml::Value::String("format".to_string()),
628 serde_yaml::Value::String(format_str.to_string()),
629 );
630 if let Some(description) = &model.description {
631 model_map.insert(
632 serde_yaml::Value::String("description".to_string()),
633 serde_yaml::Value::String(description.clone()),
634 );
635 }
636 serde_yaml::Value::Mapping(model_map)
637 })
638 .collect();
639 yaml.insert(
640 serde_yaml::Value::String("bpmnModels".to_string()),
641 serde_yaml::Value::Sequence(models_yaml),
642 );
643 }
644
645 if let Some(dmn_models) = &asset.dmn_models {
646 let models_yaml: Vec<serde_yaml::Value> = dmn_models
647 .iter()
648 .map(|model| {
649 let mut model_map = serde_yaml::Mapping::new();
650 model_map.insert(
651 serde_yaml::Value::String("name".to_string()),
652 serde_yaml::Value::String(model.name.clone()),
653 );
654 model_map.insert(
655 serde_yaml::Value::String("reference".to_string()),
656 serde_yaml::Value::String(model.reference.clone()),
657 );
658 let format_str = match model.format {
659 CADSDMNFormat::Dmn13Xml => "dmn13-xml",
660 CADSDMNFormat::Json => "json",
661 };
662 model_map.insert(
663 serde_yaml::Value::String("format".to_string()),
664 serde_yaml::Value::String(format_str.to_string()),
665 );
666 if let Some(description) = &model.description {
667 model_map.insert(
668 serde_yaml::Value::String("description".to_string()),
669 serde_yaml::Value::String(description.clone()),
670 );
671 }
672 serde_yaml::Value::Mapping(model_map)
673 })
674 .collect();
675 yaml.insert(
676 serde_yaml::Value::String("dmnModels".to_string()),
677 serde_yaml::Value::Sequence(models_yaml),
678 );
679 }
680
681 if let Some(openapi_specs) = &asset.openapi_specs {
682 let specs_yaml: Vec<serde_yaml::Value> = openapi_specs
683 .iter()
684 .map(|spec| {
685 let mut spec_map = serde_yaml::Mapping::new();
686 spec_map.insert(
687 serde_yaml::Value::String("name".to_string()),
688 serde_yaml::Value::String(spec.name.clone()),
689 );
690 spec_map.insert(
691 serde_yaml::Value::String("reference".to_string()),
692 serde_yaml::Value::String(spec.reference.clone()),
693 );
694 let format_str = match spec.format {
695 CADSOpenAPIFormat::Openapi30 => "openapi-3.0",
696 CADSOpenAPIFormat::Openapi31 => "openapi-3.1",
697 CADSOpenAPIFormat::Swagger20 => "swagger-2.0",
698 };
699 spec_map.insert(
700 serde_yaml::Value::String("format".to_string()),
701 serde_yaml::Value::String(format_str.to_string()),
702 );
703 if let Some(description) = &spec.description {
704 spec_map.insert(
705 serde_yaml::Value::String("description".to_string()),
706 serde_yaml::Value::String(description.clone()),
707 );
708 }
709 serde_yaml::Value::Mapping(spec_map)
710 })
711 .collect();
712 yaml.insert(
713 serde_yaml::Value::String("openapiSpecs".to_string()),
714 serde_yaml::Value::Sequence(specs_yaml),
715 );
716 }
717
718 if let Some(custom_properties) = &asset.custom_properties {
719 let mut custom_map = serde_yaml::Mapping::new();
720 for (key, value) in custom_properties {
721 custom_map.insert(
722 serde_yaml::Value::String(key.clone()),
723 Self::json_to_yaml_value(value),
724 );
725 }
726 if !custom_map.is_empty() {
727 yaml.insert(
728 serde_yaml::Value::String("customProperties".to_string()),
729 serde_yaml::Value::Mapping(custom_map),
730 );
731 }
732 }
733
734 serde_yaml::to_string(&serde_yaml::Value::Mapping(yaml))
736 .unwrap_or_else(|_| String::from(""))
737 }
738
739 fn json_to_yaml_value(json: &serde_json::Value) -> serde_yaml::Value {
741 match json {
742 serde_json::Value::Null => serde_yaml::Value::Null,
743 serde_json::Value::Bool(b) => serde_yaml::Value::Bool(*b),
744 serde_json::Value::Number(n) => {
745 if let Some(i) = n.as_i64() {
746 serde_yaml::Value::Number(serde_yaml::Number::from(i))
747 } else if let Some(f) = n.as_f64() {
748 serde_yaml::Value::Number(serde_yaml::Number::from(f))
749 } else {
750 serde_yaml::Value::String(n.to_string())
751 }
752 }
753 serde_json::Value::String(s) => serde_yaml::Value::String(s.clone()),
754 serde_json::Value::Array(arr) => {
755 let yaml_arr: Vec<serde_yaml::Value> =
756 arr.iter().map(Self::json_to_yaml_value).collect();
757 serde_yaml::Value::Sequence(yaml_arr)
758 }
759 serde_json::Value::Object(obj) => {
760 let mut yaml_map = serde_yaml::Mapping::new();
761 for (k, v) in obj {
762 yaml_map.insert(
763 serde_yaml::Value::String(k.clone()),
764 Self::json_to_yaml_value(v),
765 );
766 }
767 serde_yaml::Value::Mapping(yaml_map)
768 }
769 }
770 }
771}