Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,80 @@
|
||||
//! Upload 只在 HTTP App 与同领域 Port/Adapter 之间移动,不放宽事务和并发检查。
|
||||
|
||||
mod ownership;
|
||||
|
||||
use super::Context;
|
||||
use crate::compiler::model::*;
|
||||
use crate::syntax::{ast, diagnostic::Diagnostic};
|
||||
|
||||
pub(super) use ownership::check;
|
||||
|
||||
pub(super) fn nested(kind: &Type) -> bool {
|
||||
match kind {
|
||||
Type::Upload => true,
|
||||
Type::Optional(inner)
|
||||
| Type::List(inner)
|
||||
| Type::Stream(inner)
|
||||
| Type::AsyncStream(inner)
|
||||
| Type::Channel(inner) => nested(inner),
|
||||
Type::Map(key, value) | Type::MapEntry(key, value) => nested(key) || nested(value),
|
||||
Type::Outputs(fields) => fields.iter().any(|(_, kind)| nested(kind)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
impl Context<'_> {
|
||||
pub(super) fn upload(
|
||||
&mut self,
|
||||
operation: upload::Operation,
|
||||
arguments: &[ast::Expression],
|
||||
expected: Option<&Type>,
|
||||
source: &ast::Expression,
|
||||
) -> Result<Expression, Diagnostic> {
|
||||
let role = package::role(&self.definition_names.packages[self.source]);
|
||||
let allowed = if operation == upload::Operation::Put {
|
||||
self.definition_names.packages[self.source] == "dever.storage"
|
||||
} else {
|
||||
matches!(role, Some((_, "app" | "adapter")))
|
||||
};
|
||||
if !allowed {
|
||||
return Err(self.error(
|
||||
source,
|
||||
"Upload operations require App; storage.put requires its Adapter",
|
||||
));
|
||||
}
|
||||
let [argument] = arguments else {
|
||||
return Err(self.error(source, "Upload operation requires one Upload"));
|
||||
};
|
||||
let value = self.expression(argument, Some(&Type::Upload))?;
|
||||
let value_type = match operation {
|
||||
upload::Operation::Size => Type::Int,
|
||||
upload::Operation::Filename | upload::Operation::ContentType => Type::Text,
|
||||
upload::Operation::Close => Type::Unit,
|
||||
upload::Operation::Put => {
|
||||
let index = self
|
||||
.definition_names
|
||||
.resolve("dever.storage.PutResult", self.source, source.span)?
|
||||
.ok_or_else(|| {
|
||||
self.error(source, "storage.put requires the official PutResult")
|
||||
})?;
|
||||
let valid = matches!(&self.definitions[index].shape, Shape::Choice(variants)
|
||||
if variants.len() == 2 && variants[0].name == "Stored" && !variants[0].error
|
||||
&& variants[0].fields == [("key".into(), Type::Uuid)]
|
||||
&& variants[1].name == "Failed" && variants[1].error
|
||||
&& variants[1].fields == [("message".into(), Type::Text)]);
|
||||
if !valid {
|
||||
return Err(self.error(source, "invalid storage.PutResult contract"));
|
||||
}
|
||||
Type::Named(index)
|
||||
}
|
||||
};
|
||||
self.coerce(
|
||||
Expression {
|
||||
kind: Node::Upload(operation, vec![value]),
|
||||
value_type,
|
||||
span: source.span,
|
||||
},
|
||||
expected,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user