From e189a42836e88697dfd679fa4d656c4ba98ceca6 Mon Sep 17 00:00:00 2001 From: Reece Humphreys Date: Tue, 9 Jul 2024 11:02:48 -0400 Subject: [PATCH] Lint and format markdown files (#422) --- .github/workflows/lint.yml | 16 ++++++++ .markdownlint.json | 11 ++++- .../high-level-comparison/ice-reinvented.md | 2 + .../using-icerpc-with-ice.md | 1 + .../slice/converting-ice-into-slice.md | 2 +- .../icerpc-for-ice-users/slice/ice-object.md | 2 +- .../icerpc-for-ice-users/slice/new-slice.md | 41 +++++++++++-------- .../dispatch-pipeline-with-di.md | 6 +-- content/icerpc/duplex-transport.md | 16 ++++---- .../icerpc/ice-protocol/protocol-frames.md | 2 +- content/icerpc/invocation/outgoing-request.md | 1 + content/icerpc/multiplexed-transport.md | 20 ++++----- .../icerpc/slic-transport/protocol-frames.md | 2 + content/icerpc/slic-transport/streams.md | 2 +- content/slice/encoding/constructed-types.md | 13 +++--- content/slice/encoding/operation.md | 1 + content/slice/encoding/primitive-types.md | 2 + content/slice/language-guide/class-types.md | 22 ++++++---- content/slice/language-guide/comments.md | 10 ++++- content/slice/language-guide/enum-types.md | 15 ++++++- content/slice/language-guide/exception.md | 8 ++++ content/slice/language-guide/fields.md | 15 ++++++- content/slice/language-guide/parameters.md | 3 +- .../language-guide/preprocessor-directives.md | 1 + .../slice/language-guide/primitive-types.md | 2 + content/slice/language-guide/struct-types.md | 9 ++++ .../slice/language-reference/slice-grammar.md | 10 ++++- 27 files changed, 172 insertions(+), 63 deletions(-) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..ec0459f6 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,16 @@ +name: 'Lint Markdown Files' + +on: + pull_request: + branches: [main] + +jobs: + spellcheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: articulate/actions-markdownlint@v1 + with: + config: .markdownlint.json + files: 'content/**/*.md' + ignore: node_modules diff --git a/.markdownlint.json b/.markdownlint.json index 21943c77..1c43a79f 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -1,5 +1,12 @@ { - "MD013": { "line_length": 120, "tables": false, "code_blocks": false }, + "MD001": false, + "MD013": { + "line_length": 120, + "tables": false, + "code_blocks": false + }, + "MD024": false, "MD034": false, - "MD040": false + "MD040": false, + "MD055": false } diff --git a/content/icerpc-for-ice-users/high-level-comparison/ice-reinvented.md b/content/icerpc-for-ice-users/high-level-comparison/ice-reinvented.md index 033363b8..91d22d9a 100644 --- a/content/icerpc-for-ice-users/high-level-comparison/ice-reinvented.md +++ b/content/icerpc-for-ice-users/high-level-comparison/ice-reinvented.md @@ -14,6 +14,7 @@ Ice is a one-stop solution for building network applications. With Ice, you get components to help you build portable, multi-language networked applications. Ice includes: + - an RPC framework - IDL and serialization format (Slice) - configuration (Ice properties) @@ -26,6 +27,7 @@ Ice includes: On the other hand, IceRPC has a single focus: RPCs (the name gave it away!). When building an application with IceRPC, you use IceRPC for your RPCs, and you need to look outside IceRPC for other functionalities. For example, you could select: + - IceRPC for your RPCs - Slice or Protobuf to define your network APIs - YAML for configuration diff --git a/content/icerpc-for-ice-users/high-level-comparison/using-icerpc-with-ice.md b/content/icerpc-for-ice-users/high-level-comparison/using-icerpc-with-ice.md index c0dec151..f5ade6de 100644 --- a/content/icerpc-for-ice-users/high-level-comparison/using-icerpc-with-ice.md +++ b/content/icerpc-for-ice-users/high-level-comparison/using-icerpc-with-ice.md @@ -13,6 +13,7 @@ using IceRPC, or use IceRPC to create new services for your Ice clients. If you start from an existing Ice client or server, the first step is to convert your Slice definitions (in `.ice` files) to the new Slice syntax. The converted Slice files must specify `Slice1` mode: + ```slice mode = Slice1 // required for interop with Ice ... diff --git a/content/icerpc-for-ice-users/slice/converting-ice-into-slice.md b/content/icerpc-for-ice-users/slice/converting-ice-into-slice.md index c56e3a2c..c399d24e 100644 --- a/content/icerpc-for-ice-users/slice/converting-ice-into-slice.md +++ b/content/icerpc-for-ice-users/slice/converting-ice-into-slice.md @@ -273,7 +273,7 @@ class Person { With the .ice syntax, the return type of an operation can be split between a return type and out parameters, whereas with the .slice syntax, an operation has only "in" parameters but can return a tuple. -When converting .ice definitions into .slice definitions, keep in mind that Ice encodes out parameters _before_ the +When converting .ice definitions into .slice definitions, keep in mind that Ice encodes out parameters *before* the return type. {% aside alignment="top" %} diff --git a/content/icerpc-for-ice-users/slice/ice-object.md b/content/icerpc-for-ice-users/slice/ice-object.md index 0103a194..89e8894e 100644 --- a/content/icerpc-for-ice-users/slice/ice-object.md +++ b/content/icerpc-for-ice-users/slice/ice-object.md @@ -79,7 +79,7 @@ unnecessary (`uncheckedCast` works just as well), it's shown by all Ice demos an The net result is: if you reimplement an existing Ice server with IceRPC, your services need to implement `Ice::Object` when they are being "checked cast" by existing Ice client applications. -## Checked cast and unchecked cast in IceRPC for C# +## Checked cast and unchecked cast in IceRPC for C\# If you like `checkedCast` and want to keep check-casting your proxies, the IceRPC + Slice integration provides an equivalent API: [AsAsync]. The target service must implement `Ice::Object`; otherwise, `AsAsync` will fail with a diff --git a/content/icerpc-for-ice-users/slice/new-slice.md b/content/icerpc-for-ice-users/slice/new-slice.md index b94669fa..76e53402 100644 --- a/content/icerpc-for-ice-users/slice/new-slice.md +++ b/content/icerpc-for-ice-users/slice/new-slice.md @@ -16,6 +16,7 @@ applications. With Ice, the version of the Ice encoding to use when sending a request is a runtime decision. You can reconfigure a proxy to use the version of your choice. For example: + ```csharp {% title="Setting the Ice encoding version with Ice for C#" %} helloPrx = helloPrx.ice_encodingVersion(Ice.Util.Encoding_1_0); ``` @@ -27,12 +28,14 @@ With the new Slice language, the encoding to use is decided at build-time, when define an interface, the encoding for operation arguments and return values is specified unambiguously with the [mode statement](/slice1/language-guide/compilation-mode), and gets hard-coded in the generated code. -#### Example +### Example ```slice mode = Slice1 ``` + or + ```slice mode = Slice2 ``` @@ -46,7 +49,7 @@ A Slice file that doesn't specify a compilation mode uses the default mode: Slic The compilation mode also determines which definitions are allowed in your Slice file. -#### Slice1 +### Slice1 This mode provides an equivalent syntax for all Slice definitions in the .ice syntax, including classes, exceptions, interfaces, and structs. The names are mostly the same: for example, a class in a `.ice` file corresponds to a @@ -54,11 +57,12 @@ class in a `.slice` file, and a struct in a `.ice` file corresponds to a compact You should use this mode when (and only when) you need to send or receive requests to and from Ice applications. -#### Slice2 +### Slice2 This is the default mode and the preferred mode when you don't need interop with Ice applications. This mode allows you to mark any type as optional with the `?` suffix. For example: + ```slice // Implicitly uses `mode = Slice2` @@ -69,25 +73,28 @@ interface Translator { ``` Slice2 also provides: - - stream parameters - - unsigned integer types such as uint32 - - variable-size integer types such as varint64 - - underlying types for enums - - structs that can be augmented while maintaining on-the-wire compatibility -However, Slice2 is not a superset of Slice1. The following constructs are only accepted in Slice1 mode: - - classes, including AnyClass - - exceptions +- stream parameters +- unsigned integer types such as uint32 +- variable-size integer types such as varint64 +- underlying types for enums +- structs that can be augmented while maintaining on-the-wire compatibility + +However, Slice2 is not a superset of Slice1. The following constructs are only accepted in Slice1 mode + +- classes, including AnyClass +- exceptions ## New constructs The .slice syntax adds a few constructs that are available with both Slice1 and Slice2 but have no equivalent with the .ice syntax, namely: - - anonymous sequences and dictionaries\ - You can now use `Sequence` directly as a parameter or field type. - - custom types\ - A custom type is a type that you encode and decode yourself in all language mappings. - - typealias\ - A typealias is a new name for another type. + +- anonymous sequences and dictionaries\ + You can now use `Sequence` directly as a parameter or field type. +- custom types\ + A custom type is a type that you encode and decode yourself in all language mappings. +- typealias\ + A typealias is a new name for another type. [convert]: converting-ice-into-slice diff --git a/content/icerpc/dependency-injection/dispatch-pipeline-with-di.md b/content/icerpc/dependency-injection/dispatch-pipeline-with-di.md index 73aae3e4..3d4bccf5 100644 --- a/content/icerpc/dependency-injection/dispatch-pipeline-with-di.md +++ b/content/icerpc/dependency-injection/dispatch-pipeline-with-di.md @@ -112,9 +112,9 @@ leaf dispatcher via services injected by a DI container. Such a DI-friendly middleware needs to implement one of the following `IMiddleware` interfaces: -- [IMiddleware](csharp:IceRpc.Extensions.DependencyInjection.IMiddleware-1) -- [IMiddleware](csharp:IceRpc.Extensions.DependencyInjection.IMiddleware-2) -- [IMiddleware](csharp:IceRpc.Extensions.DependencyInjection.IMiddleware-3) +- [`IMiddleware`](csharp:IceRpc.Extensions.DependencyInjection.IMiddleware-1) +- [`IMiddleware`](csharp:IceRpc.Extensions.DependencyInjection.IMiddleware-2) +- [`IMiddleware`](csharp:IceRpc.Extensions.DependencyInjection.IMiddleware-3) For example, say we want to reimplement the deadline middleware in a more DI-friendly fashion. The standard deadline middleware reads the deadline field and creates a deadline feature to communicate this deadline to downstream middleware diff --git a/content/icerpc/duplex-transport.md b/content/icerpc/duplex-transport.md index aba6e3b1..4290124a 100644 --- a/content/icerpc/duplex-transport.md +++ b/content/icerpc/duplex-transport.md @@ -41,10 +41,10 @@ See also [Security with TLS][security-with-tls] for additional information. The C# duplex transport abstraction is composed of a number of interfaces that a custom transport needs to implement: -- [IDuplexClientTransport]: a factory to create outgoing connections -- [IDuplexServerTransport]: a factory to create listeners -- [IListener]: a factory to listen for and create incoming connections -- [IDuplexConnection]: a connection to allow a client and server to communicate +- [`IDuplexClientTransport`]: a factory to create outgoing connections +- [`IDuplexServerTransport`]: a factory to create listeners +- [`IListener`]: a factory to listen for and create incoming connections +- [`IDuplexConnection`]: a connection to allow a client and server to communicate The API documentation of these interfaces specifies the contract a custom transport needs to comply with. @@ -60,10 +60,10 @@ To use a custom transport, the application needs to provide an instance of `IDup [flow-control]: https://en.wikipedia.org/wiki/Flow_control_(data) [ice-protocol]: protocols-and-transports/ice-duplex-transports -[IDuplexClientTransport]: csharp:IceRpc.Transports.IDuplexClientTransport -[IDuplexServerTransport]: csharp:IceRpc.Transports.IDuplexServerTransport -[IListener]: csharp:IceRpc.Transports.IListener-1 -[IDuplexConnection]: csharp:IceRpc.Transports.IDuplexConnection +[`IDuplexClientTransport`]: csharp:IceRpc.Transports.IDuplexClientTransport +[`IDuplexServerTransport`]: csharp:IceRpc.Transports.IDuplexServerTransport +[`IListener`]: csharp:IceRpc.Transports.IListener-1 +[`IDuplexConnection`]: csharp:IceRpc.Transports.IDuplexConnection [Server]: csharp:IceRpc.Server [ConnectionCache]: csharp:IceRpc.ConnectionCache [ClientConnection]: csharp:IceRpc.ClientConnection diff --git a/content/icerpc/ice-protocol/protocol-frames.md b/content/icerpc/ice-protocol/protocol-frames.md index 5b843abd..15a07afe 100644 --- a/content/icerpc/ice-protocol/protocol-frames.md +++ b/content/icerpc/ice-protocol/protocol-frames.md @@ -216,4 +216,4 @@ set to 1.1. [protocol-and-encoding]: https://doc.zeroc.com/ice/3.7/ice-protocol-and-encoding [Slice]: /slice1 [status-code]: ../invocation/incoming-response#status-code -[request-fields]: ../invocation/outgoing-request#request-fields \ No newline at end of file +[request-fields]: ../invocation/outgoing-request#request-field diff --git a/content/icerpc/invocation/outgoing-request.md b/content/icerpc/invocation/outgoing-request.md index 873a7351..481a4485 100644 --- a/content/icerpc/invocation/outgoing-request.md +++ b/content/icerpc/invocation/outgoing-request.md @@ -9,6 +9,7 @@ In order to make an RPC, you construct an outgoing request and then pass this re method of an [invoker](invocation-pipeline#the-invoker-abstraction). An outgoing request carries all the information an invoker needs to send a request: + - the [service address](service-address) of the target service - the name of the operation to call on this service - request [fields](#request-fields) diff --git a/content/icerpc/multiplexed-transport.md b/content/icerpc/multiplexed-transport.md index 50efd4d1..2ce65795 100644 --- a/content/icerpc/multiplexed-transport.md +++ b/content/icerpc/multiplexed-transport.md @@ -42,11 +42,11 @@ See also [Security with TLS][security-with-tls] for additional information. The C# multiplexed transport abstraction consists of a number of interfaces that a custom transport needs to implement: -- [IMultiplexedClientTransport]: a factory to create outgoing connections -- [IMultiplexedServerTransport]: a factory to create listeners -- [IListener]: a factory to listen for and create incoming connections -- [IMultiplexedConnection]: a connection to accept and create streams -- [IMultiplexedStream]: a stream to allow a client and server to communicate +- [`IMultiplexedClientTransport`]: a factory to create outgoing connections +- [`IMultiplexedServerTransport`]: a factory to create listeners +- [`IListener`]: a factory to listen for and create incoming connections +- [`IMultiplexedConnection`]: a connection to accept and create streams +- [`IMultiplexedStream`]: a stream to allow a client and server to communicate The API documentation of these interfaces specifies the contract a custom transport needs to comply with. @@ -62,11 +62,11 @@ To use a custom transport, the application needs to provide an instance of `IMul [full-duplex]: https://en.wikipedia.org/wiki/Duplex_(telecommunications)#Full_duplex [flow-control]: https://en.wikipedia.org/wiki/Flow_control_(data) -[IMultiplexedClientTransport]: csharp:IceRpc.Transports.IMultiplexedClientTransport -[IMultiplexedServerTransport]: csharp:IceRpc.Transports.IMultiplexedServerTransport -[IListener]: csharp:IceRpc.Transports.IListener-1 -[IMultiplexedConnection]: csharp:IceRpc.Transports.IMultiplexedConnection -[IMultiplexedStream]: csharp:IceRpc.Transports.IMultiplexedStream +[`IMultiplexedClientTransport`]: csharp:IceRpc.Transports.IMultiplexedClientTransport +[`IMultiplexedServerTransport`]: csharp:IceRpc.Transports.IMultiplexedServerTransport +[`IListener`]: csharp:IceRpc.Transports.IListener-1 +[`IMultiplexedConnection`]: csharp:IceRpc.Transports.IMultiplexedConnection +[`IMultiplexedStream`]: csharp:IceRpc.Transports.IMultiplexedStream [Server]: csharp:IceRpc.Server [ConnectionCache]: csharp:IceRpc.ConnectionCache [ClientConnection]: csharp:IceRpc.ClientConnection diff --git a/content/icerpc/slic-transport/protocol-frames.md b/content/icerpc/slic-transport/protocol-frames.md index c20db993..48787262 100644 --- a/content/icerpc/slic-transport/protocol-frames.md +++ b/content/icerpc/slic-transport/protocol-frames.md @@ -12,10 +12,12 @@ Frames and types from this page are defined using [Slice]. All the frames have a header and a body. The header layout is common to all Slic versions and is composed of the following fields: + - a frame type defined as an `uint8` enumeration - a frame size defined as a `varuint62` representing the size of the frame body. The frame type is defined as follows: + ```slice enum FrameType : uint8 { Initialize = 1 diff --git a/content/icerpc/slic-transport/streams.md b/content/icerpc/slic-transport/streams.md index 3c872d07..9c711f51 100644 --- a/content/icerpc/slic-transport/streams.md +++ b/content/icerpc/slic-transport/streams.md @@ -78,6 +78,7 @@ Reducing the maximum stream frame size reduces this delay. It's in particular us A stream has two separate state machines: one for its write-side and one for its read-side. The state machines also depend on the type of the stream. The type of a stream is defined as follows: + - a local stream is a stream created by the application - a remote stream is a stream accepted by the application @@ -183,5 +184,4 @@ peer that its done reading. [StreamLast]: protocol-frames#stream-and-streamlast-frames [StreamReadsClosed]: protocol-frames#streamreadsclosed-and-streamwritesclosed-frames [StreamWritesClosed]: protocol-frames#streamreadsclosed-and-streamwritesclosed-frames -[StreamWindowUpdate]: protocol-frames#streamwindowupdate-frame [stream-concurrency]: flow-control#stream-concurrency diff --git a/content/slice/encoding/constructed-types.md b/content/slice/encoding/constructed-types.md index 375a7b8c..8c9546bc 100644 --- a/content/slice/encoding/constructed-types.md +++ b/content/slice/encoding/constructed-types.md @@ -45,12 +45,13 @@ compact enum StringInt32Result { {% /slice2 %} {% slice1 %} + ## Sequence A sequence of N elements of type T is encoded as a [variable-length size][slice1-var-size] N followed by each element encoded in order. -#### Example: empty sequence +### Example: empty sequence An empty sequence is encoded as: @@ -58,7 +59,7 @@ An empty sequence is encoded as: 0x00: size 0 ``` -#### Example: sequence of int32 +### Example: sequence of int32 A sequence of `int32` with values 5, 32 and 9 is encoded as: @@ -68,15 +69,17 @@ A sequence of `int32` with values 5, 32 and 9 is encoded as: 0x20 0x00 0x00 0x00: 32 over 4 bytes in little-endian order 0x09 0x00 0x00 0x00: 9 over 4 bytes in little-endian order ``` + {% /slice1 %} {% slice2 %} + ## Sequence with a non-optional element type A sequence of N elements with a non-optional element type T is encoded as a `varuint62`-encoded N followed by each element encoded in order. -#### Example: empty sequence +### Example: empty sequence An empty sequence is encoded as: @@ -84,7 +87,7 @@ An empty sequence is encoded as: 0x00: size 0 ``` -#### Example: sequence of int32 +### Example: sequence of int32 A sequence of `int32` with values 5, 32 and 9 is encoded as: @@ -100,7 +103,7 @@ A sequence of `int32` with values 5, 32 and 9 is encoded as: A sequence of N elements with a optional element type T? is encoded as a varuint62-encoded N followed by a [bit sequence][bit-sequence] with N bits, followed by each element with a value encoded in order. -#### Example: sequence of int32? +### Example: sequence of int32? A sequence of `int32?` with values 5, no-value, 9 and no-value is encoded as: diff --git a/content/slice/encoding/operation.md b/content/slice/encoding/operation.md index 53f607c0..b523c4c0 100644 --- a/content/slice/encoding/operation.md +++ b/content/slice/encoding/operation.md @@ -20,6 +20,7 @@ Unlike the encoding of tagged fields in classes, the encoding of tagged argument {% /slice1 %} {% slice2 %} + ## Non-stream encoding The arguments of an operation are encoded as a [segment]. The body of this segment corresponds to a virtual [struct] diff --git a/content/slice/encoding/primitive-types.md b/content/slice/encoding/primitive-types.md index d1245d22..40e9f423 100644 --- a/content/slice/encoding/primitive-types.md +++ b/content/slice/encoding/primitive-types.md @@ -4,6 +4,7 @@ description: Learn how primitive types are encoded with Slice. --- {% slice1 %} + ## AnyClass `AnyClass` is an abstract type. When you encode or decode a parameter or field with type `AnyClass`, you are encoding @@ -15,6 +16,7 @@ or decoding a concrete class instance using the [class encoding/decoding rules]( A `bool` is encoded on a single byte, where 0 means `false` and 1 means `true`. Other values are invalid. {% slice2 %} + ## Fixed-size integral types | Type | Encoded on N bytes | diff --git a/content/slice/language-guide/class-types.md b/content/slice/language-guide/class-types.md index edf8f629..886e44bb 100644 --- a/content/slice/language-guide/class-types.md +++ b/content/slice/language-guide/class-types.md @@ -8,18 +8,20 @@ Classes are not supported with Slice2. {% /slice2 %} {% slice1 %} + ## Super structs A class is a user-defined type that holds a list of fields, just like a [struct](struct-types). Classes also offer capabilities not offered by structs: - - extensibility\ - you can extend a class through inheritance and tagged fields - - graph preservation\ - you can transmit a graph of class instances through a Slice operation - - null/not-set value\ - a class parameter or field can be null or not-set, whereas in general a struct parameter or field must have a value - - slicing\ - a recipient can decode a class instance into a base class by slicing off derived "slices" it does not know + +- extensibility\ + you can extend a class through inheritance and tagged fields +- graph preservation\ + you can transmit a graph of class instances through a Slice operation +- null/not-set value\ + a class parameter or field can be null or not-set, whereas in general a struct parameter or field must have a value +- slicing\ + a recipient can decode a class instance into a base class by slicing off derived "slices" it does not know We will review each of these capabilities below. @@ -204,6 +206,7 @@ derives from [SliceClass], the base class for all C# Slice classes. For example: {% aside alignment="top" %} + ```slice class CarPart { id: string @@ -231,6 +234,7 @@ public partial class CarPart : SliceClass } ``` + {% /aside %} The mapped class has a primary constructor which sets all the fields. If any field has an optional type, the mapped @@ -239,6 +243,7 @@ class has a second constructor with a parameter for each non-nullable C# field. Slice class inheritance maps the C# class inheritance as you would expect: {% aside alignment="top" %} + ```slice class FrontBumper : CarPart { color: Color @@ -266,6 +271,7 @@ public partial class RearBumper : CarPart } } ``` + {% /aside %} {% /slice1 %} diff --git a/content/slice/language-guide/comments.md b/content/slice/language-guide/comments.md index 8cdf865e..be9b0fe8 100644 --- a/content/slice/language-guide/comments.md +++ b/content/slice/language-guide/comments.md @@ -31,27 +31,32 @@ Slice doc comments can be attached to all Slice elements except parameters, modu Slice doc comments support the following tags: {% slice1 %} + | Tag | Applies to | Description | |---------------------------|------------|--------------------------------------------------------------------| | `{@link identifier}` | All | Provide a link to the Slice type, operation or field `identifier`. | | `@param name: ...` | Operations | Describe the operation parameter `name`. | | `@returns name: ...` | Operations | Describe the return parameter `name`. | | `@see identifier` | All | Suggest to see Slice type, operation or field `identifier`. | -| `@throws exception: ... ` | Operations | Describe when the operation throws Slice exception `exception`. | +| `@throws exception: ...` | Operations | Describe when the operation throws Slice exception `exception`. | + {% /slice1 %} {% slice2 %} + | Tag | Applies to | Description | |----------------------|------------|--------------------------------------------------------------------| | `{@link identifier}` | All | Provide a link to the Slice type, operation or field `identifier`. | | `@param name: ...` | Operations | Describe the operation parameter `name`. | | `@returns name: ...` | Operations | Describe the return parameter `name`. | | `@see identifier` | All | Suggest to see Slice type, operation or field `identifier`. | + {% /slice2 %} ## Example {% slice1 %} + ```slice {% addMode=true %} module Example @@ -74,9 +79,11 @@ interface WidgetFactory { getLastWidget() -> (proxy: Widget, timeStamp: TimeStamp) throws WidgetException } ``` + {% /slice1 %} {% slice2 %} + ```slice module Example @@ -95,4 +102,5 @@ interface WidgetFactory { getLastWidget() -> (proxy: Widget, timeStamp: WellKnownTypes::TimeStamp) } ``` + {% /slice2 %} diff --git a/content/slice/language-guide/enum-types.md b/content/slice/language-guide/enum-types.md index 4e506ea2..e111bac2 100644 --- a/content/slice/language-guide/enum-types.md +++ b/content/slice/language-guide/enum-types.md @@ -138,21 +138,25 @@ matching enumerator. You can also get the opposite behavior—unchecked—by prepending `unchecked` to your enumeration definition. For example: {% slice1 %} + ```slice unchecked enum ErrorCode { NotFound NotAuthorized } ``` + {% /slice1 %} {% slice2 %} + ```slice unchecked enum ErrorCode : varuint62 { NotFound NotAuthorized } ``` + {% /slice2 %} Since `ErrorCode` is marked unchecked, the generated code will successfully decode an integral value without a matching @@ -162,20 +166,25 @@ A checked enumeration must have at least one enumerator, while an unchecked enum For example, the following enumeration is valid: {% slice1 %} + ```slice // Range: 0 to int32 max unchecked enum MyPositiveInteger {} ``` + {% /slice1 %} {% slice2 %} + ```slice // Same range as int16 unchecked enum MyInt16 : int16 {} ``` + {% /slice2 %} {% slice2 %} + ### Unchecked enum with fields When Slice decodes an enum with fields and receives an unknown enumerator, it returns a special enumerator that holds @@ -211,6 +220,7 @@ public enum Fruit : int Orange = 2 } ``` + {% /aside %} The underlying type of the mapped enumeration is always `int`. @@ -218,7 +228,7 @@ The underlying type of the mapped enumeration is always `int`. {% slice2 %} -### Enum with underlying type in C# +### Enum with underlying type in C\# An enum with underlying type maps to a public C# enumeration with the same name, and each Slice enumerator maps to a C# enumerator with the same name. For example: @@ -237,12 +247,13 @@ public enum Fruit : uint8 Orange = 2 } ``` + {% /aside %} The underlying type of the mapped enumeration is always the mapped type for the Slice underlying type. For example, a Slice `uint8` corresponds to a C# `byte`. -### Enum with fields in C# +### Enum with fields in C\# C# does not provide a native discriminated union type. This mapping relies on an emulation based on record classes [proposed a few years ago]. Briefly, a Slice enum with fields maps to a C# partial record class with the same name, and diff --git a/content/slice/language-guide/exception.md b/content/slice/language-guide/exception.md index 9f8b990e..dd87406e 100644 --- a/content/slice/language-guide/exception.md +++ b/content/slice/language-guide/exception.md @@ -8,9 +8,11 @@ Exceptions are not supported with Slice2. {% /slice2 %} {% slice1 %} + ## Operation failure The implementation of a Slice [operation] can: + - succeed and return an instance of the operation's return type, - fail and return a generic error, or - fail and return an exception defined in Slice @@ -21,6 +23,7 @@ In this last case, the exception or one of its base exceptions must be listed in Other than the `exception` keyword, the definition of an exception is syntactically identical to the definition of a [class](class-types). For example: {% aside alignment="top" %} + ```slice class BaseError { errorCode: int32 @@ -40,6 +43,7 @@ exception DerivedException : BaseException { measurement: float64 } ``` + {% /aside %} {% callout type="note" %} @@ -63,6 +67,7 @@ the mapped class derives from [SliceException], the base class for all C# Slice For example: {% aside alignment="top" %} + ```slice exception TranslationException { errorCode: TranslationErrorCode @@ -89,6 +94,7 @@ public partial class TranslationException } } ``` + {% /aside %} The mapped C# class provides a primary constructor with parameters for all its fields, plus an optional message and an @@ -97,6 +103,7 @@ optional inner exception (like most exceptions in C#). Slice exception inheritance maps to C# class inheritance: {% aside alignment="top" %} + ```slice exception BaseException { errorCode: int32 @@ -139,6 +146,7 @@ public partial class DerivedException : BaseException } } ``` + {% /aside %} ### ConvertToInternalError diff --git a/content/slice/language-guide/fields.md b/content/slice/language-guide/fields.md index c42abd9e..cba92cb8 100644 --- a/content/slice/language-guide/fields.md +++ b/content/slice/language-guide/fields.md @@ -35,6 +35,7 @@ This special "not set" value corresponds to null in C#, `std::nullopt` in C++, n For example: {% slice1 %} + ```slice mode = Slice1 @@ -53,6 +54,7 @@ Leaving tagged fields aside, only a few field types can be marked optional with {% /slice1 %} {% slice2 %} + ```slice struct Person { name: string @@ -75,6 +77,7 @@ A field can have a tag before its name, which makes this field a "tagged field". followed by a tag number in parenthesis. For example: {% slice1 %} + ```slice mode = Slice1 @@ -83,14 +86,17 @@ class Person { tag(1) favoriteFood: Food? // tagged field } ``` + {% /slice1 %} {% slice2 %} + ```slice struct Person { name: string tag(1) favoriteFood: Food? // tagged field } ``` + {% /slice2 %} Tagged fields allow you to change your Slice definitions while maintaining on-the-wire compatibility with applications @@ -117,8 +123,10 @@ class Contact { tag(1) name: string? } ``` + {% /slice1 %} {% slice2 %} + ```slice struct Person { tag(1) name: string? @@ -128,6 +136,7 @@ struct Contact { tag(1) name: string? } ``` + {% /slice2 %} ### Tag sorting @@ -137,6 +146,7 @@ You don't need to sort tagged fields by tag number. For instance, the `Person` b list: {% slice1 %} + ```slice class Person { tag(5) emailAddress: string? @@ -144,8 +154,10 @@ class Person { tag(1) favoriteFood: Food? } ``` + {% /slice1 %} {% slice2 %} + ```slice struct Person { tag(5) emailAddress: string? @@ -153,6 +165,7 @@ struct Person { tag(1) favoriteFood: Food? } ``` + {% /slice2 %} ### Tag semantics @@ -177,6 +190,6 @@ field is the mapped C# type for `Type`. Tagged fields are mapped just like regular fields. The tag and tag number don't appear in the mapped C# API. -### Optional type in C# +### Optional type in C\# Optional types are mapped to nullable C# types. For example, `int32?` is mapped to `int?` in C#. diff --git a/content/slice/language-guide/parameters.md b/content/slice/language-guide/parameters.md index 21322891..473c5f3c 100644 --- a/content/slice/language-guide/parameters.md +++ b/content/slice/language-guide/parameters.md @@ -81,7 +81,8 @@ case. The type of the C# field is the mapped C# type for `Type`. Tagged parameters are mapped just like regular parameters. The tag and tag number don't appear in the mapped C# API. {% slice2 %} -### Stream parameters in C# + +### Stream parameters in C\# A stream parameter of type `uint8` is mapped to a [PipeReader]. For example: diff --git a/content/slice/language-guide/preprocessor-directives.md b/content/slice/language-guide/preprocessor-directives.md index 551d3c8f..c230f11e 100644 --- a/content/slice/language-guide/preprocessor-directives.md +++ b/content/slice/language-guide/preprocessor-directives.md @@ -62,6 +62,7 @@ Indentation is not required when nesting directives, but is recommended to impro The `#if` and `#elif` directives require a boolean expression that the preprocessor evaluates. These expressions consist of symbols (which evaluate to `true` or `false`) and the following boolean operators: + - `!` - Logical NOT - `&&` - Logical AND - `||` - Logical OR diff --git a/content/slice/language-guide/primitive-types.md b/content/slice/language-guide/primitive-types.md index db1d9614..6ec5e828 100644 --- a/content/slice/language-guide/primitive-types.md +++ b/content/slice/language-guide/primitive-types.md @@ -40,6 +40,7 @@ Slice provides 8 fixed-size integral types. Types that start with a `u` are unsi | uint32 | 0 to 4,294,967,295 | uint | | int64 | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | long | | uint64 | 0 to 18,446,744,073,709,551,615 | ulong | + {% /slice2 %} ## Floating-point types @@ -63,6 +64,7 @@ Slice provides 4 integral types. | int16 | -32,768 to 32,767 | short | | int32 | -2,147,483,648 to 2,147,483,647 | int | | int64 | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | long | + {% /slice1 %} ## String diff --git a/content/slice/language-guide/struct-types.md b/content/slice/language-guide/struct-types.md index 2a5de332..f8daa780 100644 --- a/content/slice/language-guide/struct-types.md +++ b/content/slice/language-guide/struct-types.md @@ -8,6 +8,7 @@ description: Learn how to define and use structs in Slice. A struct is a user-defined type that holds a list of [fields](fields). For example: {% slice1 %} + ```slice enum StateAbbreviation { AL, AK, AZ, AR, AS ... WY } @@ -27,6 +28,7 @@ All structs must be marked "compact" with Slice1. A compact struct cannot hold a {% /slice1 %} {% slice2 %} + ```slice enum StateAbbreviation : uint8 { AL, AK, AZ, AR, AS ... WY } @@ -65,6 +67,7 @@ A Slice struct maps to a public C# record struct with the same name. For example {% slice1 %} {% aside alignment="top" %} + ```slice compact struct PostalAddress { recipientFullName: string @@ -112,11 +115,13 @@ public partial record struct PostalAddress } } ``` + {% /aside %} {% /slice1 %} {% slice2 %} {% aside alignment="top" %} + ```slice struct PostalAddress { recipientFullName: string @@ -167,6 +172,7 @@ public partial record struct PostalAddress } } ``` + {% /aside %} {% /slice2 %} @@ -180,10 +186,12 @@ You can map a Slice struct to a readonly C# struct with the `cs::readonly` [attr not accept any argument. For example: {% aside alignment="top" %} + ```slice [cs::readonly] compact struct Point { x: int32, y: int32 } ``` + ```csharp public readonly partial record struct Point { @@ -194,6 +202,7 @@ public readonly partial record struct Point ... } ``` + {% /aside %} You can also apply `cs::readonly` to a struct field to map this field to a read-only C# field. diff --git a/content/slice/language-reference/slice-grammar.md b/content/slice/language-reference/slice-grammar.md index c4a819e4..9b97540c 100644 --- a/content/slice/language-reference/slice-grammar.md +++ b/content/slice/language-reference/slice-grammar.md @@ -128,6 +128,7 @@ Dictionaries require two type parameters: the _key_ and _value_ types. There is no restriction on the element and value types, but since dictionary keys must be comparable, key types must be one of the following: + - `bool` - `string` - integral types (`int8`, `uint8`, `int16`, `uint16`, `int32`, `uint32`, `varint32`, `varuint32`, `int64`, `uint64`, @@ -150,6 +151,7 @@ Dictionary ``` For example: + ```slice Sequence Dictionary @@ -183,6 +185,7 @@ A [compact struct][compact-struct-guide] cannot contain [tagged fields][tag]. For additional information on structs, see the [struct][struct-guide] page. {% slice1 %} + ### Class types Classes can only be defined or referenced in [`Slice1`][compilation-mode-guide] mode. @@ -211,6 +214,7 @@ For additional information on classes, see the [class][class-guide] page. {% /slice1 %} {% slice1 %} + ### Exceptions Exceptions can only be defined or referenced in [`Slice1`][compilation-mode-guide] mode. @@ -336,6 +340,7 @@ ExceptionSpecification | "throws" "(" NonEmptyCommaList ")" ; ``` + {% /slice1 %} For additional information on operations, see the [operation][operation-guide] page. @@ -414,6 +419,7 @@ Enumerator ``` If an enumerator's value isn't explicitly assigned, it is given an implicit value according to the following rules: + - If this is the first enumerator in an enum, it is assigned an implicit value of `0`. - Otherwise, it is assigned an implicit value equal to the previous enumerator's value `+ 1`. @@ -485,6 +491,7 @@ Tags can only be applied to [fields][field] and [parameters][parameter] with an {% slice1 %} Tags can only be applied to [fields][field] and [parameters][parameter], and only if the type of that field/parameter: + - is optional (it ends with a `?` symbol) - is not a class, and does not use classes internally {% /slice1 %} @@ -498,6 +505,7 @@ Tag ### Identifiers Slice supports three forms of identifiers: + - **unscoped** identifiers consist of a letter, followed by any number of letters, digits, or underscores. - **relatively scoped** identifiers consist of one or more unscoped identifiers separated by `::` tokens. - **globally scoped** identifiers consist of a `::` token, followed by a relatively scoped identifier. @@ -550,6 +558,7 @@ struct // The struct keyword ### Integer literals Slice supports three forms of integer literals: + - A decimal literal for base-10 numbers. These consist of one or more digits between `0` and `9` (inclusive). - A hexadecimal literal for base-16 numbers. @@ -940,7 +949,6 @@ UndelimitedList ; ``` -[slice-file]: #slice-files [mode-statement]: #mode-statements [module-declaration]: #module-declarations [primitive]: #primitive-types