diff --git a/05-typestate-go-structs/go.mod b/05-typestate-go-structs/go.mod new file mode 100644 index 0000000..6f20c44 --- /dev/null +++ b/05-typestate-go-structs/go.mod @@ -0,0 +1,3 @@ +module typestate-structs + +go 1.26.5 diff --git a/05-typestate-go-structs/main.go b/05-typestate-go-structs/main.go new file mode 100644 index 0000000..6957835 --- /dev/null +++ b/05-typestate-go-structs/main.go @@ -0,0 +1,45 @@ +package main + +type LockedCredentialManager struct { + entries map[string]string +} + +type UnlockedCredentialManager struct { + entries map[string]string +} + +func NewCredentialManager() LockedCredentialManager { + return LockedCredentialManager{ + entries: make(map[string]string), + } +} + +func (m LockedCredentialManager) Unlock(masterSecret string) UnlockedCredentialManager { + return UnlockedCredentialManager{ + entries: m.entries, + } +} + +func (m UnlockedCredentialManager) Set(key string, secret string) { + panic("todo") +} + +func (m UnlockedCredentialManager) Get(key string) (string, bool) { + panic("todo") +} + +func (m UnlockedCredentialManager) Lock() LockedCredentialManager { + return LockedCredentialManager{ + entries: m.entries, + } +} + +func main() { + pw := NewCredentialManager() + + unlocked := pw.Unlock("pssst") + unlocked.Set("foo", "bar") + _, _ = unlocked.Get("foo") + + unlocked.Lock() +} diff --git a/06-typestate-go-interfaces/go.mod b/06-typestate-go-interfaces/go.mod new file mode 100644 index 0000000..803b7c7 --- /dev/null +++ b/06-typestate-go-interfaces/go.mod @@ -0,0 +1,3 @@ +module typestate-interfaces + +go 1.26.5 diff --git a/06-typestate-go-interfaces/main.go b/06-typestate-go-interfaces/main.go new file mode 100644 index 0000000..13b5719 --- /dev/null +++ b/06-typestate-go-interfaces/main.go @@ -0,0 +1,54 @@ +package main + +import "errors" + +type LockedCredentialManager interface { + Unlock(masterKey string) (UnlockedCredentialManager, error) +} + +type UnlockedCredentialManager interface { + Lock() (LockedCredentialManager, error) + Set(key string, secret string) error + Get(key string) (string, error) +} + +type credentialManager struct { + unlocked bool + entries map[string]string +} + +func NewCredentialManager() LockedCredentialManager { + return &credentialManager{ + entries: make(map[string]string), + } +} + +func (t *credentialManager) Unlock(masterKey string) (UnlockedCredentialManager, error) { + if t.unlocked { + return nil, errors.New("already unlocked") + } + t.unlocked = true + return t, nil +} + +func (t *credentialManager) Lock() (LockedCredentialManager, error) { + if !t.unlocked { + return nil, errors.New("already locked") + } + t.unlocked = false + return t, nil +} + +func (t *credentialManager) Set(key string, secret string) error { + if !t.unlocked { + return errors.New("locked") + } + panic("todo") +} + +func (t *credentialManager) Get(key string) (string, error) { + if !t.unlocked { + return "", errors.New("locked") + } + panic("todo") +} diff --git a/05-type-mapping/main.ts b/07-type-mapping/main.ts similarity index 100% rename from 05-type-mapping/main.ts rename to 07-type-mapping/main.ts diff --git a/README.md b/README.md new file mode 100644 index 0000000..91f310e --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Type Level Programming + +## Sources + +- https://www.emoses.org/posts/resolver-resolved-pattern/ +- https://farazdagi.com/posts/2024-04-07-typestate-pattern/ +- https://youtu.be/_ccDqRTx-JU diff --git a/go.work b/go.work new file mode 100644 index 0000000..9ac69b5 --- /dev/null +++ b/go.work @@ -0,0 +1,6 @@ +go 1.26.5 + +use ( + ./05-typestate-go-structs + ./06-typestate-go-interfaces +)