docs: rewrite reference and clarify interface abstraction
This commit is contained in:
@@ -2,15 +2,15 @@
|
||||
|
||||
## Status
|
||||
|
||||
この文書は、WIP HostをRustで実装するための概念的なAPI modelを整理するdraftである。
|
||||
WIP HostをRustで実装する際、Interfaceの宣言とObjectの実装をどう組み合わせて公開するか。このdraftは、そのための概念的なAPI modelを提案する。
|
||||
|
||||
このdraftで示すtrait名、attribute、derive、generated type名、method signatureは説明用であり、具体的なRust API syntaxとして確定しない。Ownership、lifetime、async runtime、error type、macro crate構成も未決定である。
|
||||
Trait名、attribute、derive、generated type名、method signatureは説明用であり、具体的なRust API syntaxは確定していない。Ownership、lifetime、async runtime、error type、macro crate構成も未決定である。
|
||||
|
||||
Protocol上の確定事項は[Core Model](../2-core-model.md)、[Object tree / Schema](../2.1-object-tree-schema.md)、[Operation and Interface](../2.2-operation-and-interface.md)、[Protocol](../3-protocol.md)を参照する。動的なObject projectionの運用要件は[Dynamic Worldspace Projection](dynamic-worldspace-projection.md)、対応するTypeScript modelは[TypeScript API Model](typescript-api-model.md)を参照する。
|
||||
Protocol上の確定事項は[Core Model](../2-core-model.md)、[Object tree / Schema](../2.1-object-tree-schema.md)、[Operation and Interface](../2.2-operation-and-interface.md)、[Protocol](../3-protocol.md)に従う。動的なObject projectionの運用要件は[Dynamic Worldspace Projection](dynamic-worldspace-projection.md)、対応するTypeScript modelは[TypeScript API Model](typescript-api-model.md)を参照する。
|
||||
|
||||
## 目的
|
||||
|
||||
Rust APIでは、次のmodelを自然に表現できるようにする。
|
||||
Rust APIでは、Interfaceをtraitで宣言し、structで実装するmodelを自然に表現できるようにする。ただし、structが実装しているInterfaceと、ある時点で公開するInterfaceは分けて選べるようにする。
|
||||
|
||||
1. Rust traitでWIP Interfaceを宣言する。
|
||||
2. Rust structが、Protocol Objectとして公開するmetadataを提供する。
|
||||
@@ -19,13 +19,13 @@ Rust APIでは、次のmodelを自然に表現できるようにする。
|
||||
5. Trait declarationからInterface Descriptor、Value codec、validation、Operation dispatchに必要なcodeを生成する。
|
||||
6. Struct instanceをWorldspace全体について常駐させず、`observe`と`call_operation`の解決時にdata-drivenに生成できる。
|
||||
|
||||
このmodelでは、Protocol上のObjectとInterfaceの関連付けは`Object.interfaces`だけで表す。Operation implementationへ到達するためのRust内部codeはSDK / Host Runtimeの実装詳細であり、新しいProtocol conceptを導入しない。
|
||||
Protocol上でObjectとInterfaceを関連付けるのは`Object.interfaces`だけである。Operation implementationを呼び出すためのRust内部codeはSDK / Host Runtimeの実装詳細として扱い、新しいProtocol conceptは導入しない。
|
||||
|
||||
## Conceptual model
|
||||
|
||||
### Interface trait
|
||||
|
||||
WIP InterfaceはRust traitとして宣言する。
|
||||
WIP Interfaceは、Rust traitとして宣言する。
|
||||
|
||||
```rust
|
||||
#[wip::interface]
|
||||
@@ -47,9 +47,9 @@ trait FileInterface {
|
||||
}
|
||||
```
|
||||
|
||||
このcodeはconceptual syntaxである。`Option<i64>`の対応範囲、`Bytes` wrapper、documentationの取得方法、async methodとerrorの具体形は別途決定する。
|
||||
このcodeはconceptual syntaxであり、具体的なAPIとして確定したものではない。`Option<i64>`の対応範囲、`Bytes` wrapper、documentationの取得方法、async methodとerrorの具体形は別途決定する。
|
||||
|
||||
Trait declarationは、次のlogical declarationに対応する。
|
||||
Trait declarationとProtocol上の宣言は、次のように対応付ける。
|
||||
|
||||
- 一つのtrait declarationを、一つのInterface Descriptorを生成するRust側definitionとして扱う。
|
||||
- Trait名はgenerated Rust itemやlocal registrationを識別するために使用できるが、Protocol `InterfaceDescriptor`のfieldや構造化されたInterface参照としてそのまま公開しない。
|
||||
@@ -60,11 +60,11 @@ Trait declarationは、次のlogical declarationに対応する。
|
||||
- Rust typeをDescriptorの`TypeExpr`とProtocol `Value`へ対応付ける。
|
||||
- Documentationをtrait、method、parameter、return、関連typeから取得できるようにする。
|
||||
|
||||
Descriptorのshapeはtrait declarationによって決まり、各structのtrait implementationによって変化しない。
|
||||
したがって、Descriptorのshapeを決めるのはtrait declarationである。各structがそのtraitをどう実装するかによって、Descriptorは変化しない。
|
||||
|
||||
### Object implementation
|
||||
|
||||
Rust structは、その時点でWorldspaceへ投影するObjectをHost内部で表現できる。
|
||||
その時点でWorldspaceへ投影するObjectは、Host内部ではRust structとして表現できる。
|
||||
|
||||
```rust
|
||||
struct File {
|
||||
@@ -75,7 +75,7 @@ struct File {
|
||||
}
|
||||
```
|
||||
|
||||
Structは概念上の`WipObject` traitを実装する。
|
||||
公開metadataを提供するために、structが概念上の`WipObject` traitを実装する形を想定する。
|
||||
|
||||
```rust
|
||||
impl WipObject for File {
|
||||
@@ -97,20 +97,20 @@ impl WipObject for File {
|
||||
}
|
||||
```
|
||||
|
||||
`WipObject`が返す値のownershipやborrow形式は未決定である。概念的にはProtocol Objectのうち、publication時に選択するInterface集合以外の公開metadataを提供する。
|
||||
`WipObject`は、Protocol Objectの公開metadataのうち、publication時に選ぶInterface集合以外を提供する。返す値のownershipやborrow形式は未決定である。
|
||||
|
||||
`WipObject`がProtocol metadataとして返す値へ次を含めない。これらをimplementing structのprivate fieldとして保持することは禁止しない。
|
||||
Structが保持する情報のすべてを公開metadataにするわけではない。次の情報は`WipObject`がProtocol metadataとして返す値に含めないが、implementing structのprivate fieldとして保持してよい。
|
||||
|
||||
- Absolute path。PathはObjectのfieldではなく、Worldspace resolutionのcontextである。
|
||||
- Children。ChildrenはTree上の配置contextである。
|
||||
- 固定されたInterface集合。InterfaceはObjectを公開する時点で追加する。
|
||||
- Backend connection、file descriptor、credential等のHost-private state。
|
||||
|
||||
Structが保持する`path`やbackend handle等はHost内部のOperation implementationに使用できるが、`WipObject`のmetadataまたはProtocol Objectへ自動的にserializeしない。
|
||||
たとえば、structの`path`やbackend handleはHost内部のOperation implementationで使用できる。ただし、`WipObject`のmetadataやProtocol Objectへ自動的にserializeする対象にはしない。
|
||||
|
||||
### Interface implementation
|
||||
|
||||
Object implementationとして使用するstructは、公開したいInterface traitを実装する。
|
||||
Object implementationに使うstructは、公開したいInterface traitを実装する。
|
||||
|
||||
```rust
|
||||
impl FileInterface for File {
|
||||
@@ -131,15 +131,15 @@ impl FileInterface for File {
|
||||
}
|
||||
```
|
||||
|
||||
Trait implementationはOperationのbehaviorを提供する。Interface Descriptorはtrait implementationから生成せず、Interface trait declarationから生成する。
|
||||
Trait implementationが提供するのはOperationのbehaviorである。Interface Descriptorの生成元は、このimplementationではなくInterface trait declarationとする。
|
||||
|
||||
Rustには、あるtypeが実装しているtraitを列挙する一般的なreflectionがない。また、一つのstructが複数のInterface traitを実装し得る。そのため、trait implementationが存在するだけでInterfaceを暗黙に公開しない。
|
||||
また、traitを実装しただけでInterfaceを公開することにはしない。Rustには、あるtypeが実装しているtraitを列挙する一般的なreflectionがなく、一つのstructが複数のInterface traitを実装することもあるためである。
|
||||
|
||||
### Object publication
|
||||
|
||||
ObjectをWorldspaceへ返す時点で、struct instanceと公開する0個以上のInterface Declarationを明示的に組み合わせる。Interfaceは追加順を保持するordered setであり、同じDefinitionを重複して追加しない。
|
||||
ObjectをWorldspaceへ返す時点で、struct instanceと、公開する0個以上のInterface Declarationを明示的に組み合わせる。Interfaceは追加順を保持するordered setとし、同じDefinitionの重複追加は認めない。
|
||||
|
||||
Conceptual syntaxは次のようになる。
|
||||
次のconceptual syntaxでは、解決した`File`に公開するInterfaceを追加している。
|
||||
|
||||
```rust
|
||||
let file = File::resolve(path).await?;
|
||||
@@ -147,9 +147,9 @@ let object = PublishedObject::new(file)
|
||||
.expose(FileInterfaceDefinition);
|
||||
```
|
||||
|
||||
ここで各`InterfaceDefinition`は、`#[wip::interface]`が生成するconceptualなcompanion definitionである。実際の名前や、associated item、module、valueのどの形で生成するかは未決定である。
|
||||
各`InterfaceDefinition`は、`#[wip::interface]`が生成するconceptualなcompanion definitionを表す。実際の名前も、associated item、module、valueのどの形で生成するかも未決定である。
|
||||
|
||||
Publication APIは、追加する各Definitionについて概念的に次のboundを要求する。
|
||||
Publication APIが各Definitionの追加に要求するboundは、概念的には次の形になる。
|
||||
|
||||
```rust
|
||||
impl<T: WipObject> PublishedObject<T> {
|
||||
@@ -165,9 +165,9 @@ impl<T: FileInterface> InterfaceDefinition<T>
|
||||
}
|
||||
```
|
||||
|
||||
このboundにより、Objectへ追加する各Interfaceについて、公開する値がObject metadataとOperation implementationの両方を提供することをcompile timeに確認できる。どのInterfaceも追加しないObjectも表現できる。
|
||||
このboundで、公開する値がObject metadataを提供し、追加する各InterfaceのOperation implementationも提供することをcompile timeに確認できる。Interfaceを一つも追加しないObjectも表現できる。
|
||||
|
||||
`PublishedObject`はHost SDK内のconceptual typeであり、Protocol typeとして追加しない。Host Runtimeはこれを使用して次を構築する。
|
||||
`PublishedObject`はHost SDK内のconceptual typeであり、Protocol typeには追加しない。Host Runtimeはこの値からProtocol Objectを構築する。
|
||||
|
||||
```rust
|
||||
Object {
|
||||
@@ -179,13 +179,15 @@ Object {
|
||||
}
|
||||
```
|
||||
|
||||
`selected_interface_references`は、Hostが各generated Interface Definitionを登録または公開するときに割り当てる構造化参照`{ scope, name }`を、publication APIへの追加順で並べたものである。同じ`(scope, name)`の重複は拒否し、Objectの配置pathに対する祖先制約も検証する。Macroが参照をcompile timeに固定することは要求しない。
|
||||
`selected_interface_references`には、Hostが各generated Interface Definitionの登録または公開時に割り当てる構造化参照`{ scope, name }`を、publication APIへの追加順で並べる。同じ`(scope, name)`の重複は拒否し、Objectの配置pathに対する祖先制約も検証する。Macroが参照をcompile timeに固定することは要求しない。
|
||||
|
||||
`observe`はDescriptor自体をObjectへ埋め込まず、このInterface参照のordered setだけを返す。Clientが各参照を`fetch_interface`したとき、Host Runtimeはtrait declarationから生成されたDescriptorと、存在する場合はInterface validatorを返す。同じ参照とvalidatorの組のDescriptorはHost上で共有およびcacheできるため、Object instanceごとにDescriptorを再生成または再送する必要はない。
|
||||
`observe`でObjectに含めるのは、Descriptor自体ではなく、このInterface参照のordered setだけである。Clientが各参照を`fetch_interface`すると、Host Runtimeはtrait declarationから生成したDescriptorと、存在する場合はInterface validatorを返す。
|
||||
|
||||
同じ参照とvalidatorの組に対応するDescriptorは、Host上で共有およびcacheできる。このため、Object instanceごとにDescriptorを再生成したり再送したりする必要はない。
|
||||
|
||||
## Macroが生成する責務
|
||||
|
||||
`#[wip::interface]`は、conceptualには次を生成または提供する。
|
||||
`#[wip::interface]`には、宣言からDescriptorを生成するだけでなく、Valueの変換・検証とdispatchに必要なcodeを提供する役割を想定する。
|
||||
|
||||
- Interface Descriptorを構築するdefinition。
|
||||
- Trait methodとOperation Declarationの対応情報。
|
||||
@@ -196,15 +198,13 @@ Object {
|
||||
- 任意の`T: WipObject + InterfaceTrait`について、そのInterfaceを`PublishedObject<T>`へ追加するための型付きentry point。
|
||||
- HostがInterface参照、optional validator、Descriptorを登録、取得、cacheするためのidentity。
|
||||
|
||||
MacroがRust codebase内のtrait implementationを探索または列挙することは要求しない。Publication時のgeneric boundによって、対象structがInterface traitを実装していることを確認する。
|
||||
対象structがInterface traitを実装しているかは、publication時のgeneric boundで確認する。MacroがRust codebase内のtrait implementationを探索したり列挙したりすることは要求しない。
|
||||
|
||||
Generated dispatch codeはRust SDK内部の実装詳細である。Host内部のdispatch mechanismやRust type名等をProtocolへ公開しない。
|
||||
Generated dispatch codeはRust SDK内部の実装詳細である。Host内部のdispatch mechanismやRust type名等はProtocolへ公開しない。
|
||||
|
||||
## Rust typeとProtocol type
|
||||
|
||||
Interface traitで使用できるRust typeは、Descriptorの`TypeExpr`とProtocol `Value`へ対応付けられなければならない。
|
||||
|
||||
Conceptualにはderiveまたは明示的なcodec implementationを使用する。
|
||||
Interface traitで使うRust typeには、Descriptorの`TypeExpr`とProtocol `Value`への対応付けが必要となる。概念的には、deriveまたは明示的なcodec implementationを使うことを想定する。
|
||||
|
||||
```rust
|
||||
#[derive(WipType)]
|
||||
@@ -221,7 +221,7 @@ enum ReadResult {
|
||||
}
|
||||
```
|
||||
|
||||
このsyntaxも未決定である。少なくとも次を表現できる必要がある。
|
||||
このsyntaxも未決定である。Typeの対応付けでは、少なくとも次を表現できる必要がある。
|
||||
|
||||
- Unit、Boolean、Integer、Number、String、Bytes、Json、Entry。
|
||||
- Record、List、Enum、Union。
|
||||
@@ -229,15 +229,15 @@ enum ReadResult {
|
||||
- Requiredとoptionalなfieldおよびparameter。
|
||||
- Documentation。
|
||||
|
||||
Rustの`Option<T>`をoptional field / parameter以外で許可するか、enumをProtocol EnumまたはUnionへどう対応付けるか、newtypeをどのように扱うかは未決定である。
|
||||
Rustの`Option<T>`をoptional field / parameter以外でも許可するかは、まだ決めていない。EnumをProtocol EnumまたはUnionへどう対応付けるか、newtypeをどう扱うかも未決定である。
|
||||
|
||||
Rust SDKは、integerのProtocol相互運用範囲、finite number、unknown field、Union shape、Entry path等をProtocol boundaryで検証しなければならない。
|
||||
型の対応付けとは別に、Protocol boundaryでの検証も必要となる。Rust SDKは、integerのProtocol相互運用範囲、finite number、unknown field、Union shape、Entry path等をそこで検証しなければならない。
|
||||
|
||||
## Dynamic Worldspaceでのlifecycle
|
||||
|
||||
### `observe`
|
||||
|
||||
Projection implementationはrequest時にbackend dataを解決し、struct instanceを生成する。
|
||||
Projection implementationはrequest時にbackend dataを解決し、その時点のstruct instanceを生成する。
|
||||
|
||||
```rust
|
||||
async fn resolve_file(path: &WipPath) -> Result<PublishedObject> {
|
||||
@@ -255,9 +255,9 @@ async fn resolve_file(path: &WipPath) -> Result<PublishedObject> {
|
||||
}
|
||||
```
|
||||
|
||||
Host Runtimeは`PublishedObject`からProtocol Objectを返す。Response生成後にこの`File` instanceを破棄してよく、Worldspace内の全fileに対応するinstanceを保持しない。
|
||||
Host Runtimeは`PublishedObject`からProtocol Objectを返す。Responseを生成した後は、この`File` instanceを破棄してよい。Worldspace内の全fileに対応するinstanceを保持する必要はない。
|
||||
|
||||
Requested depthが正の場合、Directory listingで発見した各entryについて、その時点のstruct instanceを生成して公開できる。Providerがdirectory全体を先に収集してから`Vec`として返すことは要求しないが、一つのparentのobservationを成功させるには公開されたindexable childrenをclean exhaustionまで列挙しなければならない。
|
||||
Requested depthが正の場合は、Directory listingで発見した各entryについて、その時点のstruct instanceを生成して公開できる。Providerがdirectory全体を先に収集し、`Vec`として返すことは要求しない。ただし、一つのparentのobservationを成功させるには、公開されたindexable childrenをclean exhaustionまで列挙する必要がある。
|
||||
|
||||
```rust
|
||||
let mut entries = filesystem.discover_children(path, budget).await?;
|
||||
@@ -274,7 +274,7 @@ while let Some(entry) = entries.next().await? {
|
||||
}
|
||||
```
|
||||
|
||||
`discover_children`、`budget`、`observation`はconceptualであり、具体APIではない。必要なsemanticsは次である。
|
||||
`discover_children`、`budget`、`observation`は具体APIではなく、conceptualな表記である。Childの発見と公開には、次のsemanticsを要求する。
|
||||
|
||||
- 各childを現在の主体についてprojectし、非公開Objectとそのsubtreeを返さない。
|
||||
- 公開されたindexable childrenをすべて列挙し、clean exhaustionで終了する。
|
||||
@@ -286,7 +286,7 @@ while let Some(entry) = entries.next().await? {
|
||||
|
||||
### `call_operation`
|
||||
|
||||
Hostはcall時に、requestのTargetと`InterfaceTarget`をHost Runtimeへ渡す。Runtimeは一つのatomic execution boundaryへ入ってから`target.path`を現在のObject implementationとstableなbackend対象へ解決する。
|
||||
Call時には現在のObjectを解決し直す。HostはrequestのTargetと`InterfaceTarget`をHost Runtimeへ渡し、Runtimeは一つのatomic execution boundaryに入ってから、`target.path`を現在のObject implementationとstableなbackend対象へ解決する。
|
||||
|
||||
```rust
|
||||
runtime.call_current(
|
||||
@@ -299,7 +299,7 @@ runtime.call_current(
|
||||
).await
|
||||
```
|
||||
|
||||
`resolve_current_projection`と`runtime.call_current`というAPIを採用することは決定しない。ResolverはRuntimeが開始したexecution boundary内で呼ばれ、返す値はそのboundary中にObject identityとbackend対象を安定して保持するhandleまたはtransaction contextを含む必要がある。このexampleが示す要件は次である。
|
||||
`resolve_current_projection`と`runtime.call_current`を実際のAPIとして採用するかは決めていない。ResolverはRuntimeが開始したexecution boundary内で呼ばれ、そのboundary中にObject identityとbackend対象を安定して保持するhandleまたはtransaction contextを含む値を返す必要がある。上のexampleは、次の要件を表す。
|
||||
|
||||
- 過去の`observe`で作成したstruct instanceを保持していなくてもOperationを実行できる。
|
||||
- Call時の現在の主体、Object visibility、Object metadata、Interface集合を同じProjection pathで再解決し、Objectが非公開なら`NotFound`を返す。
|
||||
@@ -315,15 +315,15 @@ runtime.call_current(
|
||||
- Macro-generated dispatchが、選択されたInterface traitのmethodを現在のstruct instanceに対して呼び出す。異なるInterfaceの同名Operationをmergeまたは曖昧に解決しない。
|
||||
- Operation実行後の現在状態に対応するvalidatorを、必要に応じて`CallOperationResponse`へ返せる。
|
||||
|
||||
Object validatorをObject identityへ結び付けるためにClient-facingな`ref`を要求しない。ProviderまたはHostはHost-privateなidentityを使用できるが、そのidentity confirmation、Object validator比較、Interface membershipとvalidator比較、DescriptorとOperation implementationの固定、authorization、Operation実行を一つのatomic boundaryで行う。
|
||||
Object validatorとObject identityの関連付けに、Client-facingな`ref`は必須ではない。ProviderまたはHostはHost-privateなidentityを使用できる。ただし、identity confirmation、Object validator比較、Interface membershipとvalidator比較、DescriptorとOperation implementationの固定、authorization、Operation実行は、一つのatomic boundaryで行う。
|
||||
|
||||
Operation実行後validatorを、同じstruct instanceから再計算するか、Operation resultとともに返すか、backendを再観測するかは未決定である。どの方式でも、resultを生成した実行後状態とvalidatorを対応させなければならない。
|
||||
実行後のvalidatorをどこから取得するかも未決定である。同じstruct instanceから再計算する方式、Operation resultとともに返す方式、backendを再観測する方式が考えられるが、いずれもresultを生成した実行後状態とvalidatorを対応させる必要がある。
|
||||
|
||||
Structが`PathBuf`だけを保持し、validator比較後にpathを無条件で開き直す実装は、対象差し替えに対するatomicityを保証できない場合がある。Rust APIは、file descriptor、transaction、conditional update、lock等を利用してbackend固有のatomicityを実現できる必要があるが、その抽象化は未決定である。
|
||||
Structが`PathBuf`だけを保持している場合、validator比較後にpathを無条件で開き直すと、対象差し替えに対するatomicityを保証できないことがある。Rust APIには、file descriptor、transaction、conditional update、lock等でbackend固有のatomicityを実現できることを求める。そのための抽象化は未決定である。
|
||||
|
||||
## 複数Interfaceの実装
|
||||
|
||||
一つのstructは複数のInterface traitを実装できる。
|
||||
一つのstructは、複数のInterface traitを実装できる。
|
||||
|
||||
```rust
|
||||
impl ReadOnlyFileInterface for File {
|
||||
@@ -335,7 +335,7 @@ impl WritableFileInterface for File {
|
||||
}
|
||||
```
|
||||
|
||||
Publication時に、現在の主体へ公開する0個以上のInterfaceを選択し、表示したい順で追加する。
|
||||
そのうち、現在の主体へ公開する0個以上のInterfaceをpublication時に選び、表示したい順に追加する。
|
||||
|
||||
```rust
|
||||
let mut object = PublishedObject::new(file)
|
||||
@@ -348,15 +348,15 @@ if authorization.can_write() {
|
||||
object
|
||||
```
|
||||
|
||||
Protocol Objectの`interfaces`は追加順を保持するordered setである。同じInterface参照の重複は拒否する。各Interface Descriptorは独立したOperation集合を宣言し、複数trait implementationを一つのDescriptorへ暗黙にmergeしない。
|
||||
Protocol Objectの`interfaces`は追加順を保持するordered setであり、同じInterface参照の重複は拒否する。各Interface Descriptorは独立したOperation集合を宣言するため、複数のtrait implementationを一つのDescriptorへ暗黙にmergeしない。
|
||||
|
||||
異なるInterfaceは同じOperation名を宣言できる。Dispatchはrequestの`InterfaceTarget.reference`とOperation名の組で一意に決まり、表示上のqualified表記は[Text Viewの参照表記](../4.2-text-view.md#参照表記)に従う。Signature全体をProtocol request fieldへparseし直さない。
|
||||
異なるInterfaceが同じOperation名を宣言しても、dispatchはrequestの`InterfaceTarget.reference`とOperation名の組で一意に決まる。表示上のqualified表記は[Text Viewの参照表記](../4.2-text-view.md#参照表記)に従い、signature全体をProtocol request fieldへparseし直さない。
|
||||
|
||||
Rust traitのsupertrait、trait alias、複数traitの組み合わせをDescriptor生成へどう対応付けるかは未決定であり、Protocol上のInterface inheritanceを暗黙に導入しない。
|
||||
Rust traitのsupertrait、trait alias、複数traitの組み合わせをDescriptor生成にどう対応付けるかは未決定である。これらによって、Protocol上のInterface inheritanceを暗黙に導入することはしない。
|
||||
|
||||
## 固定Interface向けのsugar
|
||||
|
||||
一つのRust typeを常に同じInterface集合で公開する場合、次のようなsugarを追加してよい。
|
||||
一つのRust typeを常に同じInterface集合で公開する場合は、次のようなsugarを追加してよい。
|
||||
|
||||
```rust
|
||||
#[wip::object(interfaces = [ReadOnlyFileInterface, WritableFileInterface])]
|
||||
@@ -365,19 +365,19 @@ struct File {
|
||||
}
|
||||
```
|
||||
|
||||
または、conceptualには`WipObject`のassociated itemとしてdefault Interface集合を指定できる。
|
||||
別のconceptualな形として、`WipObject`のassociated itemにdefault Interface集合を指定することも考えられる。
|
||||
|
||||
ただし、固定Interface集合をcore modelにはしない。主体、policy、resource kind等に基づいて同じstructへ異なるInterface subsetを追加できるexplicit publication modelを基礎とする。
|
||||
ただし、core modelの基礎はexplicit publicationとする。主体、policy、resource kind等によって、同じstructへ異なるInterface subsetを追加できる必要があるため、固定Interface集合をcore modelにはしない。
|
||||
|
||||
Sugarを使用する場合も、対象typeが指定されたすべてのInterface traitを実装していることと、同じInterfaceを重複していないことを確認しなければならない。
|
||||
Sugarを使う場合も、対象typeが指定したすべてのInterface traitを実装していることと、同じInterfaceを重複していないことを確認する必要がある。
|
||||
|
||||
## HostへのInterface登録
|
||||
|
||||
Generated Interface DefinitionをHostへ登録し、構造化されたInterface参照を割り当てる必要がある。
|
||||
Generated Interface Definitionには、Hostへの登録を通じて構造化されたInterface参照を割り当てる必要がある。参照の絶対scopeとlocal name、および配置pathへの祖先制約は[2.2. Operation and Interface](../2.2-operation-and-interface.md#interfaceの識別とscope)に従う。
|
||||
|
||||
参照の絶対scopeとlocal name、および配置pathへの祖先制約は[2.2. Operation and Interface](../2.2-operation-and-interface.md#interfaceの識別とscope)に従う。以下のconceptual API例はscope / nameを渡す具体構文を省略しており、暗黙のroot scopeを定めるものではない。登録時のcontextと引数の具体APIは引き続き未決定である。Self-scopeは許可され、scopeはそのpathのObjectに紐づく。Scope Objectのoptionalな`ref`はProtocolの`scope_ref`として観測・検証し、`ref`がない場合のidentity追跡不能も許容する。Scopeの移動追跡や独立したscope validatorを導入しない。
|
||||
Self-scopeは許可され、scopeはそのpathのObjectに紐づく。Scope Objectのoptionalな`ref`はProtocolの`scope_ref`として観測・検証する。`ref`がなければidentityを追跡できないことも許容し、scopeの移動追跡や独立したscope validatorは導入しない。
|
||||
|
||||
Conceptualには、eager registrationとlazy registrationの両方が考えられる。
|
||||
登録方法としては、conceptualにはeager registrationとlazy registrationの両方が考えられる。次の例はscope / nameを渡す具体構文を省略しており、暗黙のroot scopeを定めてはいない。登録時のcontextと引数の具体APIも引き続き未決定である。
|
||||
|
||||
```rust
|
||||
let file_read_interface = host.register_interface(ReadOnlyFileInterfaceDefinition)?;
|
||||
@@ -387,9 +387,7 @@ let object = PublishedObject::new(file)
|
||||
.expose(file_write_interface);
|
||||
```
|
||||
|
||||
または、Hostが最初のpublication時に各definitionをinternしてよい。
|
||||
|
||||
どちらの場合も次を守る。
|
||||
また、Hostが最初のpublication時に各definitionをinternする方式でもよい。どちらの登録方法でも、次の条件を満たす必要がある。
|
||||
|
||||
- MutableなInterface参照では`fetch_interface`がvalidatorを返し、同じ参照とvalidatorの組から異なるDescriptorを返さない。
|
||||
- Validatorを返さないInterface参照は、その参照の有効期間中Descriptorをimmutableにする。
|
||||
@@ -401,7 +399,7 @@ let object = PublishedObject::new(file)
|
||||
|
||||
## Request contextとauthorization
|
||||
|
||||
Operation implementationは、Object instance以外にrequest contextを必要とし得る。
|
||||
Operation implementationが必要とする情報は、Object instanceだけとは限らない。Request contextとして、次の情報も必要になり得る。
|
||||
|
||||
- 現在の主体。
|
||||
- Cancellationとdeadline。
|
||||
@@ -409,30 +407,30 @@ Operation implementationは、Object instance以外にrequest contextを必要
|
||||
- Host serviceやbackend connectionへのaccess。
|
||||
- Resource limit。
|
||||
|
||||
これらをmethod parameter、receiver wrapper、generated context、task-local stateのどれで渡すかは未決定である。Protocol parameterとして宣言された値と、Hostが注入するcontextを明確に区別しなければならない。
|
||||
このcontextをmethod parameter、receiver wrapper、generated context、task-local stateのどれで渡すかは未決定である。どの形でも、Protocol parameterとして宣言された値とHostが注入するcontextは明確に区別する必要がある。
|
||||
|
||||
Object publication時のInterface集合の選択と、Operation call時のmembership、Interface validator、authorizationの再評価を実装できる必要がある。以前の`observe`で公開されたInterface集合だけを根拠に、現在のOperation実行を許可してはならない。
|
||||
Interface集合はObject publication時に選択するだけでなく、Operation call時にもmembership、Interface validator、authorizationを再評価できなければならない。以前の`observe`で公開したInterface集合だけを根拠に、現在のOperation実行を許可することはできない。
|
||||
|
||||
Operation resultのRecord、List、Union等へnestedしたすべての`Entry`位置について、Hostは現在の主体にそのpathを認識させてよいことを再帰的に確認できなければならない。通常のstructural Value validationだけではこのvisibility checkを満たさない。Macro-generated code、Projection、Host Runtimeのどこで確認するかは未決定である。
|
||||
Resultのvisibility checkも、通常のstructural Value validationとは別に必要となる。Hostは、Operation resultのRecord、List、Union等にnestedしたすべての`Entry`について、現在の主体にそのpathを認識させてよいかを再帰的に確認できなければならない。この確認をMacro-generated code、Projection、Host Runtimeのどこで行うかは未決定である。
|
||||
|
||||
Operation argumentとして`Entry` pathを受け取った場合も、pathの所持をauthorizationの証明として扱わず、参照先へ作用する時点で現在の主体について認可する。
|
||||
Argumentとして受け取った`Entry` pathについても、pathの所持をauthorizationの証明にはしない。参照先へ作用する時点で、現在の主体について認可する。
|
||||
|
||||
## Error model
|
||||
|
||||
Rust methodのerror表現は、次の四種類を区別できなければならない。
|
||||
Rust methodのerror表現には、次の四種類を区別できることを求める。
|
||||
|
||||
- Protocol validationまたはdispatch failure。
|
||||
- Effectがcommitされていないと保証できるHost / backend implementation failure。
|
||||
- Operationの未実行またはrollbackを保証できない`OperationOutcomeUnknown`。
|
||||
- Interfaceがreturn typeとして宣言したdomain failure。
|
||||
|
||||
現在のProtocolでは、domain failureはOperation resultのUnion caseとして表す。Rustの`Result<T, E>`をdomain Union、Host error、または両方のどれへ対応付けるかは未決定である。
|
||||
現在のProtocolはdomain failureをOperation resultのUnion caseとして表す。Rustの`Result<T, E>`をdomain Union、Host error、またはその両方のどれに対応付けるかは未決定である。
|
||||
|
||||
MacroがRust panic、result encode failure、宣言型に違反するimplementation resultをdomain failureへ自動変換してはならない。Host Runtimeは、effectがcommitされていないと保証できる場合だけ`Internal`へmappingし、保証できない場合は`OperationOutcomeUnknown`へmappingする。Clientへ送信済みか不明なtransport切断も自動retryしない。
|
||||
Rust panic、result encode failure、宣言型に違反するimplementation resultを、Macroがdomain failureへ自動変換することは認めない。Host Runtimeは、effectがcommitされていないと保証できる場合だけ`Internal`へmappingし、保証できなければ`OperationOutcomeUnknown`へmappingする。Clientへ送信済みかどうか不明なtransport切断についても、自動retryはしない。
|
||||
|
||||
## 要件
|
||||
|
||||
Rust API modelは少なくとも次を満たす。
|
||||
このdraftのRust API modelに求める要件は、少なくとも次のとおりである。
|
||||
|
||||
- Interface Descriptorをtrait declarationから生成し、trait implementationごとに変化させない。
|
||||
- Structが`WipObject`と、追加する各Interface traitを実装していることをcompile timeに確認する。
|
||||
@@ -459,7 +457,7 @@ Rust API modelは少なくとも次を満たす。
|
||||
|
||||
## 非目標
|
||||
|
||||
このdraftは次を決定しない。
|
||||
次の事項は、このdraftでは決定しない。
|
||||
|
||||
- 最終的なcrate、module、trait、attribute、deriveの名前。
|
||||
- Proc macroの内部実装。
|
||||
@@ -495,4 +493,4 @@ Rust API modelは少なくとも次を満たす。
|
||||
- 主体ごとに異なるInterface combinationを追加したPublished Objectのconcrete return typeをどう統一するか。
|
||||
- Rust client APIを同じtrait declarationから生成するか。
|
||||
|
||||
これらを決定する際は、静的service objectだけでなく、Filesystem、database row、virtual aggregate、主体別Interface compositionを同じAPIで実装できるか評価する。
|
||||
これらの選択は、静的service objectに使えるだけでは足りない。Filesystem、database row、virtual aggregate、主体別Interface compositionも、同じAPIで実装できるかを評価して決定する。
|
||||
|
||||
Reference in New Issue
Block a user