Skip to main content

rust_ethernet_ip/client/
schema_export.rs

1use super::EipClient;
2use crate::schema::{self, SchemaExport};
3
4impl EipClient {
5    /// Exports a stable schema view built from the current discovery APIs.
6    pub async fn export_schema(&mut self) -> crate::error::Result<SchemaExport> {
7        let (discovered_tags, discovery_warnings) =
8            self.discover_tags_detailed_internal(true).await?;
9        let route_path = self.route_path_snapshot();
10        let mut schema = SchemaExport::new(route_path.as_ref());
11        schema.warnings.extend(discovery_warnings);
12
13        let mut tags = discovered_tags;
14        tags.sort_by(|a, b| a.name.cmp(&b.name));
15        schema.tags = tags.iter().map(schema::SchemaTag::from).collect();
16
17        let mut udt_sources: std::collections::HashMap<u32, (&str, u32)> =
18            std::collections::HashMap::new();
19        for tag in &tags {
20            if tag.data_type == 0x00A0
21                && let Some(template_instance_id) = tag.template_instance_id
22            {
23                udt_sources
24                    .entry(template_instance_id)
25                    .or_insert((tag.name.as_str(), tag.size));
26            }
27        }
28
29        let mut template_ids: Vec<u32> = udt_sources.keys().copied().collect();
30        template_ids.sort_unstable();
31
32        for template_id in template_ids {
33            let Some((tag_name, size_bytes)) = udt_sources.get(&template_id).copied() else {
34                continue;
35            };
36
37            match self
38                .get_udt_definition_by_template_id(template_id, tag_name)
39                .await
40            {
41                Ok((definition, structure_size_bytes)) => {
42                    schema.udts.push(schema::SchemaUdt::from_definition(
43                        &definition,
44                        Some(template_id),
45                        if size_bytes == 0 {
46                            structure_size_bytes
47                        } else {
48                            size_bytes
49                        },
50                    ));
51                }
52                Err(err) => schema.warnings.push(format!(
53                    "Failed to resolve UDT definition for tag '{}' (template {}): {}",
54                    tag_name, template_id, err
55                )),
56            }
57        }
58
59        schema.udts.sort_by(|a, b| a.name.cmp(&b.name));
60        Ok(schema)
61    }
62
63    /// Exports the current schema view as pretty-printed JSON.
64    pub async fn export_schema_json(&mut self) -> crate::error::Result<String> {
65        let schema = self.export_schema().await?;
66        serde_json::to_string_pretty(&schema).map_err(|err| {
67            crate::error::EtherNetIpError::Protocol(format!(
68                "Failed to serialize schema export to JSON: {}",
69                err
70            ))
71        })
72    }
73}