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