Skip to content

Feat/base64 base64url #924

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions docs/predicate/base64_2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
sidebar_position: 9
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

# base64/2

## Description

`base64/2` is a predicate that unifies a string to a `base64/2` encoded string.

The output is returned as an atom with padding included.

The signature is as follows:

```text
base64(+Plain, -Encoded) is det
base64(-Plain, +Encoded) is det
```

Where:

- Plain is an atom, a list of characters, or character codes representing the unencoded text.
- Encoded is an atom, a list of characters, or character codes representing the `base64/2` encoded form.

The predicate is equivalent to base64\_encoded/3 with options: \[as\(atom\), encoding\(utf8\), charset\(classic\), padding\(true\)\].

## Examples

### Encode and decode a string into a Base64 encoded atom

This scenario demonstrates how to encode an decode a plain string into a Base64-encoded atom using the `base64/2`
predicate.

Here are the steps of the scenario:

- **Given** the query:

``` prolog
base64('Hello world', Encoded),
base64(Decoded, 'SGVsbG8gd29ybGQ=').
```

- **When** the query is run
- **Then** the answer we get is:

``` yaml
height: 42
gas_used: 3976
answer:
has_more: false
variables: ["Encoded", "Decoded"]
results:
- substitutions:
- variable: Encoded
expression: "'SGVsbG8gd29ybGQ='"
- variable: Decoded
expression: "'Hello world'"
```
6 changes: 3 additions & 3 deletions docs/predicate/base64_encoded_3.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
---
sidebar_position: 9
sidebar_position: 10
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

# base64_encoded/3

## Description

`base64_encoded/3` is a predicate that unifies a string to a base64 encoded string as specified by [RFC 4648](<https://rfc-editor.org/rfc/rfc4648.html>).
`base64_encoded/3` is a predicate that unifies a string to a Base64 encoded string as specified by [RFC 4648](<https://rfc-editor.org/rfc/rfc4648.html>).

The signature is as follows:

Expand All @@ -20,7 +20,7 @@ base64_encoded(+Plain, +Encoded, +Options) is det
Where:

- Plain is an atom, a list of character codes, or list of characters containing the unencoded \(plain\) text.
- Encoded is an atom or string containing the base64 encoded text.
- Encoded is an atom or string containing the Base64 encoded text.
- Options is a list of options that can be used to control the encoding process.

## Options
Expand Down
26 changes: 26 additions & 0 deletions docs/predicate/base64_url_2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
sidebar_position: 11
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

# base64_url/2

## Description

`base64_url/2` is a predicate that unifies a string to a Base64 URL\-safe encoded string.

Encoded values are safe for use in URLs and filenames: "\+" is replaced by "\-", "/" by "\_", and padding is omitted.

The signature is as follows:

```text
base64url(+Plain, -Encoded) is det
base64url(-Plain, +Encoded) is det
```

Where:

- Plain is an atom, a list of characters, or character codes representing the unencoded text.
- Encoded is an atom, a list of characters, or character codes representing the Base64 URL\-safe encoded form.

The predicate is equivalent to base64\_encoded/3 with options: \[as\(atom\), encoding\(utf8\), charset\(url\), padding\(false\)\].
2 changes: 1 addition & 1 deletion docs/predicate/bech32_address_2.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 10
sidebar_position: 12
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/block_header_1.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 11
sidebar_position: 13
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/block_height_1.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 12
sidebar_position: 14
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/block_time_1.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 13
sidebar_position: 15
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/chain_id_1.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 14
sidebar_position: 16
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/consult_1.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 15
sidebar_position: 17
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/crypto_data_hash_3.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 16
sidebar_position: 18
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/current_output_1.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 17
sidebar_position: 19
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/did_components_2.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 18
sidebar_position: 20
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/ecdsa_verify_4.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 19
sidebar_position: 21
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/eddsa_verify_4.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 20
sidebar_position: 22
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/hex_bytes_2.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 21
sidebar_position: 23
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/json_prolog_2.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 22
sidebar_position: 24
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/json_read_2.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 23
sidebar_position: 25
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/json_write_2.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 24
sidebar_position: 26
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/open_3.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 26
sidebar_position: 28
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/open_4.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 25
sidebar_position: 27
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/read_string_3.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 27
sidebar_position: 29
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/read_term_3.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 28
sidebar_position: 30
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/retract_1.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 29
sidebar_position: 31
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/source_file_1.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 30
sidebar_position: 32
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/string_bytes_3.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 31
sidebar_position: 33
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/term_to_atom_2.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 32
sidebar_position: 34
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/uri_encoded_3.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 33
sidebar_position: 35
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 1 addition & 1 deletion docs/predicate/write_term_3.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 34
sidebar_position: 36
---
[//]: # (This file is auto-generated. Please do not modify it yourself.)

Expand Down
2 changes: 2 additions & 0 deletions x/logic/interpreter/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ var registry = orderedmap.New[string, any](
{Key: "json_read/2", Value: predicate.JSONRead},
{Key: "json_write/2", Value: predicate.JSONWrite},
{Key: "base64_encoded/3", Value: predicate.Base64Encoded},
{Key: "base64url/2", Value: predicate.Base64URL},
{Key: "base64/2", Value: predicate.Base64},
}...),
)

Expand Down
50 changes: 48 additions & 2 deletions x/logic/predicate/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var (
atomAtom = engine.NewAtom("atom")
)

// Base64Encoded is a predicate that unifies a string to a base64 encoded string as specified by [RFC 4648].
// Base64Encoded is a predicate that unifies a string to a Base64 encoded string as specified by [RFC 4648].
//
// The signature is as follows:
//
Expand All @@ -26,7 +26,7 @@ var (
//
// Where:
// - Plain is an atom, a list of character codes, or list of characters containing the unencoded (plain) text.
// - Encoded is an atom or string containing the base64 encoded text.
// - Encoded is an atom or string containing the Base64 encoded text.
// - Options is a list of options that can be used to control the encoding process.
//
// # Options
Expand Down Expand Up @@ -146,6 +146,52 @@ func getBase64Encoding(options engine.Term, env *engine.Env) (*base64.Encoding,
return encoding, nil
}

// Base64URL is a predicate that unifies a string to a Base64 URL-safe encoded string.
//
// Encoded values are safe for use in URLs and filenames: "+" is replaced by "-", "/" by "_", and padding is omitted.
//
// The signature is as follows:
//
// base64url(+Plain, -Encoded) is det
// base64url(-Plain, +Encoded) is det
//
// Where:
// - Plain is an atom, a list of characters, or character codes representing the unencoded text.
// - Encoded is an atom, a list of characters, or character codes representing the Base64 URL-safe encoded form.
//
// The predicate is equivalent to base64_encoded/3 with options: [as(atom), encoding(utf8), charset(url), padding(false)].
func Base64URL(vm *engine.VM, plain, encoded engine.Term, cont engine.Cont, env *engine.Env) *engine.Promise {
return Base64Encoded(vm, plain, encoded, engine.List(
prolog.AtomAs.Apply(atomAtom),
prolog.AtomEncoding.Apply(prolog.AtomUtf8),
prolog.AtomCharset.Apply(atomURL),
prolog.AtomPadding.Apply(prolog.AtomFalse),
), cont, env)
}

// Base64 is a predicate that unifies a string to a Base64 encoded string.
//
// The output is returned as an atom with padding included.
//
// The signature is as follows:
//
// base64(+Plain, -Encoded) is det
// base64(-Plain, +Encoded) is det
//
// Where:
// - Plain is an atom, a list of characters, or character codes representing the unencoded text.
// - Encoded is an atom, a list of characters, or character codes representing the Base64 encoded form.
//
// The predicate is equivalent to base64_encoded/3 with options: [as(atom), encoding(utf8), charset(classic), padding(true)].
func Base64(vm *engine.VM, plain, encoded engine.Term, cont engine.Cont, env *engine.Env) *engine.Promise {
return Base64Encoded(vm, plain, encoded, engine.List(
prolog.AtomAs.Apply(atomAtom),
prolog.AtomEncoding.Apply(prolog.AtomUtf8),
prolog.AtomCharset.Apply(atomClassic),
prolog.AtomPadding.Apply(prolog.AtomTrue),
), cont, env)
}

// HexBytes is a predicate that unifies hexadecimal encoded bytes to a list of bytes.
//
// The signature is as follows:
Expand Down
28 changes: 28 additions & 0 deletions x/logic/predicate/features/base64_2.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Feature: base64/2
This feature is to test the base64/2 predicate.

@great_for_documentation
Scenario: Encode and decode a string into a Base64 encoded atom
This scenario demonstrates how to encode an decode a plain string into a Base64-encoded atom using the `base64/2`
predicate.

Given the query:
""" prolog
base64('Hello world', Encoded),
base64(Decoded, 'SGVsbG8gd29ybGQ=').
"""
When the query is run
Then the answer we get is:
""" yaml
height: 42
gas_used: 3976
answer:
has_more: false
variables: ["Encoded", "Decoded"]
results:
- substitutions:
- variable: Encoded
expression: "'SGVsbG8gd29ybGQ='"
- variable: Decoded
expression: "'Hello world'"
"""
Loading
Loading