Skip to main content

zerodds_idl_java/
type_map.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3//! Mapping IDL-Primitive → Java-Type-Strings.
4//!
5//! Folgt OMG IDL4-Java-Mapping v1.0 §6 (Type Mapping). Java hat keine
6//! native unsigned-Integer-Typen — der Spec-konforme Workaround:
7//!
8//! - `unsigned short` → Java `int` (nicht `short`, um den vollen
9//!   Wertebereich abzubilden).
10//! - `unsigned long` → Java `long` (nicht `int`).
11//! - `unsigned long long` → Java `long` (mit Doc-Hinweis; Default ist
12//!   die `long`-Variante; `BigInteger` waere die volle Loesung,
13//!   bleibt hier außerhalb des aktuellen Scopes).
14//!
15//! `boolean` → `boolean`, `octet` → `byte`, `char`/`wchar` → `char`,
16//! `string`/`wstring` → `String`, `float`/`double` → `float`/`double`.
17
18use zerodds_idl::ast::{FloatingType, IntegerType, PrimitiveType};
19
20/// Mapping fuer eine [`PrimitiveType`] auf den Java-Typ.
21#[must_use]
22pub fn primitive_to_java(p: PrimitiveType) -> &'static str {
23    match p {
24        PrimitiveType::Boolean => "boolean",
25        PrimitiveType::Octet => "byte",
26        PrimitiveType::Char => "char",
27        PrimitiveType::WideChar => "char",
28        PrimitiveType::Integer(i) => integer_to_java(i),
29        PrimitiveType::Floating(f) => floating_to_java(f),
30    }
31}
32
33/// Mapping fuer Integer-Subtypen.
34///
35/// Spec-konformer Unsigned-Workaround:
36/// - `unsigned short` → `int` (16 Bit Range passt nicht in `short`).
37/// - `unsigned long` → `long` (32 Bit Range passt nicht in `int`).
38/// - `unsigned long long` → `long` (mit Vorzeichen-Treppe; siehe Doc).
39#[must_use]
40pub fn integer_to_java(i: IntegerType) -> &'static str {
41    match i {
42        IntegerType::Short | IntegerType::Int16 => "short",
43        IntegerType::Long | IntegerType::Int32 => "int",
44        IntegerType::LongLong | IntegerType::Int64 => "long",
45        // Unsigned-Workaround: nimm den naechst-groesseren signed Typ.
46        IntegerType::UShort | IntegerType::UInt16 => "int",
47        IntegerType::ULong | IntegerType::UInt32 => "long",
48        // unsigned long long: Java hat keinen 64-Bit-unsigned-Integer.
49        // Default: `long` (Vorzeichen, mit Doc-Comment im Emitter).
50        IntegerType::ULongLong | IntegerType::UInt64 => "long",
51        IntegerType::Int8 => "byte",
52        IntegerType::UInt8 => "short",
53    }
54}
55
56/// Mapping fuer Floating-Subtypen. `long double` ist außerhalb des aktuellen Scopes und wird
57/// in `typespec_to_java` als [`crate::error::JavaGenError::UnsupportedConstruct`]
58/// behandelt.
59#[must_use]
60pub fn floating_to_java(f: FloatingType) -> &'static str {
61    match f {
62        FloatingType::Float => "float",
63        FloatingType::Double => "double",
64        FloatingType::LongDouble => "double",
65    }
66}
67
68/// Liefert `true`, wenn ein IDL-Integer-Type fuer Java unsigned-Workaround
69/// braucht (Doc-Hinweis im Generator).
70#[must_use]
71pub fn is_unsigned(i: IntegerType) -> bool {
72    matches!(
73        i,
74        IntegerType::UShort
75            | IntegerType::UInt16
76            | IntegerType::ULong
77            | IntegerType::UInt32
78            | IntegerType::ULongLong
79            | IntegerType::UInt64
80            | IntegerType::UInt8
81    )
82}
83
84/// Wrapper-Klasse fuer ein primitive Java-Type, fuer Generics
85/// (z.B. `List<Integer>` statt `List<int>`).
86#[must_use]
87pub fn primitive_to_java_boxed(p: PrimitiveType) -> &'static str {
88    match p {
89        PrimitiveType::Boolean => "Boolean",
90        PrimitiveType::Octet => "Byte",
91        PrimitiveType::Char => "Character",
92        PrimitiveType::WideChar => "Character",
93        PrimitiveType::Integer(i) => integer_to_java_boxed(i),
94        PrimitiveType::Floating(f) => floating_to_java_boxed(f),
95    }
96}
97
98/// Boxed-Variante fuer Integer-Subtypen.
99#[must_use]
100pub fn integer_to_java_boxed(i: IntegerType) -> &'static str {
101    match i {
102        IntegerType::Short | IntegerType::Int16 => "Short",
103        IntegerType::Long | IntegerType::Int32 => "Integer",
104        IntegerType::LongLong | IntegerType::Int64 => "Long",
105        IntegerType::UShort | IntegerType::UInt16 => "Integer",
106        IntegerType::ULong | IntegerType::UInt32 => "Long",
107        IntegerType::ULongLong | IntegerType::UInt64 => "Long",
108        IntegerType::Int8 => "Byte",
109        IntegerType::UInt8 => "Short",
110    }
111}
112
113/// Boxed-Variante fuer Floating-Subtypen.
114#[must_use]
115pub fn floating_to_java_boxed(f: FloatingType) -> &'static str {
116    match f {
117        FloatingType::Float => "Float",
118        FloatingType::Double => "Double",
119        FloatingType::LongDouble => "Double",
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    #![allow(clippy::expect_used, clippy::panic)]
126    use super::*;
127
128    #[test]
129    fn primitive_boolean() {
130        assert_eq!(primitive_to_java(PrimitiveType::Boolean), "boolean");
131    }
132
133    #[test]
134    fn primitive_octet() {
135        assert_eq!(primitive_to_java(PrimitiveType::Octet), "byte");
136    }
137
138    #[test]
139    fn primitive_char() {
140        assert_eq!(primitive_to_java(PrimitiveType::Char), "char");
141    }
142
143    #[test]
144    fn primitive_wchar() {
145        assert_eq!(primitive_to_java(PrimitiveType::WideChar), "char");
146    }
147
148    #[test]
149    fn integer_short_signed() {
150        assert_eq!(integer_to_java(IntegerType::Short), "short");
151    }
152
153    #[test]
154    fn integer_long_signed() {
155        assert_eq!(integer_to_java(IntegerType::Long), "int");
156    }
157
158    #[test]
159    fn integer_long_long_signed() {
160        assert_eq!(integer_to_java(IntegerType::LongLong), "long");
161    }
162
163    #[test]
164    fn integer_unsigned_short_widens_to_int() {
165        // Spec §6.2: unsigned short → int (16-Bit-Wertebereich passt
166        // nicht in Java-`short`, da signed).
167        assert_eq!(integer_to_java(IntegerType::UShort), "int");
168    }
169
170    #[test]
171    fn integer_unsigned_long_widens_to_long() {
172        assert_eq!(integer_to_java(IntegerType::ULong), "long");
173    }
174
175    #[test]
176    fn integer_unsigned_long_long_keeps_long() {
177        // Default-Workaround: `long` (vorzeichen-treppe akzeptiert,
178        // Stretch-Goal: BigInteger).
179        assert_eq!(integer_to_java(IntegerType::ULongLong), "long");
180    }
181
182    #[test]
183    fn integer_explicit_widths() {
184        assert_eq!(integer_to_java(IntegerType::Int8), "byte");
185        assert_eq!(integer_to_java(IntegerType::UInt8), "short");
186        assert_eq!(integer_to_java(IntegerType::Int16), "short");
187        assert_eq!(integer_to_java(IntegerType::UInt16), "int");
188        assert_eq!(integer_to_java(IntegerType::Int32), "int");
189        assert_eq!(integer_to_java(IntegerType::UInt32), "long");
190        assert_eq!(integer_to_java(IntegerType::Int64), "long");
191        assert_eq!(integer_to_java(IntegerType::UInt64), "long");
192    }
193
194    #[test]
195    fn floating_float_double() {
196        assert_eq!(floating_to_java(FloatingType::Float), "float");
197        assert_eq!(floating_to_java(FloatingType::Double), "double");
198    }
199
200    #[test]
201    fn unsigned_marker_is_correct() {
202        assert!(!is_unsigned(IntegerType::Short));
203        assert!(is_unsigned(IntegerType::UShort));
204        assert!(!is_unsigned(IntegerType::Long));
205        assert!(is_unsigned(IntegerType::ULong));
206        assert!(is_unsigned(IntegerType::ULongLong));
207    }
208
209    #[test]
210    fn boxed_long_is_long() {
211        assert_eq!(integer_to_java_boxed(IntegerType::LongLong), "Long");
212    }
213
214    #[test]
215    fn boxed_int_is_integer() {
216        assert_eq!(integer_to_java_boxed(IntegerType::Long), "Integer");
217    }
218
219    #[test]
220    fn boxed_unsigned_long_is_long() {
221        assert_eq!(integer_to_java_boxed(IntegerType::ULong), "Long");
222    }
223
224    #[test]
225    fn boxed_primitive_boolean_is_capital_boolean() {
226        assert_eq!(primitive_to_java_boxed(PrimitiveType::Boolean), "Boolean");
227    }
228
229    #[test]
230    fn boxed_octet_is_byte_capital() {
231        assert_eq!(primitive_to_java_boxed(PrimitiveType::Octet), "Byte");
232    }
233
234    #[test]
235    fn boxed_floats() {
236        assert_eq!(floating_to_java_boxed(FloatingType::Float), "Float");
237        assert_eq!(floating_to_java_boxed(FloatingType::Double), "Double");
238    }
239}