diff --git a/conjure-api/src/main/conjure/conjure-api.yml b/conjure-api/src/main/conjure/conjure-api.yml index da9fdc5da..bb5e0f1ed 100644 --- a/conjure-api/src/main/conjure/conjure-api.yml +++ b/conjure-api/src/main/conjure/conjure-api.yml @@ -70,6 +70,7 @@ types: primitive: PrimitiveType optional: OptionalType list: ListType + array: ArrayType set: SetType map: MapType reference: @@ -93,6 +94,7 @@ types: - STRING - DATETIME - INTEGER + - F32 - DOUBLE - SAFELONG - BINARY @@ -114,6 +116,10 @@ types: fields: keyType: Type valueType: Type + ArrayType: + docs: Arrays are an ordered list of primitive types that are non-null + fields: + itemType: PrimitiveType # objects TypeDefinition: diff --git a/conjure-core/src/main/java/com/palantir/conjure/defs/ConjureTypeParserVisitor.java b/conjure-core/src/main/java/com/palantir/conjure/defs/ConjureTypeParserVisitor.java index a1e4b38e3..90394d327 100644 --- a/conjure-core/src/main/java/com/palantir/conjure/defs/ConjureTypeParserVisitor.java +++ b/conjure-core/src/main/java/com/palantir/conjure/defs/ConjureTypeParserVisitor.java @@ -25,6 +25,7 @@ import com.palantir.conjure.parser.types.builtin.AnyType; import com.palantir.conjure.parser.types.builtin.BinaryType; import com.palantir.conjure.parser.types.builtin.DateTimeType; +import com.palantir.conjure.parser.types.collect.ArrayType; import com.palantir.conjure.parser.types.collect.ListType; import com.palantir.conjure.parser.types.collect.MapType; import com.palantir.conjure.parser.types.collect.OptionalType; @@ -124,6 +125,12 @@ public Type visitList(ListType type) { return Type.list(com.palantir.conjure.spec.ListType.of(type.itemType().visit(this))); } + @Override + public Type visitArray(ArrayType type) { + return Type.array(com.palantir.conjure.spec.ArrayType.of( + com.palantir.conjure.spec.PrimitiveType.valueOf(type.itemType().name()))); + } + @Override public Type visitMap(MapType type) { return Type.map(com.palantir.conjure.spec.MapType.of( diff --git a/conjure-core/src/main/java/com/palantir/conjure/defs/validator/EndpointDefinitionValidator.java b/conjure-core/src/main/java/com/palantir/conjure/defs/validator/EndpointDefinitionValidator.java index 641e80336..407fb27d1 100644 --- a/conjure-core/src/main/java/com/palantir/conjure/defs/validator/EndpointDefinitionValidator.java +++ b/conjure-core/src/main/java/com/palantir/conjure/defs/validator/EndpointDefinitionValidator.java @@ -24,6 +24,7 @@ import com.palantir.conjure.exceptions.ConjureRuntimeException; import com.palantir.conjure.spec.ArgumentDefinition; import com.palantir.conjure.spec.ArgumentName; +import com.palantir.conjure.spec.ArrayType; import com.palantir.conjure.spec.EndpointDefinition; import com.palantir.conjure.spec.ExternalReference; import com.palantir.conjure.spec.HttpMethod; @@ -33,6 +34,7 @@ import com.palantir.conjure.spec.ParameterId; import com.palantir.conjure.spec.ParameterType; import com.palantir.conjure.spec.PrimitiveType; +import com.palantir.conjure.spec.PrimitiveType.Value; import com.palantir.conjure.spec.SetType; import com.palantir.conjure.spec.Type; import com.palantir.conjure.spec.TypeDefinition; @@ -315,6 +317,11 @@ public Boolean visitList(ListType value) { return recursivelyValidate(value.getItemType(), visitor); } + @Override + public Boolean visitArray(ArrayType value) { + return value.getItemType().get() != Value.ANY; + } + @Override public Boolean visitSet(SetType value) { return recursivelyValidate(value.getItemType(), visitor); diff --git a/conjure-core/src/main/java/com/palantir/conjure/defs/validator/FieldDefinitionValidator.java b/conjure-core/src/main/java/com/palantir/conjure/defs/validator/FieldDefinitionValidator.java index 64e06ba13..b68e9f6a1 100644 --- a/conjure-core/src/main/java/com/palantir/conjure/defs/validator/FieldDefinitionValidator.java +++ b/conjure-core/src/main/java/com/palantir/conjure/defs/validator/FieldDefinitionValidator.java @@ -17,6 +17,7 @@ package com.palantir.conjure.defs.validator; import com.palantir.conjure.exceptions.ConjureIllegalStateException; +import com.palantir.conjure.spec.ArrayType; import com.palantir.conjure.spec.ExternalReference; import com.palantir.conjure.spec.FieldDefinition; import com.palantir.conjure.spec.ListType; @@ -62,6 +63,11 @@ public Void visitList(ListType value) { return value.getItemType().accept(this); } + @Override + public Void visitArray(ArrayType value) { + return this.visitPrimitive(value.getItemType()); + } + @Override public Void visitSet(SetType value) { return value.getItemType().accept(this); diff --git a/conjure-core/src/main/java/com/palantir/conjure/defs/validator/SafetyValidator.java b/conjure-core/src/main/java/com/palantir/conjure/defs/validator/SafetyValidator.java index b4d9c4e48..3c77a7b16 100644 --- a/conjure-core/src/main/java/com/palantir/conjure/defs/validator/SafetyValidator.java +++ b/conjure-core/src/main/java/com/palantir/conjure/defs/validator/SafetyValidator.java @@ -20,6 +20,7 @@ import com.palantir.conjure.exceptions.ConjureIllegalStateException; import com.palantir.conjure.spec.AliasDefinition; import com.palantir.conjure.spec.ArgumentName; +import com.palantir.conjure.spec.ArrayType; import com.palantir.conjure.spec.EndpointDefinition; import com.palantir.conjure.spec.EnumDefinition; import com.palantir.conjure.spec.ExternalReference; @@ -164,6 +165,11 @@ public Stream visitList(ListType value) { return value.getItemType().accept(this); } + @Override + public Stream visitArray(ArrayType value) { + return this.visitPrimitive(value.getItemType()); + } + @Override public Stream visitSet(SetType value) { return value.getItemType().accept(this); @@ -219,6 +225,11 @@ public Stream visitInteger() { return Stream.empty(); } + @Override + public Stream visitF32() { + return Stream.empty(); + } + @Override public Stream visitDouble() { return Stream.empty(); @@ -283,6 +294,11 @@ public Boolean visitList(ListType value) { return value.getItemType().accept(this); } + @Override + public Boolean visitArray(ArrayType value) { + return this.visitPrimitive(value.getItemType()); + } + @Override public Boolean visitSet(SetType value) { return value.getItemType().accept(this); @@ -328,6 +344,11 @@ public Boolean visitInteger() { return true; } + @Override + public Boolean visitF32() { + return true; + } + @Override public Boolean visitDouble() { return true; diff --git a/conjure-core/src/main/java/com/palantir/conjure/parser/types/ConjureTypeVisitor.java b/conjure-core/src/main/java/com/palantir/conjure/parser/types/ConjureTypeVisitor.java index 7487aaa62..3b4ef8deb 100644 --- a/conjure-core/src/main/java/com/palantir/conjure/parser/types/ConjureTypeVisitor.java +++ b/conjure-core/src/main/java/com/palantir/conjure/parser/types/ConjureTypeVisitor.java @@ -19,6 +19,7 @@ import com.palantir.conjure.parser.types.builtin.AnyType; import com.palantir.conjure.parser.types.builtin.BinaryType; import com.palantir.conjure.parser.types.builtin.DateTimeType; +import com.palantir.conjure.parser.types.collect.ArrayType; import com.palantir.conjure.parser.types.collect.ListType; import com.palantir.conjure.parser.types.collect.MapType; import com.palantir.conjure.parser.types.collect.OptionalType; @@ -32,6 +33,8 @@ public interface ConjureTypeVisitor { T visitList(ListType type); + T visitArray(ArrayType type); + T visitMap(MapType type); T visitOptional(OptionalType type); diff --git a/conjure-core/src/main/java/com/palantir/conjure/parser/types/collect/ArrayType.java b/conjure-core/src/main/java/com/palantir/conjure/parser/types/collect/ArrayType.java new file mode 100644 index 000000000..1a2eab09e --- /dev/null +++ b/conjure-core/src/main/java/com/palantir/conjure/parser/types/collect/ArrayType.java @@ -0,0 +1,41 @@ +/* + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.palantir.conjure.parser.types.collect; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.palantir.conjure.defs.ConjureImmutablesStyle; +import com.palantir.conjure.parser.types.ConjureType; +import com.palantir.conjure.parser.types.ConjureTypeVisitor; +import com.palantir.conjure.parser.types.primitive.PrimitiveType; +import org.immutables.value.Value; + +@Value.Immutable +@ConjureImmutablesStyle +public interface ArrayType extends ConjureType { + + @JsonProperty("item-type") + PrimitiveType itemType(); + + @Override + default T visit(ConjureTypeVisitor visitor) { + return visitor.visitArray(this); + } + + static ArrayType of(PrimitiveType itemType) { + return ImmutableArrayType.builder().itemType(itemType).build(); + } +} diff --git a/conjure-core/src/main/java/com/palantir/conjure/parser/types/primitive/PrimitiveType.java b/conjure-core/src/main/java/com/palantir/conjure/parser/types/primitive/PrimitiveType.java index 8b1202901..00e91d3a0 100644 --- a/conjure-core/src/main/java/com/palantir/conjure/parser/types/primitive/PrimitiveType.java +++ b/conjure-core/src/main/java/com/palantir/conjure/parser/types/primitive/PrimitiveType.java @@ -32,6 +32,7 @@ public enum PrimitiveType implements LocalReferenceType { STRING(TypeName.of("string")), INTEGER(TypeName.of("integer")), + F32(TypeName.of("f32")), DOUBLE(TypeName.of("double")), BOOLEAN(TypeName.of("boolean")), SAFELONG(TypeName.of("safelong")), diff --git a/conjure-core/src/test/java/com/palantir/conjure/defs/validator/TypeNameValidatorTest.java b/conjure-core/src/test/java/com/palantir/conjure/defs/validator/TypeNameValidatorTest.java index 0c629e9f1..c5f992edd 100644 --- a/conjure-core/src/test/java/com/palantir/conjure/defs/validator/TypeNameValidatorTest.java +++ b/conjure-core/src/test/java/com/palantir/conjure/defs/validator/TypeNameValidatorTest.java @@ -40,8 +40,9 @@ public void testInvalidNames() { .isInstanceOf(IllegalArgumentException.class) .hasMessage( "TypeNames must be a primitive type" - + " [STRING, DATETIME, INTEGER, DOUBLE, SAFELONG, BINARY, ANY, BOOLEAN, UUID, RID," - + " BEARERTOKEN, UNKNOWN] or match pattern ^[A-Z][a-z0-9]+([A-Z][a-z0-9]+)*$: %s", + + " [STRING, DATETIME, INTEGER, F32, DOUBLE, SAFELONG, BINARY, ANY, BOOLEAN," + + " UUID, RID, BEARERTOKEN, UNKNOWN]" + + " or match pattern ^[A-Z][a-z0-9]+([A-Z][a-z0-9]+)*$: %s", invalid); } } diff --git a/conjure-core/src/test/java/com/palantir/conjure/parser/types/TypeParserTests.java b/conjure-core/src/test/java/com/palantir/conjure/parser/types/TypeParserTests.java index b0b0d02e2..5c5ce1067 100644 --- a/conjure-core/src/test/java/com/palantir/conjure/parser/types/TypeParserTests.java +++ b/conjure-core/src/test/java/com/palantir/conjure/parser/types/TypeParserTests.java @@ -92,12 +92,11 @@ public void testParser_foreignRefType() throws ParseException { assertThatThrownBy(() -> TypeParser.INSTANCE.parse("1_bar.Foo")) .isInstanceOf(ParseException.class) - .hasMessage( - "TypeNames must be a primitive type [datetime, boolean, string, double, bearertoken, binary, " - + "safelong, integer, rid, any, uuid] or match pattern " - + "^[A-Z][a-z0-9]+([A-Z][a-z0-9]+)*$: 1_bar\n" - + "1_bar.Foo\n" - + "^"); + .hasMessage("TypeNames must be a primitive type [datetime, boolean, string, f32, double, bearertoken, " + + "binary, safelong, integer, rid, any, uuid] or match pattern " + + "^[A-Z][a-z0-9]+([A-Z][a-z0-9]+)*$: 1_bar\n" + + "1_bar.Foo\n" + + "^"); } @Test @@ -243,8 +242,8 @@ public void testInvalidNames() { assertThatThrownBy(() -> TypeParser.INSTANCE.parse(invalid)) .isInstanceOf(ParseException.class) .hasMessage( - "TypeNames must be a primitive type [datetime, boolean, string, double, bearertoken, binary," - + " safelong, integer, rid, any, uuid] or match pattern " + "TypeNames must be a primitive type [datetime, boolean, string, f32, double, bearertoken," + + " binary, safelong, integer, rid, any, uuid] or match pattern " + "^[A-Z][a-z0-9]+([A-Z][a-z0-9]+)*$:" + " %s\n" + "bytes\n" @@ -257,12 +256,11 @@ public void testInvalidNames_list() { String invalid = "list"; assertThatThrownBy(() -> TypeParser.INSTANCE.parse(invalid)) .isInstanceOf(ParseException.class) - .hasMessage( - "TypeNames must be a primitive type [datetime, boolean, string, double, bearertoken, binary," - + " safelong, integer, rid, any, uuid] or match pattern " - + "^[A-Z][a-z0-9]+([A-Z][a-z0-9]+)*$:" - + " bytes\n" - + "list\n" - + " ^"); + .hasMessage("TypeNames must be a primitive type [datetime, boolean, string, f32, double, bearertoken," + + " binary, safelong, integer, rid, any, uuid] or match pattern " + + "^[A-Z][a-z0-9]+([A-Z][a-z0-9]+)*$:" + + " bytes\n" + + "list\n" + + " ^"); } } diff --git a/conjure-core/src/test/resources/spec-tests/types.yml b/conjure-core/src/test/resources/spec-tests/types.yml index 8d74ada50..c3d9d8cc9 100644 --- a/conjure-core/src/test/resources/spec-tests/types.yml +++ b/conjure-core/src/test/resources/spec-tests/types.yml @@ -12,6 +12,9 @@ positive: IntegerExample: fields: integer: integer + F32Example: + fields: + f32: f32 DoubleExample: fields: double: double diff --git a/conjure-generator-common/src/main/java/com/palantir/conjure/visitor/DealiasingTypeVisitor.java b/conjure-generator-common/src/main/java/com/palantir/conjure/visitor/DealiasingTypeVisitor.java index b06d0b888..1d9c7c7f1 100644 --- a/conjure-generator-common/src/main/java/com/palantir/conjure/visitor/DealiasingTypeVisitor.java +++ b/conjure-generator-common/src/main/java/com/palantir/conjure/visitor/DealiasingTypeVisitor.java @@ -19,6 +19,7 @@ import com.google.common.base.Preconditions; import com.palantir.conjure.either.Either; import com.palantir.conjure.spec.AliasDefinition; +import com.palantir.conjure.spec.ArrayType; import com.palantir.conjure.spec.EnumDefinition; import com.palantir.conjure.spec.ExternalReference; import com.palantir.conjure.spec.ListType; @@ -103,6 +104,11 @@ public Either visitList(ListType value) { return Either.right(Type.list(value)); } + @Override + public Either visitArray(ArrayType value) { + return Either.right(Type.array(value)); + } + @Override public Either visitSet(SetType value) { return Either.right(Type.set(value)); diff --git a/conjure-generator-common/src/main/java/com/palantir/conjure/visitor/TypeVisitor.java b/conjure-generator-common/src/main/java/com/palantir/conjure/visitor/TypeVisitor.java index c9190eeb0..c0d7a5311 100644 --- a/conjure-generator-common/src/main/java/com/palantir/conjure/visitor/TypeVisitor.java +++ b/conjure-generator-common/src/main/java/com/palantir/conjure/visitor/TypeVisitor.java @@ -16,6 +16,7 @@ package com.palantir.conjure.visitor; +import com.palantir.conjure.spec.ArrayType; import com.palantir.conjure.spec.ExternalReference; import com.palantir.conjure.spec.ListType; import com.palantir.conjure.spec.MapType; @@ -141,6 +142,11 @@ public Boolean visitList(ListType _value) { return false; } + @Override + public Boolean visitArray(ArrayType _value) { + return false; + } + @Override public Boolean visitSet(SetType _value) { return false; @@ -184,6 +190,11 @@ public T visitList(ListType value) { throw new IllegalStateException("Unsupported type: " + value); } + @Override + public T visitArray(ArrayType value) { + throw new IllegalStateException("Unsupported type: " + value); + } + @Override public T visitSet(SetType value) { throw new IllegalStateException("Unsupported type: " + value); diff --git a/docs/concepts.md b/docs/concepts.md index aeecf4d80..8f3b572af 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -31,7 +31,8 @@ Users may define the following kinds of named types. These can be referenced by - `binary` - a sequence of binary. - `boolean` - `true` or `false` - `datetime` - an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) value e.g. `2018-07-25T10:20:32+01:00` - - `double` - a floating point number specified by [IEEE 754](https://ieeexplore.ieee.org/document/4610935/), which includes NaN, +/-Infinity and signed zero. + - `f32` - a 32-bit floating point number specified by [IEEE 754](https://ieeexplore.ieee.org/document/4610935/), which includes NaN, +/-Infinity and signed zero. + - `double` - a 64-bit floating point number specified by [IEEE 754](https://ieeexplore.ieee.org/document/4610935/), which includes NaN, +/-Infinity and signed zero. - `integer` - a signed 32-bit integer value ranging from -231 to 231 - 1. - `rid` - a [Resource Identifier](https://github.com/palantir/resource-identifier), e.g. `ri.recipes.main.ingredient.1234` - `safelong` - a signed 53-bit integer that can be safely represented by browsers without loss of precision, value ranges from -253 + 1 to 253 - 1 diff --git a/docs/spec/conjure_definitions.md b/docs/spec/conjure_definitions.md index 2a35c1962..3970bc12a 100644 --- a/docs/spec/conjure_definitions.md +++ b/docs/spec/conjure_definitions.md @@ -158,6 +158,7 @@ bearertoken binary boolean datetime +f32 double integer rid diff --git a/docs/spec/intermediate_representation.md b/docs/spec/intermediate_representation.md index 4ae691267..a379c4f73 100644 --- a/docs/spec/intermediate_representation.md +++ b/docs/spec/intermediate_representation.md @@ -207,6 +207,7 @@ The representation of a primitive type must have a "type" key with a string valu 1. STRING 1. DATETIME 1. INTEGER +1. F32 1. DOUBLE 1. SAFELONG 1. BINARY diff --git a/docs/spec/wire.md b/docs/spec/wire.md index bd4950ac2..8d5468f80 100644 --- a/docs/spec/wire.md +++ b/docs/spec/wire.md @@ -277,6 +277,7 @@ Conjure Type | JSON Type | Comment `boolean` | Boolean | `datetime` | String | In accordance with [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601). `double` | Number or `"NaN"` or `"Infinity"` or `"-Infinity"` | As defined by [IEEE 754 standard](http://ieeexplore.ieee.org/document/4610935/). +`f32` | Number or `"NaN"` or `"Infinity"` or `"-Infinity"` | As defined by [IEEE 754 standard](http://ieeexplore.ieee.org/document/4610935/). `integer` | Number | Signed 32 bits, value ranging from -231 to 231 - 1. `rid` | String | In accordance with the [Resource Identifier](https://github.com/palantir/resource-identifier) definition. `safelong` | Number | Integer with value ranging from -253 + 1 to 253 - 1. @@ -381,11 +382,12 @@ Serializers may use optional Smile features: raw binary encoding, string dedupli ### 6.1. Built-in types Conjure Type | Smile Type | Comments | ------------------ | ---------- | ---------| +----------------- |------------| ---------| `bearertoken` | String | `binary` | Binary | Smile natively supports binary data, so no Base64 encoding is necessary. `boolean` | Boolean | `datetime` | String | +`f32` | Float | Non-finite values are not handled specially. `double` | Double | Non-finite values are not handled specially. `integer` | Integer | `rid` | String | @@ -426,6 +428,7 @@ Conjure Type | PLAIN Representation | Comments | `binary` | unquoted String | Represented as a Base64 encoded string in accordance with [RFC 4648](https://tools.ietf.org/html/rfc4648#section-4). `boolean` | `true` or `false` | `datetime` | unquoted String | In accordance with [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601). +`f32` | Number or `NaN` or `Infinity` or `-Infinity` | As defined by [IEEE 754 standard](http://ieeexplore.ieee.org/document/4610935/). `double` | Number or `NaN` or `Infinity` or `-Infinity` | As defined by [IEEE 754 standard](http://ieeexplore.ieee.org/document/4610935/). `integer` | Number | Signed 32 bits, value ranging from -231 to 231 - 1. `rid` | unquoted String | In accordance with the [Resource Identifier](https://github.com/palantir/resource-identifier) definition.