context: update ValueContext to handle Any value and more Key types, use closures (#11993)
parent
d6a4bce2ef
commit
c151e075e1
|
@ -99,6 +99,10 @@ const (
|
||||||
'do_not_remove',
|
'do_not_remove',
|
||||||
]
|
]
|
||||||
skip_on_windows = [
|
skip_on_windows = [
|
||||||
|
'vlib/context/cancel_test.v',
|
||||||
|
'vlib/context/deadline_test.v',
|
||||||
|
'vlib/context/empty_test.v',
|
||||||
|
'vlib/context/value_test.v',
|
||||||
'vlib/orm/orm_test.v',
|
'vlib/orm/orm_test.v',
|
||||||
'vlib/v/tests/orm_sub_struct_test.v',
|
'vlib/v/tests/orm_sub_struct_test.v',
|
||||||
'vlib/v/tests/closure_test.v',
|
'vlib/v/tests/closure_test.v',
|
||||||
|
|
|
@ -59,9 +59,9 @@ fn example_with_cancel() {
|
||||||
return dst
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.with_cancel(context.background())
|
ctx, cancel := context.with_cancel(context.background())
|
||||||
defer {
|
defer {
|
||||||
context.cancel(ctx)
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
ch := gen(ctx)
|
ch := gen(ctx)
|
||||||
|
@ -87,13 +87,13 @@ const (
|
||||||
// function that it should abandon its work as soon as it gets to it.
|
// function that it should abandon its work as soon as it gets to it.
|
||||||
fn example_with_deadline() {
|
fn example_with_deadline() {
|
||||||
dur := time.now().add(short_duration)
|
dur := time.now().add(short_duration)
|
||||||
ctx := context.with_deadline(context.background(), dur)
|
ctx, cancel := context.with_deadline(context.background(), dur)
|
||||||
|
|
||||||
defer {
|
defer {
|
||||||
// Even though ctx will be expired, it is good practice to call its
|
// Even though ctx will be expired, it is good practice to call its
|
||||||
// cancellation function in any case. Failure to do so may keep the
|
// cancellation function in any case. Failure to do so may keep the
|
||||||
// context and its parent alive longer than necessary.
|
// context and its parent alive longer than necessary.
|
||||||
context.cancel(ctx)
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx_ch := ctx.done()
|
ctx_ch := ctx.done()
|
||||||
|
@ -122,9 +122,9 @@ const (
|
||||||
fn example_with_timeout() {
|
fn example_with_timeout() {
|
||||||
// Pass a context with a timeout to tell a blocking function that it
|
// Pass a context with a timeout to tell a blocking function that it
|
||||||
// should abandon its work after the timeout elapses.
|
// should abandon its work after the timeout elapses.
|
||||||
ctx := context.with_timeout(context.background(), short_duration)
|
ctx, cancel := context.with_timeout(context.background(), short_duration)
|
||||||
defer {
|
defer {
|
||||||
context.cancel(ctx)
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx_ch := ctx.done()
|
ctx_ch := ctx.done()
|
||||||
|
@ -142,25 +142,36 @@ fn example_with_timeout() {
|
||||||
```v
|
```v
|
||||||
import context
|
import context
|
||||||
|
|
||||||
type ValueContextKey = string
|
const not_found_value = &Value{
|
||||||
|
val: 'key not found'
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Value {
|
||||||
|
val string
|
||||||
|
}
|
||||||
|
|
||||||
// This example demonstrates how a value can be passed to the context
|
// This example demonstrates how a value can be passed to the context
|
||||||
// and also how to retrieve it if it exists.
|
// and also how to retrieve it if it exists.
|
||||||
fn example_with_value() {
|
fn example_with_value() {
|
||||||
f := fn (ctx context.Context, key ValueContextKey) string {
|
f := fn (ctx context.Context, key context.Key) &Value {
|
||||||
if value := ctx.value(key) {
|
if value := ctx.value(key) {
|
||||||
if !isnil(value) {
|
match value {
|
||||||
return *(&string(value))
|
Value {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
else {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 'key not found'
|
return not_found_value
|
||||||
}
|
}
|
||||||
|
|
||||||
key := ValueContextKey('language')
|
key := 'language'
|
||||||
value := 'VAL'
|
value := &Value{
|
||||||
ctx := context.with_value(context.background(), key, &value)
|
val: 'VAL'
|
||||||
|
}
|
||||||
|
ctx := context.with_value(context.background(), key, value)
|
||||||
|
|
||||||
assert value == f(ctx, key)
|
assert value == f(ctx, key)
|
||||||
assert 'key not found' == f(ctx, ValueContextKey('color'))
|
assert not_found_value == f(ctx, 'color')
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// This module defines the Context type, which carries deadlines, cancellation signals,
|
// This module defines the Context type, which carries deadlines, cancellation signals,
|
||||||
// and other request-scoped values across API boundaries and between processes.
|
// and other request-scoped values across API boundaries and between processes.
|
||||||
// Based off: https://github.com/golang/go/tree/master/src/context
|
// Based on: https://github.com/golang/go/tree/master/src/context
|
||||||
// Last commit: https://github.com/golang/go/commit/52bf14e0e8bdcd73f1ddfb0c4a1d0200097d3ba2
|
// Last commit: https://github.com/golang/go/commit/52bf14e0e8bdcd73f1ddfb0c4a1d0200097d3ba2
|
||||||
module context
|
module context
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ const (
|
||||||
background = EmptyContext(0)
|
background = EmptyContext(0)
|
||||||
todo = EmptyContext(1)
|
todo = EmptyContext(1)
|
||||||
|
|
||||||
cancel_context_key = 'context.CancelContext'
|
cancel_context_key = Key('context.CancelContext')
|
||||||
|
|
||||||
// canceled is the error returned by Context.err when the context is canceled.
|
// canceled is the error returned by Context.err when the context is canceled.
|
||||||
canceled = error('context canceled')
|
canceled = error('context canceled')
|
||||||
|
@ -20,6 +20,24 @@ const (
|
||||||
deadline_exceeded = error('context deadline exceeded')
|
deadline_exceeded = error('context deadline exceeded')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Key represents the type for the ValueContext key
|
||||||
|
pub type Key = bool
|
||||||
|
| byte
|
||||||
|
| f32
|
||||||
|
| f64
|
||||||
|
| i16
|
||||||
|
| i64
|
||||||
|
| i8
|
||||||
|
| int
|
||||||
|
| string
|
||||||
|
| u16
|
||||||
|
| u32
|
||||||
|
| u64
|
||||||
|
| voidptr
|
||||||
|
|
||||||
|
// Any represents a generic type for the ValueContext
|
||||||
|
pub interface Any {}
|
||||||
|
|
||||||
pub interface Context {
|
pub interface Context {
|
||||||
// deadline returns the time when work done on behalf of this context
|
// deadline returns the time when work done on behalf of this context
|
||||||
// should be canceled. deadline returns none when no deadline is
|
// should be canceled. deadline returns none when no deadline is
|
||||||
|
@ -56,7 +74,7 @@ pub interface Context {
|
||||||
// Context.Value. A key can be any type that supports equality;
|
// Context.Value. A key can be any type that supports equality;
|
||||||
// packages should define keys as an unexported type to avoid
|
// packages should define keys as an unexported type to avoid
|
||||||
// collisions.
|
// collisions.
|
||||||
value(key string) ?voidptr
|
value(key Key) ?Any
|
||||||
str() string
|
str() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// This module defines the Context type, which carries deadlines, cancellation signals,
|
// This module defines the Context type, which carries deadlines, cancellation signals,
|
||||||
// and other request-scoped values across API boundaries and between processes.
|
// and other request-scoped values across API boundaries and between processes.
|
||||||
// Based off: https://github.com/golang/go/tree/master/src/context
|
// Based on: https://github.com/golang/go/tree/master/src/context
|
||||||
// Last commit: https://github.com/golang/go/commit/52bf14e0e8bdcd73f1ddfb0c4a1d0200097d3ba2
|
// Last commit: https://github.com/golang/go/commit/52bf14e0e8bdcd73f1ddfb0c4a1d0200097d3ba2
|
||||||
module context
|
module context
|
||||||
|
|
||||||
|
@ -8,12 +8,15 @@ import rand
|
||||||
import sync
|
import sync
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
pub type CancelFn = fn ()
|
||||||
|
|
||||||
pub interface Canceler {
|
pub interface Canceler {
|
||||||
id string
|
id string
|
||||||
cancel(remove_from_parent bool, err IError)
|
cancel(remove_from_parent bool, err IError)
|
||||||
done() chan int
|
done() chan int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[deprecated]
|
||||||
pub fn cancel(ctx Context) {
|
pub fn cancel(ctx Context) {
|
||||||
match mut ctx {
|
match mut ctx {
|
||||||
CancelContext {
|
CancelContext {
|
||||||
|
@ -44,10 +47,12 @@ mut:
|
||||||
//
|
//
|
||||||
// Canceling this context releases resources associated with it, so code should
|
// Canceling this context releases resources associated with it, so code should
|
||||||
// call cancel as soon as the operations running in this Context complete.
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
pub fn with_cancel(parent Context) Context {
|
pub fn with_cancel(parent Context) (Context, CancelFn) {
|
||||||
mut c := new_cancel_context(parent)
|
mut c := new_cancel_context(parent)
|
||||||
propagate_cancel(parent, mut c)
|
propagate_cancel(parent, c)
|
||||||
return Context(c)
|
return Context(c), fn [mut c] () {
|
||||||
|
c.cancel(true, canceled)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// new_cancel_context returns an initialized CancelContext.
|
// new_cancel_context returns an initialized CancelContext.
|
||||||
|
@ -61,7 +66,7 @@ fn new_cancel_context(parent Context) &CancelContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx CancelContext) deadline() ?time.Time {
|
pub fn (ctx &CancelContext) deadline() ?time.Time {
|
||||||
return none
|
return none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,14 +84,14 @@ pub fn (mut ctx CancelContext) err() IError {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx CancelContext) value(key string) ?voidptr {
|
pub fn (ctx &CancelContext) value(key Key) ?Any {
|
||||||
if key == cancel_context_key {
|
if key == cancel_context_key {
|
||||||
return voidptr(unsafe { &ctx })
|
return ctx
|
||||||
}
|
}
|
||||||
return ctx.context.value(key)
|
return ctx.context.value(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx CancelContext) str() string {
|
pub fn (ctx &CancelContext) str() string {
|
||||||
return context_name(ctx.context) + '.with_cancel'
|
return context_name(ctx.context) + '.with_cancel'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +127,7 @@ fn (mut ctx CancelContext) cancel(remove_from_parent bool, err IError) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn propagate_cancel(parent Context, mut child Canceler) {
|
fn propagate_cancel(parent Context, child Canceler) {
|
||||||
done := parent.done()
|
done := parent.done()
|
||||||
select {
|
select {
|
||||||
_ := <-done {
|
_ := <-done {
|
||||||
|
@ -132,19 +137,19 @@ fn propagate_cancel(parent Context, mut child Canceler) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut p := parent_cancel_context(parent) or {
|
mut p := parent_cancel_context(parent) or {
|
||||||
go fn (parent Context, mut child Canceler) {
|
go fn (parent Context, child Canceler) {
|
||||||
pdone := parent.done()
|
pdone := parent.done()
|
||||||
select {
|
select {
|
||||||
_ := <-pdone {
|
_ := <-pdone {
|
||||||
child.cancel(false, parent.err())
|
child.cancel(false, parent.err())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(parent, mut child)
|
}(parent, child)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.err is none {
|
if p.err is none {
|
||||||
p.children[child.id] = *child
|
p.children[child.id] = child
|
||||||
} else {
|
} else {
|
||||||
// parent has already been canceled
|
// parent has already been canceled
|
||||||
child.cancel(false, p.err)
|
child.cancel(false, p.err)
|
||||||
|
@ -157,19 +162,20 @@ fn propagate_cancel(parent Context, mut child Canceler) {
|
||||||
// parent.done() matches that CancelContext. (If not, the CancelContext
|
// parent.done() matches that CancelContext. (If not, the CancelContext
|
||||||
// has been wrapped in a custom implementation providing a
|
// has been wrapped in a custom implementation providing a
|
||||||
// different done channel, in which case we should not bypass it.)
|
// different done channel, in which case we should not bypass it.)
|
||||||
fn parent_cancel_context(parent Context) ?CancelContext {
|
fn parent_cancel_context(parent Context) ?&CancelContext {
|
||||||
done := parent.done()
|
done := parent.done()
|
||||||
if done.closed {
|
if done.closed {
|
||||||
return none
|
return none
|
||||||
}
|
}
|
||||||
if p_ptr := parent.value(cancel_context_key) {
|
mut p := parent.value(cancel_context_key) ?
|
||||||
if !isnil(p_ptr) {
|
match mut p {
|
||||||
mut p := &CancelContext(p_ptr)
|
CancelContext {
|
||||||
pdone := p.done()
|
pdone := p.done()
|
||||||
if done == pdone {
|
if done == pdone {
|
||||||
return *p
|
return p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {}
|
||||||
}
|
}
|
||||||
return none
|
return none
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,9 @@ fn test_with_cancel() {
|
||||||
return dst
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.with_cancel(context.background())
|
ctx, cancel := context.with_cancel(context.background())
|
||||||
defer {
|
defer {
|
||||||
context.cancel(ctx)
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
ch := gen(ctx)
|
ch := gen(ctx)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// This module defines the Context type, which carries deadlines, cancellation signals,
|
// This module defines the Context type, which carries deadlines, cancellation signals,
|
||||||
// and other request-scoped values across API boundaries and between processes.
|
// and other request-scoped values across API boundaries and between processes.
|
||||||
// Based off: https://github.com/golang/go/tree/master/src/context
|
// Based on: https://github.com/golang/go/tree/master/src/context
|
||||||
// Last commit: https://github.com/golang/go/commit/52bf14e0e8bdcd73f1ddfb0c4a1d0200097d3ba2
|
// Last commit: https://github.com/golang/go/commit/52bf14e0e8bdcd73f1ddfb0c4a1d0200097d3ba2
|
||||||
module context
|
module context
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ mut:
|
||||||
//
|
//
|
||||||
// Canceling this context releases resources associated with it, so code should
|
// Canceling this context releases resources associated with it, so code should
|
||||||
// call cancel as soon as the operations running in this Context complete.
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
pub fn with_deadline(parent Context, d time.Time) Context {
|
pub fn with_deadline(parent Context, d time.Time) (Context, CancelFn) {
|
||||||
id := rand.uuid_v4()
|
id := rand.uuid_v4()
|
||||||
if cur := parent.deadline() {
|
if cur := parent.deadline() {
|
||||||
if cur < d {
|
if cur < d {
|
||||||
|
@ -40,11 +40,13 @@ pub fn with_deadline(parent Context, d time.Time) Context {
|
||||||
deadline: d
|
deadline: d
|
||||||
id: id
|
id: id
|
||||||
}
|
}
|
||||||
propagate_cancel(parent, mut ctx)
|
propagate_cancel(parent, ctx)
|
||||||
dur := d - time.now()
|
dur := d - time.now()
|
||||||
if dur.nanoseconds() <= 0 {
|
if dur.nanoseconds() <= 0 {
|
||||||
ctx.cancel(true, deadline_exceeded) // deadline has already passed
|
ctx.cancel(true, deadline_exceeded) // deadline has already passed
|
||||||
return Context(ctx)
|
return Context(ctx), fn [mut ctx] () {
|
||||||
|
ctx.cancel(true, canceled)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.err() is none {
|
if ctx.err() is none {
|
||||||
|
@ -53,18 +55,20 @@ pub fn with_deadline(parent Context, d time.Time) Context {
|
||||||
ctx.cancel(true, deadline_exceeded)
|
ctx.cancel(true, deadline_exceeded)
|
||||||
}(mut ctx, dur)
|
}(mut ctx, dur)
|
||||||
}
|
}
|
||||||
return Context(ctx)
|
return Context(ctx), fn [mut ctx] () {
|
||||||
|
ctx.cancel(true, canceled)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// with_timeout returns with_deadline(parent, time.now().add(timeout)).
|
// with_timeout returns with_deadline(parent, time.now().add(timeout)).
|
||||||
//
|
//
|
||||||
// Canceling this context releases resources associated with it, so code should
|
// Canceling this context releases resources associated with it, so code should
|
||||||
// call cancel as soon as the operations running in this Context complete
|
// call cancel as soon as the operations running in this Context complete
|
||||||
pub fn with_timeout(parent Context, timeout time.Duration) Context {
|
pub fn with_timeout(parent Context, timeout time.Duration) (Context, CancelFn) {
|
||||||
return with_deadline(parent, time.now().add(timeout))
|
return with_deadline(parent, time.now().add(timeout))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx TimerContext) deadline() ?time.Time {
|
pub fn (ctx &TimerContext) deadline() ?time.Time {
|
||||||
return ctx.deadline
|
return ctx.deadline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +80,7 @@ pub fn (mut ctx TimerContext) err() IError {
|
||||||
return ctx.cancel_ctx.err()
|
return ctx.cancel_ctx.err()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx TimerContext) value(key string) ?voidptr {
|
pub fn (ctx &TimerContext) value(key Key) ?Any {
|
||||||
return ctx.cancel_ctx.value(key)
|
return ctx.cancel_ctx.value(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +92,7 @@ pub fn (mut ctx TimerContext) cancel(remove_from_parent bool, err IError) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx TimerContext) str() string {
|
pub fn (ctx &TimerContext) str() string {
|
||||||
return context_name(ctx.cancel_ctx.context) + '.with_deadline(' + ctx.deadline.str() + ' [' +
|
return context_name(ctx.cancel_ctx.context) + '.with_deadline(' + ctx.deadline.str() + ' [' +
|
||||||
(time.now() - ctx.deadline).str() + '])'
|
(time.now() - ctx.deadline).str() + '])'
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,13 @@ const (
|
||||||
// function that it should abandon its work as soon as it gets to it.
|
// function that it should abandon its work as soon as it gets to it.
|
||||||
fn test_with_deadline() {
|
fn test_with_deadline() {
|
||||||
dur := time.now().add(short_duration)
|
dur := time.now().add(short_duration)
|
||||||
ctx := context.with_deadline(context.background(), dur)
|
ctx, cancel := context.with_deadline(context.background(), dur)
|
||||||
|
|
||||||
defer {
|
defer {
|
||||||
// Even though ctx will be expired, it is good practice to call its
|
// Even though ctx will be expired, it is good practice to call its
|
||||||
// cancellation function in any case. Failure to do so may keep the
|
// cancellation function in any case. Failure to do so may keep the
|
||||||
// context and its parent alive longer than necessary.
|
// context and its parent alive longer than necessary.
|
||||||
context.cancel(ctx)
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx_ch := ctx.done()
|
ctx_ch := ctx.done()
|
||||||
|
@ -33,9 +33,9 @@ fn test_with_deadline() {
|
||||||
fn test_with_timeout() {
|
fn test_with_timeout() {
|
||||||
// Pass a context with a timeout to tell a blocking function that it
|
// Pass a context with a timeout to tell a blocking function that it
|
||||||
// should abandon its work after the timeout elapses.
|
// should abandon its work after the timeout elapses.
|
||||||
ctx := context.with_timeout(context.background(), short_duration)
|
ctx, cancel := context.with_timeout(context.background(), short_duration)
|
||||||
defer {
|
defer {
|
||||||
context.cancel(ctx)
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx_ch := ctx.done()
|
ctx_ch := ctx.done()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// This module defines the Context type, which carries deadlines, cancellation signals,
|
// This module defines the Context type, which carries deadlines, cancellation signals,
|
||||||
// and other request-scoped values across API boundaries and between processes.
|
// and other request-scoped values across API boundaries and between processes.
|
||||||
// Based off: https://github.com/golang/go/tree/master/src/context
|
// Based on: https://github.com/golang/go/tree/master/src/context
|
||||||
// Last commit: https://github.com/golang/go/commit/52bf14e0e8bdcd73f1ddfb0c4a1d0200097d3ba2
|
// Last commit: https://github.com/golang/go/commit/52bf14e0e8bdcd73f1ddfb0c4a1d0200097d3ba2
|
||||||
module context
|
module context
|
||||||
|
|
||||||
|
@ -10,11 +10,11 @@ import time
|
||||||
// struct{}, since vars of this type must have distinct addresses.
|
// struct{}, since vars of this type must have distinct addresses.
|
||||||
pub type EmptyContext = int
|
pub type EmptyContext = int
|
||||||
|
|
||||||
pub fn (ctx EmptyContext) deadline() ?time.Time {
|
pub fn (ctx &EmptyContext) deadline() ?time.Time {
|
||||||
return none
|
return none
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx EmptyContext) done() chan int {
|
pub fn (ctx &EmptyContext) done() chan int {
|
||||||
ch := chan int{}
|
ch := chan int{}
|
||||||
defer {
|
defer {
|
||||||
ch.close()
|
ch.close()
|
||||||
|
@ -22,16 +22,15 @@ pub fn (ctx EmptyContext) done() chan int {
|
||||||
return ch
|
return ch
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx EmptyContext) err() IError {
|
pub fn (ctx &EmptyContext) err() IError {
|
||||||
// TODO: Change this to `none`
|
|
||||||
return none_
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn (ctx EmptyContext) value(key string) ?voidptr {
|
|
||||||
return none
|
return none
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx EmptyContext) str() string {
|
pub fn (ctx &EmptyContext) value(key Key) ?Any {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (ctx &EmptyContext) str() string {
|
||||||
if ctx == background {
|
if ctx == background {
|
||||||
return 'context.Background'
|
return 'context.Background'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
module context
|
|
||||||
|
|
||||||
const none_ = IError(&None{})
|
|
||||||
|
|
||||||
struct None {
|
|
||||||
msg string
|
|
||||||
code int
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (_ None) str() string {
|
|
||||||
return 'none'
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
// This module defines the Context type, which carries deadlines, cancellation signals,
|
// This module defines the Context type, which carries deadlines, cancellation signals,
|
||||||
// and other request-scoped values across API boundaries and between processes.
|
// and other request-scoped values across API boundaries and between processes.
|
||||||
// Based off: https://github.com/golang/go/tree/master/src/context
|
// Based on: https://github.com/golang/go/tree/master/src/context
|
||||||
// Last commit: https://github.com/golang/go/commit/52bf14e0e8bdcd73f1ddfb0c4a1d0200097d3ba2
|
// Last commit: https://github.com/golang/go/commit/52bf14e0e8bdcd73f1ddfb0c4a1d0200097d3ba2
|
||||||
module context
|
module context
|
||||||
|
|
||||||
|
@ -9,8 +9,8 @@ import time
|
||||||
// A ValueContext carries a key-value pair. It implements Value for that key and
|
// A ValueContext carries a key-value pair. It implements Value for that key and
|
||||||
// delegates all other calls to the embedded Context.
|
// delegates all other calls to the embedded Context.
|
||||||
pub struct ValueContext {
|
pub struct ValueContext {
|
||||||
key string
|
key Key
|
||||||
value voidptr
|
value Any
|
||||||
mut:
|
mut:
|
||||||
context Context
|
context Context
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ mut:
|
||||||
// string or any other built-in type to avoid collisions between
|
// string or any other built-in type to avoid collisions between
|
||||||
// packages using context. Users of with_value should define their own
|
// packages using context. Users of with_value should define their own
|
||||||
// types for keys
|
// types for keys
|
||||||
pub fn with_value(parent Context, key string, value voidptr) Context {
|
pub fn with_value(parent Context, key Key, value Any) Context {
|
||||||
return &ValueContext{
|
return &ValueContext{
|
||||||
context: parent
|
context: parent
|
||||||
key: key
|
key: key
|
||||||
|
@ -33,25 +33,25 @@ pub fn with_value(parent Context, key string, value voidptr) Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx ValueContext) deadline() ?time.Time {
|
pub fn (ctx &ValueContext) deadline() ?time.Time {
|
||||||
return ctx.context.deadline()
|
return ctx.context.deadline()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx ValueContext) done() chan int {
|
pub fn (ctx &ValueContext) done() chan int {
|
||||||
return ctx.context.done()
|
return ctx.context.done()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx ValueContext) err() IError {
|
pub fn (ctx &ValueContext) err() IError {
|
||||||
return ctx.context.err()
|
return ctx.context.err()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx ValueContext) value(key string) ?voidptr {
|
pub fn (ctx &ValueContext) value(key Key) ?Any {
|
||||||
if ctx.key == key {
|
if ctx.key == key {
|
||||||
return ctx.value
|
return ctx.value
|
||||||
}
|
}
|
||||||
return ctx.context.value(key)
|
return ctx.context.value(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx ValueContext) str() string {
|
pub fn (ctx &ValueContext) str() string {
|
||||||
return context_name(ctx.context) + '.with_value'
|
return context_name(ctx.context) + '.with_value'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,34 @@
|
||||||
import context
|
import context
|
||||||
|
|
||||||
type ValueContextKey = string
|
const not_found_value = &Value{
|
||||||
|
val: 'key not found'
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Value {
|
||||||
|
val string
|
||||||
|
}
|
||||||
|
|
||||||
// This example demonstrates how a value can be passed to the context
|
// This example demonstrates how a value can be passed to the context
|
||||||
// and also how to retrieve it if it exists.
|
// and also how to retrieve it if it exists.
|
||||||
fn test_with_value() {
|
fn test_with_value() {
|
||||||
f := fn (ctx context.Context, key ValueContextKey) string {
|
f := fn (ctx context.Context, key context.Key) &Value {
|
||||||
if value := ctx.value(key) {
|
if value := ctx.value(key) {
|
||||||
if !isnil(value) {
|
match value {
|
||||||
return *(&string(value))
|
Value {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
else {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 'key not found'
|
return not_found_value
|
||||||
}
|
}
|
||||||
|
|
||||||
key := ValueContextKey('language')
|
key := 'language'
|
||||||
value := 'VAL'
|
value := &Value{
|
||||||
ctx := context.with_value(context.background(), key, &value)
|
val: 'VAL'
|
||||||
|
}
|
||||||
|
ctx := context.with_value(context.background(), key, value)
|
||||||
|
|
||||||
assert value == f(ctx, key)
|
assert value == f(ctx, key)
|
||||||
assert 'key not found' == f(ctx, ValueContextKey('color'))
|
assert not_found_value == f(ctx, 'color')
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue