Skip to content

Commit

Permalink
fun/* additions, particularly either, promise and future
Browse files Browse the repository at this point in the history
  • Loading branch information
golightlyb committed May 17, 2023
1 parent 6f93b4a commit 1f48f70
Show file tree
Hide file tree
Showing 14 changed files with 694 additions and 70 deletions.
4 changes: 2 additions & 2 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
github.com/tawesoft/golib

Copyright © 2019 - 2022 Ben Golightly <[email protected]>
Copyright © 2019 - 2022 Tawesoft Ltd <[email protected]>
Copyright © 2019 - 2023 Ben Golightly <[email protected]>
Copyright © 2019 - 2023 Tawesoft Ltd <[email protected]>
Copyright © Contributors (api.github.com/repos/tawesoft/golib/contributors)
Copyright © Unicode, W3C & others (some portions; see LICENSE-PARTS.txt)

Expand Down
44 changes: 26 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![Coverage Status](https://coveralls.io/repos/github/tawesoft/golib/badge.svg?branch=v2)](https://coveralls.io/github/tawesoft/golib?branch=v2)

A monorepo for small Go (v1.20+) modules maintained by
[Tawesoft®](https://www.tawesoft.co.uk).
[Tawesoft®](https://www.tawesoft.co.uk), with few dependencies.

```go
import "github.com/tawesoft/golib/v2/..."
Expand All @@ -27,17 +27,20 @@ support, are additionally covered by compatible [MIT-like licences](/LICENSE-PAR
| dialog | [v2][d01] | - | cross-platform message boxes & file pickers |
| digraph | - | [v2][d02] | *(unstable)* directed graphs (including DAGs) |
| drop | - | - | *(TODO)* drop process privileges and inherit handles |
| fun/maybe | [v2][f01] | - | "Maybe" sum type |
| fun/partial | [v2][f02] | - | partial function application |
| fun/result | [v2][f03] | - | "Result" sum type |
| fun/slices | [v2][f04] | - | higher-order functions for slices |
| fun/either | [v2][f01] | - | "Either" sum type |
| fun/future | [v2][f02] | - | synchronous and asynchronous future values |
| fun/maybe | [v2][f03] | - | "Maybe" sum type |
| fun/partial | [v2][f04] | - | partial function application |
| fun/promise | [v2][f05] | - | store computations to be performed later |
| fun/result | [v2][f06] | - | "Result" sum type |
| fun/slices | [v2][f07] | - | higher-order functions for slices |
| grace | - | - | *(TODO)* start and gracefully shutdown processes |
| humanize | - | - | *(TODO)* locale-aware numbers &amp; quantities |
| iter | [v2][i01] | - | composable lazy iteration |
| ks | - | [v2][k01] | *(unstable)* "kitchen sink" of extras |
| loader | - | - | *(TODO)* concurrent dependency graph solver |
| html/meta/opengraph | [v2][m01] | - | HTML meta tags for Facebook's Open Graph protocol |
| html/meta/twittercard | [v2][m02] | - | HTML meta tags for Twitter Cards |
| html/meta/opengraph | [v2][h01] | - | HTML meta tags for Facebook's Open Graph protocol |
| html/meta/twittercard | [v2][h02] | - | HTML meta tags for Twitter Cards |
| must | [v2][m03] | - | assertions |
| operator | [v2][o01] | - | operators as functions |
| tuple | [v2][p01] | - | convert to/from tuples |
Expand All @@ -61,9 +64,10 @@ expected for a Go package of v2 or higher. "Latest" packages, or
| text/fold | - | [v2][t04] | Unicode text folding |
| text/np | - | [v2][t05] | Unicode numeric properties |
| text/number/algorithmic | [v2][t07] | - | CLDR algorithmic (non-decimal) numbering systems |
| text/number/rbnf | - | [v2][t08] | CLDR Rule-Based Number Formats |
| text/number/symbols | - | [v2][t09] | CLDR locale-appropriate Number Symbols |
| text/runeio | - | [v2][t06] | *(unstable)* Unicode streams with lookahead &amp; rewind |
| text/number/plurals | [v2][t08] | - | CLDR plural rules with a simple interface |
| text/number/rbnf | - | [v2][t09] | CLDR Rule-Based Number Formats |
| text/number/symbols | - | [v2][t10] | CLDR locale-appropriate Number Symbols |


**Note:** "Stable" packages have the
[normal stability guarantees](https://go.dev/doc/modules/version-numbers)
Expand All @@ -74,14 +78,17 @@ expected for a Go package of v2 or higher. "Latest" packages, or
[c01]: https://pkg.go.dev/github.com/tawesoft/golib/v2/css/tokenizer
[d01]: https://pkg.go.dev/github.com/tawesoft/golib/v2/dialog
[d02]: https://pkg.go.dev/github.com/tawesoft/golib/v2/digraph
[f01]: https://pkg.go.dev/github.com/tawesoft/golib/v2/fun/maybe
[f02]: https://pkg.go.dev/github.com/tawesoft/golib/v2/fun/partial
[f03]: https://pkg.go.dev/github.com/tawesoft/golib/v2/fun/result
[f04]: https://pkg.go.dev/github.com/tawesoft/golib/v2/fun/slices
[f01]: https://pkg.go.dev/github.com/tawesoft/golib/v2/fun/either
[f02]: https://pkg.go.dev/github.com/tawesoft/golib/v2/fun/future
[f03]: https://pkg.go.dev/github.com/tawesoft/golib/v2/fun/maybe
[f04]: https://pkg.go.dev/github.com/tawesoft/golib/v2/fun/partial
[f05]: https://pkg.go.dev/github.com/tawesoft/golib/v2/fun/promise
[f06]: https://pkg.go.dev/github.com/tawesoft/golib/v2/fun/result
[f07]: https://pkg.go.dev/github.com/tawesoft/golib/v2/fun/slices
[i01]: https://pkg.go.dev/github.com/tawesoft/golib/v2/iter
[k01]: https://pkg.go.dev/github.com/tawesoft/golib/v2/ks
[m01]: https://pkg.go.dev/github.com/tawesoft/golib/v2/meta/opengraph
[m02]: https://pkg.go.dev/github.com/tawesoft/golib/v2/meta/twittercard
[h01]: https://pkg.go.dev/github.com/tawesoft/golib/v2/meta/opengraph
[h02]: https://pkg.go.dev/github.com/tawesoft/golib/v2/meta/twittercard
[m03]: https://pkg.go.dev/github.com/tawesoft/golib/v2/must
[o01]: https://pkg.go.dev/github.com/tawesoft/golib/v2/operator
[p01]: https://pkg.go.dev/github.com/tawesoft/golib/v2/tuple
Expand All @@ -92,8 +99,9 @@ expected for a Go package of v2 or higher. "Latest" packages, or
[t05]: https://pkg.go.dev/github.com/tawesoft/golib/v2/text/np
[t06]: https://pkg.go.dev/github.com/tawesoft/golib/v2/text/runeio
[t07]: https://pkg.go.dev/github.com/tawesoft/golib/v2/text/number/algorithmic
[t08]: https://pkg.go.dev/github.com/tawesoft/golib/v2/text/number/rbnf
[t09]: https://pkg.go.dev/github.com/tawesoft/golib/v2/text/number/symbols
[t08]: https://pkg.go.dev/github.com/tawesoft/golib/v2/text/number/plurals
[t09]: https://pkg.go.dev/github.com/tawesoft/golib/v2/text/number/rbnf
[t10]: https://pkg.go.dev/github.com/tawesoft/golib/v2/text/number/symbols
[v01]: https://pkg.go.dev/github.com/tawesoft/golib/v2/view


Expand Down
49 changes: 26 additions & 23 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
# Security Policy

Contact: [[email protected]](mailto:[email protected])
[![Report A Vulnerability]](https://github.com/tawesoft/golib/security/advisories/new)
[![View Security Advisories]](https://github.com/tawesoft/golib/security/advisories)

Contact: [[email protected]](mailto:[email protected])

## Announcements

It is our policy to publicly announce security issues and fixes through the
GitHub "Security Advisories" feature for this repository.

You can subscribe to security announcements for this repository by
[configuring your "watching" settings](https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository)
and subscribing to security alerts.
To subscribe, [configure your watch settings] and tick either "All Activity"
or select "custom" and tick "security alerts".

[configure your watch settings]: (https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository)

## Pre-announcements

On a case-by-case basis, we are prepared to pre-announce security issues and
fixes to any downstream consumer of this repository who can provide evidence
that any security issues would have a particularly high impact on their
services, such as operators of a service that processes personal data or is
used by a large volume of users. Email us with the subject
"join security-preannounce list" for details.
services. Email [[email protected]](mailto:[email protected])
to discuss this.


## Backporting fixes
Expand All @@ -33,24 +37,23 @@ if necessary.

Please disclose responsibly so that we can notify the users of our software
with a fix and/or instructions, including a pre-announcement where appropriate.
Do not report security issues through the public issue tracker in the first
instance, unless the vulnerability is being actively exploited in the wild or
is already public knowledge.

Instead, please email information about vulnerabilities to
[[email protected]](mailto:[email protected]).
**Please do not report security issues through the public issue tracker** in the
first instance, unless the vulnerability is being actively exploited in the
wild or is already public knowledge. Please use the option to securely
report a vulnerability through GitHub at the top of this page. Alternatively,
please email us at [[email protected]](mailto:[email protected])
and if necessary we can make other arrangements with you for secure disclosure.

To help prioritise your report, format the subject line as follows:

`vulnerability: repository-url - description`

For example:
If you don't receive an acknowledgement of your report within 48 hours,
and you believe that urgent action is required, then please contact us through
any contact method listed on the
[Tawesoft website](https://www.tawesoft.co.uk/).

`vulnerability: github.com/example/repo - denial of service in foo/bar`
If we have not fixed or disclosed a vulnerability within 90 days of being
notified, then we respect your right to disclose it publicly.

If you don't receive an acknowledgement within 48 hours, please contact us
through any contact method listed on the
[Tawesoft website](https://www.tawesoft.co.uk/).

If, after being notified, we have not fixed or disclosed a vulnerability after
90 days, then you may exercise your right to disclose it publicly.
<!--// button backgrounds //-->
[Report A Vulnerability]: https://img.shields.io/badge/Report_A_Vulnerability-1f883d?style=for-the-badge&logo=github
[View Security Advisories]: https://img.shields.io/badge/View_advisories-d86900?style=for-the-badge&logo=github
2 changes: 1 addition & 1 deletion TRADEMARKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Windows is a trade mark of
[Microsoft Corporation](https://www.microsoft.com/en-gb).


## Disclaimed
## Not trade marks

The name of this "golib" software is used as a generic descriptive term for a
[software library](https://en.wikipedia.org/wiki/Library_(computing))
Expand Down
71 changes: 71 additions & 0 deletions fun/either/either.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Package either implements a simple generic "Either" type that can represent
// exactly one value out of two options.
package either

import (
"fmt"
)

// E represents a type that can hold either a value "a" of type A or a
// value "b" of type B.
type E[A any, B any] struct {
a A
b B
index byte // 'a' or 'b'
}

// Pack returns an E that contains eotjer a value "a" of type A (if index ==
// 'a'), a value "b" of type B (if index == 'b'), or panics if index is not 'a'
// or 'b'.
func Pack[A any, B any](a A, b B, index byte) E[A, B] {
if index == 'a' {
return E[A, B]{a: a, index: index}
} else if index == 'b' {
return E[A, B]{b: b, index: index}
} else {
panic(fmt.Errorf("either: Pack[%T, %T](): invalid index value", a, b))
}
}

// Unpack returns the components of an E. The last return value is a
// discriminator with the value 'a' or 'b' representing the existence of the
// value "a" of type A or the value "b" of type B.
func (e E[A, B]) Unpack() (A, B, byte) {
return e.a, e.b, e.index
}

// A returns a new E that holds a value "a" of Type A.
func A[A any, B any](a A) E[A, B] {
return E[A, B]{
a: a,
index: 'a',
}
}

// B returns a new E that holds a value "b" of type B.
func B[A any, B any](b B) E[A, B] {
return E[A, B]{
b: b,
index: 'b',
}
}

// A returns the value "a" of type A and true if the E contains that value,
// or the zero value and false otherwise.
func (e E[A, B]) A() (result A, ok bool) {
if e.index == 'a' {
result = e.a
ok = true
}
return
}

// B returns the value "b" of type B and true if the E contains that value,
// or the zero value and false otherwise.
func (e E[A, B]) B() (result B, ok bool) {
if e.index == 'b' {
result = e.b
ok = true
}
return
}
85 changes: 85 additions & 0 deletions fun/future/async.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package future

import (
"context"

"github.com/tawesoft/golib/v2/fun/partial"
"github.com/tawesoft/golib/v2/fun/promise"
"github.com/tawesoft/golib/v2/fun/result"
"github.com/tawesoft/golib/v2/fun/slices"
)

type async[T any] struct {
context context.Context
cancel context.CancelFunc
channel chan result.R[T]
}

func start[T any](ctx context.Context, promise promise.P[T], channel chan result.R[T]) {
value := result.New(promise.ComputeCtx(ctx))
for {
select {
case <- ctx.Done(): return
default: channel <- value
}
}
close(channel)
}

// NewAsync creates a new future from a promise, and begins computing that
// promise asynchronously in a new goroutine.
func NewAsync[T any](ctx context.Context, promise promise.P[T]) F[T] {
ctxWithCancel, cancel := context.WithCancel(ctx)
f := async[T]{
context: ctxWithCancel,
cancel: cancel,
channel: make(chan result.R[T]),
}
go start(ctxWithCancel, promise, f.channel)
return f
}

// NewAsyncs is like [NewAsync], but accepts a slice of promises and returns a
// slice of futures.
func NewAsyncs[T any](ctx context.Context, xs []promise.P[T]) []F[T] {
return slices.Map(
partial.Left2(NewAsync[T])(ctx),
xs,
)
}

func (f async[T]) Collect() (result T, err error) {
return f.CollectCtx(context.TODO())
}

func (f async[T]) CollectCtx(ctx context.Context) (result T, err error) {
select {
case <- ctx.Done():
err = ctx.Err()
return
case <- f.context.Done():
err = f.context.Err()
return
case r := <- f.channel:
result, err = r.Unpack()
return
}
}

func (f async[T]) Stop() {
f.cancel()
}

func (f async[T]) Peek() (result T, err error) {
select {
case <- f.context.Done():
err = f.context.Err()
return
case r := <- f.channel:
result, err = r.Unpack()
return
default:
err = NotReady
return
}
}
Loading

0 comments on commit 1f48f70

Please sign in to comment.