v / vlib / context
Raw file | 102 loc (90 sloc) | 3.23 KB | Latest commit hash e81e0ac70
1// This module defines the Context type, which carries deadlines, cancellation signals,
2// and other request-scoped values across API boundaries and between processes.
3// Based on: https://github.com/golang/go/tree/master/src/context
4// Last commit: https://github.com/golang/go/commit/52bf14e0e8bdcd73f1ddfb0c4a1d0200097d3ba2
5module context
6
7import rand
8import time
9
10// A TimerContext carries a timer and a deadline. It embeds a CancelContext to
11// implement done and err. It implements cancel by stopping its timer then
12// delegating to CancelContext.cancel
13pub struct TimerContext {
14 id string
15mut:
16 cancel_ctx CancelContext
17 deadline time.Time
18}
19
20// with_deadline returns a copy of the parent context with the deadline adjusted
21// to be no later than d. If the parent's deadline is already earlier than d,
22// with_deadline(parent, d) is semantically equivalent to parent. The returned
23// context's Done channel is closed when the deadline expires, when the returned
24// cancel function is called, or when the parent context's Done channel is
25// closed, whichever happens first.
26//
27// Canceling this context releases resources associated with it, so code should
28// call cancel as soon as the operations running in this Context complete.
29pub fn with_deadline(mut parent Context, d time.Time) (Context, CancelFn) {
30 id := rand.uuid_v4()
31 if cur := parent.deadline() {
32 if cur < d {
33 // The current deadline is already sooner than the new one.
34 return with_cancel(mut parent)
35 }
36 }
37 cancel_ctx := new_cancel_context(parent)
38 mut ctx := &TimerContext{
39 cancel_ctx: cancel_ctx
40 deadline: d
41 id: id
42 }
43 propagate_cancel(mut parent, mut ctx)
44 dur := d - time.now()
45 if dur.nanoseconds() <= 0 {
46 ctx.cancel(true, deadline_exceeded) // deadline has already passed
47 cancel_fn := fn [mut ctx] () {
48 ctx.cancel(true, canceled)
49 }
50 return Context(ctx), CancelFn(cancel_fn)
51 }
52
53 if ctx.err() is none {
54 spawn fn (mut ctx TimerContext, dur time.Duration) {
55 time.sleep(dur)
56 ctx.cancel(true, deadline_exceeded)
57 }(mut ctx, dur)
58 }
59
60 cancel_fn := fn [mut ctx] () {
61 ctx.cancel(true, canceled)
62 }
63 return Context(ctx), CancelFn(cancel_fn)
64}
65
66// with_timeout returns with_deadline(parent, time.now().add(timeout)).
67//
68// Canceling this context releases resources associated with it, so code should
69// call cancel as soon as the operations running in this Context complete
70pub fn with_timeout(mut parent Context, timeout time.Duration) (Context, CancelFn) {
71 return with_deadline(mut parent, time.now().add(timeout))
72}
73
74pub fn (ctx &TimerContext) deadline() ?time.Time {
75 return ctx.deadline
76}
77
78pub fn (mut ctx TimerContext) done() chan int {
79 return ctx.cancel_ctx.done()
80}
81
82pub fn (mut ctx TimerContext) err() IError {
83 return ctx.cancel_ctx.err()
84}
85
86pub fn (ctx &TimerContext) value(key Key) ?Any {
87 return ctx.cancel_ctx.value(key)
88}
89
90pub fn (mut ctx TimerContext) cancel(remove_from_parent bool, err IError) {
91 ctx.cancel_ctx.cancel(false, err)
92 if remove_from_parent {
93 // Remove this TimerContext from its parent CancelContext's children.
94 mut cc := &ctx.cancel_ctx.context
95 remove_child(mut cc, ctx)
96 }
97}
98
99pub fn (ctx &TimerContext) str() string {
100 return context_name(ctx.cancel_ctx.context) + '.with_deadline(' + ctx.deadline.str() + ' [' +
101 (time.now() - ctx.deadline).str() + '])'
102}