Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
  • 7 commits
  • 7 files changed
  • 0 commit comments
  • 2 contributors
View
1  .gitignore
@@ -1 +1,2 @@
*.beam
+ebin/*.app
View
2  CONTRIBUTORS
@@ -0,0 +1,2 @@
+Per Andersson <avtobiff@gmail.com>
+Bip Thelin <bip@thelin.se>
View
2  Makefile
@@ -27,7 +27,7 @@ dialyzer:
test:
erlc -W +debug_info +compressed +strip -o test/ test/*.erl
- erl -noshell -pa ebin -pa test -eval "uuid_v4_tests:test()" -eval "init:stop()"
+ erl -noshell -pa ebin -pa test -eval "uuid_tests:test()" -eval "init:stop()"
install: build
# create dist directory and install files
View
22 README
@@ -1,8 +1,10 @@
ERLANG UUID
===========
-This module implements UUID v4, UUID generated by a (pseudo) random number
-generator.
+This module implements UUID v4 and v5 as of RFC 4122.
+
+UUID v4 return a UUID generated by a (pseudo) random number generator.
+UUID v5 return a UUID generated using SHA1 and a given name within a namespace.
Source tracking available at
@@ -28,6 +30,10 @@ Install to different $ERL_ROOT ($PREFIX/lib/erlang) by setting PREFIX
sudo make PREFIX=/opt/erlang install
+Include in your own project using Rebar. Add this to your rebar.config
+
+ {uuid, ".*",
+ {git, "git://gitorious.org/avtobiff/erlang-uuid.git", "master"}}
USE
@@ -36,7 +42,17 @@ Example of usage
1> uuid:to_string(uuid:uuid4()).
"79f492f8-1337-4200-abcd-92bada1cacao"
+ 2> uuid:to_string(uuid:uuid5(dns, "fqdn.example.com")).
+ "8fd7fa87-4c20-5809-a1b0-e07f5c224f02"
+ 3> uuid:to_string(uuid:uuid5(uuid:uuid4(), "my name")).
+ "6ff58b11-e0b2-536c-b6be-bdccd38836a2"
+
+UUID v5
+-------
+UUID v5 uses SHA1 to generate a UUID using a name and a namespace as
+initializer. Valid namespaces are the atoms: url, dns, oid, x500, nil or using
+a generated UUID either as a binary or as a UUID string representation.
- Per Andersson <avtobiff@gmail.com> Mon, 14 Feb 2011 11:51:30 +0100
+ Per Andersson <avtobiff@gmail.com> Sat, 18 Feb 2012 00:19:41 +0100
View
72 src/uuid.erl
@@ -19,13 +19,14 @@
%% @doc
%% Erlang UUID
%%
-%% Currently implements UUID v4, UUID generated with (pseudo) random number
-%% generator.
+%% Currently implements UUID v4 and v5 as of RFC 4122.
%%
%% Example usage
%% <pre>
%% 1> uuid:to_string(uuid:uuid4()).
%% "79f492f8-1337-4200-abcd-92bada1cacao"
+%% 2> uuid:to_string(uuid:uuid5(dns, "fqdn.example.com")).
+%% "8fd7fa87-4c20-5809-a1b0-e07f5c224f02"
%% </pre>
%% @end
%% -----------------------------------------------------------------------------
@@ -33,12 +34,12 @@
-module(uuid).
-author('Per Andersson').
--export([uuid4/0, to_string/1, to_binary/1]).
+-export([uuid4/0, uuid5/2, to_string/1, to_string/2, to_binary/1]).
%% @doc Create a UUID v4 (random) as a binary
-%% @spec () -> binary()
+-spec uuid4() -> binary().
uuid4() ->
{A1, A2, A3} = now(),
random:seed(A1, A2, A3),
@@ -50,24 +51,69 @@ uuid4() ->
uuid4(U0, U1, U2).
+%% @doc Create a UUID v5 (name based) as a binary.
+%% Magic numbers are from Appendix C of the RFC 4122.
+-spec uuid5(NamespaceOrUuid::atom() | string() | binary(),
+ Name::string()) -> binary().
+uuid5(dns, Name) ->
+ uuid5(list_to_binary([<<16#6ba7b8109dad11d180b400c04fd430c8:128>>, Name]));
+uuid5(url, Name) ->
+ uuid5(list_to_binary([<<16#6ba7b8119dad11d180b400c04fd430c8:128>>, Name]));
+uuid5(oid, Name) ->
+ uuid5(list_to_binary([<<16#6ba7b8129dad11d180b400c04fd430c8:128>>, Name]));
+uuid5(x500, Name) ->
+ uuid5(list_to_binary([<<16#6ba7b8149dad11d180b400c04fd430c8:128>>, Name]));
+uuid5(nil, Name) ->
+ uuid5(list_to_binary([<<0:128>>, Name]));
+uuid5(UuidStr, Name) when is_list(UuidStr) ->
+ uuid5(list_to_binary([to_binary(UuidStr), Name]));
+uuid5(UuidBin, Name) when is_binary(UuidBin) ->
+ uuid5(list_to_binary([UuidBin, Name]));
+uuid5(_, _) ->
+ erlang:error(badarg).
+
+
%% @private
+%% @doc Create a UUID v5 (name based) from binary
+-spec uuid5(Data::binary()) -> binary().
+uuid5(Data) ->
+ <<Sha1:128, _:32>> = crypto:sha(Data),
+
+ <<TimeLow:32, TimeMid:16, _AndVersion:4, TimeHi:12,
+ _AndReserved:2, ClockSeqHi:6, ClockSeqLow:8, Node:48>> = <<Sha1:128>>,
+
+ Version = 5,
+ Variant = 2#10,
+
+ <<TimeLow:32, TimeMid:16, Version:4, TimeHi:12,
+ Variant:2, ClockSeqHi:6, ClockSeqLow:8, Node:48>>.
+
+
%% @doc Create a 128 bit binary (UUID v4) from input
-%% @spec (U0, U1, U2) -> binary()
-%% where U0 = U1 = U2 = integer()
+-spec uuid4(U0::integer(), U1::integer(), U2::integer()) -> binary().
uuid4(U0, U1, U2) -> <<U0:48, 4:4, U1:12, 10:4, U2:60>>.
-%% @doc Format uuid string from binary
-%% @spec (Uuid::binary()) -> string()
-to_string(<<U0:32, U1:16, U2:16, U3:16, U4:48>>) ->
+%% @doc Format UUID string from binary
+-spec to_string(Uuid::binary()) -> string().
+to_string(Uuid) when is_binary(Uuid) ->
+ to_string(pretty, Uuid);
+to_string(_) ->
+ erlang:error(badarg).
+
+-spec to_string(simple | pretty, Uuid::binary()) -> string().
+to_string(pretty, <<U0:32, U1:16, U2:16, U3:16, U4:48>>) ->
lists:flatten(io_lib:format(
"~8.16.0b-~4.16.0b-~4.16.0b-~4.16.0b-~12.16.0b",
[U0, U1, U2, U3, U4]));
-to_string(_) ->
+to_string(simple, <<S:128>>) ->
+ lists:flatten(io_lib:format("~32.16.0b", [S]));
+to_string(_, _) ->
erlang:error(badarg).
+
%% @doc Format uuid binary from string
-%% @spec (UuidStr::string()) -> binary()
+-spec to_binary(UuidStr::string()) -> binary().
to_binary(UuidStr) when is_list(UuidStr) ->
Parts = string:tokens(UuidStr, "$-"),
[I0, I1, I2, I3, I4] = [hex_to_int(Part) || Part <- Parts],
@@ -75,6 +121,10 @@ to_binary(UuidStr) when is_list(UuidStr) ->
to_binary(_) ->
erlang:error(badarg).
+
+%% @private
+%% @doc Convert from hexadecimal digit represented as string to decimal.
+-spec hex_to_int(Hex::string()) -> integer().
hex_to_int(Hex) ->
{ok, [D], []} = io_lib:fread("~16u", Hex),
D.
View
99 test/uuid_tests.erl
@@ -0,0 +1,99 @@
+%% -----------------------------------------------------------------------------
+%% Copyright © 2010 Per Andersson
+%%
+%% Erlang UUID is free software: you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation, either version 3 of the License, or
+%% (at your option) any later version.
+%%
+%% Erlang UUID is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with erlang-uuid. If not, see <http://www.gnu.org/licenses/>.
+%% -----------------------------------------------------------------------------
+%% @author Per Andersson <avtobiff@gmail.com>
+%% @copyright 2010 Per Andersson
+%% @doc
+%% Erlang UUID
+%%
+%% HERE BE UUID TESTS
+%% @end
+%% -----------------------------------------------------------------------------
+
+-module(uuid_tests).
+-author('Per Andersson').
+
+-include_lib("eunit/include/eunit.hrl").
+
+
+uuid_binary_test() ->
+ Uuid = uuid:uuid4(),
+
+ ?assertMatch(<<_U0:48, 4:4, _U1:12, 10:4, _U2:60>>, uuid:uuid4()),
+
+ ?assertMatch(<<_U0:48, 5:4, _U1:12, _:2, _U2:62>>,
+ uuid:uuid5(dns, "fqdn.example.com")),
+ ?assertEqual(uuid:uuid5(dns, "fqdn.example.com"),
+ uuid:uuid5(dns, "fqdn.example.com")),
+
+ ?assertMatch(<<_U0:48, 5:4, _U1:12, _:2, _U2:62>>,
+ uuid:uuid5(oid, "2.5.6")),
+ ?assertEqual(uuid:uuid5(oid, "2.5.6"), uuid:uuid5(oid, "2.5.6")),
+
+ ?assertMatch(<<_U0:48, 5:4, _U1:12, _:2, _U2:62>>,
+ uuid:uuid5(url, "http://fqdn.example.com/path")),
+ ?assertEqual(uuid:uuid5(url, "http://fqdn.example.com/path"),
+ uuid:uuid5(url, "http://fqdn.example.com/path")),
+
+ ?assertMatch(<<_U0:48, 5:4, _U1:12, _:2, _U2:62>>,
+ uuid:uuid5(x500, "cn=John Doe, o=Acme, Inc., c=US")),
+ ?assertEqual(uuid:uuid5(x500, "cn=John Doe, o=Acme, Inc., c=US"),
+ uuid:uuid5(x500, "cn=John Doe, o=Acme, Inc., c=US")),
+
+ ?assertMatch(<<_U0:48, 5:4, _U1:12, _:2, _U2:62>>,
+ uuid:uuid5(nil, "my own unique name")),
+ ?assertEqual(uuid:uuid5(nil, "my own unique name"),
+ uuid:uuid5(nil, "my own unique name")),
+
+ ?assertMatch(<<_U0:48, 5:4, _U1:12, _:2, _U2:62>>,
+ uuid:uuid5(Uuid, "fqdn.example.com")),
+ ?assertEqual(uuid:uuid5(Uuid, "fqdn.example.com"),
+ uuid:uuid5(Uuid, "fqdn.example.com")),
+
+ ?assertMatch(<<_U0:48, 5:4, _U1:12, _:2, _U2:62>>,
+ uuid:uuid5(uuid:to_string(Uuid), "fqdn.example.com")),
+ ?assertEqual(uuid:uuid5(uuid:to_string(Uuid), "fqdn.example.com"),
+ uuid:uuid5(uuid:to_string(Uuid), "fqdn.example.com")).
+
+representation_test() ->
+ Uuid4 = uuid:uuid4(),
+ Uuid5 = uuid:uuid5(dns, "fqdn.example.com"),
+ ?assertMatch(Uuid4, uuid:to_binary(uuid:to_string(Uuid4))),
+ ?assertMatch(Uuid5, uuid:to_binary(uuid:to_string(Uuid5))).
+
+tostring_test() ->
+ SimpleUuid = "8fd7fa874c205809a1b0e07f5c224f02",
+ PrettyUuid = "8fd7fa87-4c20-5809-a1b0-e07f5c224f02",
+ ?assertMatch(PrettyUuid,
+ uuid:to_string(uuid:uuid5(dns, "fqdn.example.com"))),
+ ?assertMatch(PrettyUuid,
+ uuid:to_string(pretty, uuid:uuid5(dns, "fqdn.example.com"))),
+ ?assertMatch(SimpleUuid,
+ uuid:to_string(simple, uuid:uuid5(dns, "fqdn.example.com"))).
+
+exceptions_test() ->
+ ?assertMatch(ok, try_badarg(to_binary, [0])),
+ ?assertMatch(ok, try_badarg(to_string, [0])),
+ ?assertMatch(ok, try_badarg(to_string, [0, 0])),
+ ?assertMatch(ok, try_badarg(uuid5, [0, 0])).
+
+
+try_badarg(F, A) ->
+ try
+ apply(uuid, F, A)
+ catch error:badarg ->
+ ok
+ end.
View
49 test/uuid_v4_tests.erl
@@ -1,49 +0,0 @@
-%% -----------------------------------------------------------------------------
-%% Copyright © 2010 Per Andersson
-%%
-%% Erlang UUID is free software: you can redistribute it and/or modify
-%% it under the terms of the GNU General Public License as published by
-%% the Free Software Foundation, either version 3 of the License, or
-%% (at your option) any later version.
-%%
-%% Erlang UUID is distributed in the hope that it will be useful,
-%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-%% GNU General Public License for more details.
-%%
-%% You should have received a copy of the GNU General Public License
-%% along with erlang-uuid. If not, see <http://www.gnu.org/licenses/>.
-%% -----------------------------------------------------------------------------
-%% @author Per Andersson <avtobiff@gmail.com>
-%% @copyright 2010 Per Andersson
-%% @doc
-%% Erlang UUID
-%%
-%% HERE BE UUIDv4 TESTS
-%% @end
-%% -----------------------------------------------------------------------------
-
--module(uuid_v4_tests).
--author('Per Andersson').
-
--include_lib("eunit/include/eunit.hrl").
-
-
-uuid_v4_binary_test() ->
- ?assertMatch(<<_U0:48, 4:4, _U1:12, 10:4, _U2:60>>, uuid:uuid4()).
-
-representation_test() ->
- Uuid = uuid:uuid4(),
- ?assertMatch(Uuid, uuid:to_binary(uuid:to_string(Uuid))).
-
-exceptions_test() ->
- ?assertMatch(ok, try_badarg(to_binary, 0)),
- ?assertMatch(ok, try_badarg(to_string, 0)).
-
-
-try_badarg(F, A) ->
- try
- uuid:F(A)
- catch error:badarg ->
- ok
- end.

No commit comments for this range

Something went wrong with that request. Please try again.